Skip to content

Commit

Permalink
Add tests describing current sticky header realization behavior (#31075)
Browse files Browse the repository at this point in the history
Summary:
See react-native-community/discussions-and-proposals#335 for extra context.

A VirtualizedList may have sticky headers, forwarded on to ScrollView. These sticky headers are exempt from virtualization once realized for the first time. This change documents the behavior of keeping sticky header cells realized after scrolling away.

This scenario performs the same behavior as creating an internal "realization window" for sticky headers with a single cell window size. Generalizing the concept of realization windows should be shaped to support the existing sticky header scenario.

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->

[Internal] [Added] - Add tests describing current sticky header realization behavior

Pull Request resolved: #31075

Reviewed By: lunaleaps

Differential Revision: D26767582

Pulled By: appden

fbshipit-source-id: 0d151bd6046fcb5384c646205aafa1ca7edf6c77
  • Loading branch information
NickGerleman authored and facebook-github-bot committed Mar 11, 2021
1 parent 035718b commit 4fb9e2f
Show file tree
Hide file tree
Showing 2 changed files with 779 additions and 0 deletions.
159 changes: 159 additions & 0 deletions Libraries/Lists/__tests__/VirtualizedList-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -504,4 +504,163 @@ describe('VirtualizedList', () => {
'scrollToIndex out of range: requested index 3 is out of 0 to 2',
);
});

it('forwards correct stickyHeaderIndices when all in initial render window', () => {
const items = Array(10)
.fill()
.map((_, i) => (i % 3 === 0 ? {key: i, sticky: true} : {key: i}));
const stickyIndices = items
.filter(item => item.sticky)
.map(item => item.key);

const ITEM_HEIGHT = 10;

const component = ReactTestRenderer.create(
<VirtualizedList
data={items}
stickyHeaderIndices={stickyIndices}
initialNumToRender={10}
renderItem={({item}) => <item value={item.key} sticky={item.sticky} />}
getItem={(data, index) => data[index]}
getItemCount={data => data.length}
getItemLayout={(_, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
})}
/>,
);

expect(component).toMatchSnapshot();
});

it('forwards correct stickyHeaderIndices when partially in initial render window', () => {
const items = Array(10)
.fill()
.map((_, i) => (i % 3 === 0 ? {key: i, sticky: true} : {key: i}));
const stickyIndices = items
.filter(item => item.sticky)
.map(item => item.key);

const ITEM_HEIGHT = 10;

const component = ReactTestRenderer.create(
<VirtualizedList
data={items}
stickyHeaderIndices={stickyIndices}
initialNumToRender={5}
renderItem={({item}) => <item value={item.key} sticky={item.sticky} />}
getItem={(data, index) => data[index]}
getItemCount={data => data.length}
getItemLayout={(_, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
})}
/>,
);

expect(component).toMatchSnapshot();
});

it('realizes sticky headers in viewport on batched render', () => {
const items = Array(10)
.fill()
.map((_, i) => (i % 3 === 0 ? {key: i, sticky: true} : {key: i}));
const stickyIndices = items
.filter(item => item.sticky)
.map(item => item.key);

const ITEM_HEIGHT = 10;

const virtualizedListProps = {
data: items,
stickyHeaderIndices: stickyIndices,
initialNumToRender: 1,
windowSize: 1,
renderItem: ({item}) => <item value={item.key} sticky={item.sticky} />,
getItem: (data, index) => data[index],
getItemCount: data => data.length,
getItemLayout: (_, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
}),
};

let component;

ReactTestRenderer.act(() => {
component = ReactTestRenderer.create(
<VirtualizedList key={'A'} {...virtualizedListProps} />,
);
});

ReactTestRenderer.act(() => {
component
.getInstance()
._onLayout({nativeEvent: {layout: {width: 10, height: 50}}});
component.getInstance()._onContentSizeChange(10, 100);
jest.runAllTimers();
});

expect(component).toMatchSnapshot();
});

it('keeps sticky headers realized after scrolled out of viewport', () => {
const items = Array(20)
.fill()
.map((_, i) =>
i % 3 === 0 ? {key: i, sticky: true} : {key: i, sticky: false},
);
const stickyIndices = items
.filter(item => item.sticky)
.map(item => item.key);

const ITEM_HEIGHT = 10;

const virtualizedListProps = {
data: items,
stickyHeaderIndices: stickyIndices,
initialNumToRender: 1,
windowSize: 1,
renderItem: ({item}) => <item value={item.key} sticky={item.sticky} />,
getItem: (data, index) => data[index],
getItemCount: data => data.length,
getItemLayout: (_, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
}),
};

let component;

ReactTestRenderer.act(() => {
component = ReactTestRenderer.create(
<VirtualizedList key={'A'} {...virtualizedListProps} />,
);
});

ReactTestRenderer.act(() => {
component
.getInstance()
._onLayout({nativeEvent: {layout: {width: 10, height: 50}}});
component.getInstance()._onContentSizeChange(10, 200);
jest.runAllTimers();
});

ReactTestRenderer.act(() => {
component.getInstance()._onScroll({
nativeEvent: {
contentOffset: {x: 0, y: 150},
contentSize: {width: 10, height: 200},
layoutMeasurement: {width: 10, height: 50},
},
});
jest.runAllTimers();
});

expect(component).toMatchSnapshot();
});
});
Loading

0 comments on commit 4fb9e2f

Please sign in to comment.