Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: facebook/react-native
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 8dfc2623eafcf8e4f03f655e6cd7572f3f04e451
Choose a base ref
..
head repository: facebook/react-native
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 43744979347085afdc60f78ecaff31426e4c2192
Choose a head ref
Showing with 111 additions and 54 deletions.
  1. +111 −54 Libraries/Lists/__tests__/VirtualizedList-test.js
165 changes: 111 additions & 54 deletions Libraries/Lists/__tests__/VirtualizedList-test.js
Original file line number Diff line number Diff line change
@@ -274,91 +274,148 @@ describe('VirtualizedList', () => {
);
});

it('should be called onEndReached correctly', () => {
function appendNewItems(items, count) {
const nextId = (items.length > 0 ? items[items.length - 1].id : 0) + 1;

for (let loop = 1; loop <= count; loop++) {
const id = nextId + loop;
items.push({
id: id,
key: `k${id}`,
});
}

return items;
}

let scrollTimeStamp = 0;
function scrollList(instance, items, y) {
scrollTimeStamp += 1000;

const nativeEvent = {
contentOffset: {y, x: 0},
layoutMeasurement: {width: 300, height: 600},
contentSize: {width: 300, height: items.length * ITEM_HEIGHT},
zoomScale: 1,
contentInset: {right: 0, top: 0, left: 0, bottom: 0},
};

instance._onScroll({
timeStamp: scrollTimeStamp,
nativeEvent,
});
}

it('OnEndReached should not be called after initial rendering', () => {
const ITEM_HEIGHT = 100;
const APPENDED_ITEM_COUNT = 10;
const data = appendNewItems([], 10);
const onEndReached = jest.fn(function() {
appendNewItems(data, APPENDED_ITEM_COUNT);
});

const props = {
data,
renderItem: ({item}) => <item value={item.key} />,
getItem: (items, index) => items[index],
getItemCount: items => items.length,
getItemLayout: (items, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
}),
onEndReached,
};
const props = createPropsWithonEndReached(data, ITEM_HEIGHT, onEndReached);

const component = ReactTestRenderer.create(<VirtualizedList {...props} />);
const instance = component.getInstance();

// It should not be called after the initial rendering
const scroll = createScrollMethod(instance, ITEM_HEIGHT);
scroll(data, 0);

expect(onEndReached).not.toHaveBeenCalled();
expect(data.length).toBe(10);
});

it('OnEndReached should be called once after scrolling by 200', () => {
const ITEM_HEIGHT = 100;
const APPENDED_ITEM_COUNT = 10;
const data = appendNewItems([], 10);
const onEndReached = jest.fn(function() {
appendNewItems(data, APPENDED_ITEM_COUNT);
});

const props = createPropsWithonEndReached(data, ITEM_HEIGHT, onEndReached);

const component = ReactTestRenderer.create(<VirtualizedList {...props} />);
const instance = component.getInstance();

// It should be called once after scrolling by 200
scrollList(instance, data, 200);
const scroll = createScrollMethod(instance, ITEM_HEIGHT);
scroll(data, 200);

expect(onEndReached).toHaveBeenCalledTimes(1);
expect(onEndReached).toHaveBeenLastCalledWith({
distanceFromEnd: 200,
});
expect(data.length).toBe(20);
});

it('OnEndReached should not be called twice in a short period while scrolling fast', () => {
const ITEM_HEIGHT = 100;
const APPENDED_ITEM_COUNT = 10;
const data = appendNewItems([], 10);
const onEndReached = jest.fn(function() {
appendNewItems(data, APPENDED_ITEM_COUNT);
});

// It should not be called after scrolling to the top
scrollList(instance, data, 0);
const props = createPropsWithonEndReached(data, ITEM_HEIGHT, onEndReached);

const component = ReactTestRenderer.create(<VirtualizedList {...props} />);
const instance = component.getInstance();

const scroll = createScrollMethod(instance, ITEM_HEIGHT);
scroll(data, 200);
scroll(data, 300, 50);

expect(onEndReached).toHaveBeenCalledTimes(1);
expect(onEndReached).toHaveBeenLastCalledWith({
distanceFromEnd: 200,
});
expect(data.length).toBe(20);
});

it('OnEndReached should be called when required to load more items', () => {
const ITEM_HEIGHT = 100;
const APPENDED_ITEM_COUNT = 10;
const data = appendNewItems([], 10);
const onEndReached = jest.fn(function() {
appendNewItems(data, APPENDED_ITEM_COUNT);
});

const props = createPropsWithonEndReached(data, ITEM_HEIGHT, onEndReached);

// It should not be called after scrolling back on the screen
scrollList(instance, data, 500);
const component = ReactTestRenderer.create(<VirtualizedList {...props} />);
const instance = component.getInstance();

const scroll = createScrollMethod(instance, ITEM_HEIGHT);
scroll(data, 200);
expect(onEndReached).toHaveBeenCalledTimes(1);
expect(data.length).toBe(20);

// It should be called when required to load more items.
scrollList(instance, data, 1000);
scroll(data, 1000);
expect(onEndReached).toHaveBeenCalledTimes(2);
expect(onEndReached).toHaveBeenLastCalledWith({
distanceFromEnd: 400,
});
expect(data.length).toBe(30);
});
});

function createPropsWithonEndReached(data, itemHeight, onEndReached) {
const props = {
data,
renderItem: ({item}) => <item value={item.key} />,
getItem: (items, index) => items[index],
getItemCount: items => items.length,
getItemLayout: (items, index) => ({
length: itemHeight,
offset: itemHeight * index,
index,
}),
onEndReached,
};

return props;
}

function appendNewItems(items, count) {
const nextId = (items.length > 0 ? items[items.length - 1].id : 0) + 1;

for (let loop = 1; loop <= count; loop++) {
const id = nextId + loop;
items.push({
id: id,
key: `k${id}`,
});
}

return items;
}

function createScrollMethod(instance, itemHeight) {
let scrollTimeStamp = 0;

return function scroll(items, y, delay = 1000) {
scrollTimeStamp += delay;

const nativeEvent = {
contentOffset: {y, x: 0},
layoutMeasurement: {width: 300, height: 600},
contentSize: {width: 300, height: items.length * itemHeight},
zoomScale: 1,
contentInset: {right: 0, top: 0, left: 0, bottom: 0},
};

instance._onScroll({
timeStamp: scrollTimeStamp,
nativeEvent,
});
};
}