UNPKG

@shopify/flash-list

Version:

FlashList is a more performant FlatList replacement

180 lines (161 loc) 6.36 kB
import { ScrollView } from "react-native"; import { ProgressiveListView } from "recyclerlistview"; import FlashList from "../FlashList"; import { mountFlashList } from "./helpers/mountFlashList"; describe("GridLayoutProviderWithProps", () => { it("updates average window on layout manager change", () => { const flashList = mountFlashList(); const oldAverageWindow = (flashList.instance as FlashList<any>).state .layoutProvider["averageWindow"]; // width change from default 400 to 600 will force layout manager to change flashList.find(ScrollView)?.trigger("onLayout", { nativeEvent: { layout: { height: 900, width: 600 } }, }); const newAverageWindow = flashList.instance.state.layoutProvider["averageWindow"]; expect(newAverageWindow).not.toBe(oldAverageWindow); flashList.unmount(); }); it("average window's size is two times the number of items that will fill the screen", () => { const flashList = mountFlashList({ numColumns: 2 }); expect( flashList.instance.state.layoutProvider["averageWindow"]["inputValues"] .length ).toBe(20); flashList.find(ScrollView)?.trigger("onLayout", { nativeEvent: { layout: { height: 2000, width: 600 } }, }); expect( flashList.instance.state.layoutProvider["averageWindow"]["inputValues"] .length ).toBe(40); flashList.setProps({ numColumns: 1 }); expect( flashList.instance.state.layoutProvider["averageWindow"]["inputValues"] .length ).toBe(20); flashList.unmount(); }); it("average window should not be less than 6 in size", () => { const flashList = mountFlashList(); flashList.find(ScrollView)?.trigger("onLayout", { nativeEvent: { layout: { height: 100, width: 100 } }, }); expect( flashList.instance.state.layoutProvider["averageWindow"]["inputValues"] .length ).toBe(6); flashList.unmount(); }); it("vertical list: average should not update when widths change", () => { const flashList = mountFlashList(); const layoutProvider = flashList.instance.state.layoutProvider; const oldAverage = layoutProvider.averageItemSize; layoutProvider.getLayoutManager()!.getLayouts()[0].width = 500; flashList.find(ProgressiveListView)?.instance.onItemLayout(0); expect(oldAverage).toBe(layoutProvider.averageItemSize); flashList.unmount(); }); it("horizontal list: average should not update when heights change", () => { const flashList = mountFlashList({ horizontal: true }); const layoutProvider = flashList.instance.state.layoutProvider; const oldAverage = layoutProvider.averageItemSize; layoutProvider.getLayoutManager()!.getLayouts()[0].height = 600; // Can throw a no op set state warning. Should be handled in PLV. flashList.find(ProgressiveListView)?.instance.onItemLayout(0); expect(oldAverage).toBe(layoutProvider.averageItemSize); flashList.unmount(); }); it("computes correct average", () => { const flashList = mountFlashList(); const layoutProvider = flashList.instance.state.layoutProvider; expect(layoutProvider.averageItemSize).toBe(200); const layouts = layoutProvider.getLayoutManager()!.getLayouts(); const progressiveListView = flashList.find(ProgressiveListView); layouts[0].height = 100; layouts[1].height = 200; layouts[2].height = 300; layouts[3].height = 400; progressiveListView?.instance.onItemLayout(0); progressiveListView?.instance.onItemLayout(1); progressiveListView?.instance.onItemLayout(2); progressiveListView?.instance.onItemLayout(3); // estimatedItemSize is treated as one of the values. That's why 240. expect(layoutProvider.averageItemSize).toBe(240); flashList.unmount(); }); it("updates all cached widths for vertical list and heights for horizontal list when orientation changes", () => { const runCacheUpdateTest = (horizontal: boolean) => { const flashList = mountFlashList({ data: new Array(20).fill("1"), horizontal, }); const progressiveListView = flashList.find(ProgressiveListView); const layoutProvider = flashList.instance.state.layoutProvider; layoutProvider .getLayoutManager()! .getLayouts() .forEach((layout, index) => { // marking layouts as if they're actual rendered sizes progressiveListView?.instance.onItemLayout(index); // checking size if (horizontal) { expect(layout.height).toBe(900); } else { expect(layout.width).toBe(400); } }); // simulates orientation change flashList.find(ScrollView)?.trigger("onLayout", { nativeEvent: { layout: { height: 400, width: 900 } }, }); layoutProvider .getLayoutManager()! .getLayouts() .forEach((layout) => { // making sure all widths or heights are updated if (horizontal) { expect(layout.height).toBe(400); } else { expect(layout.width).toBe(900); } // making sure extra keys don't make their way to layout unnecessarily expect(Object.keys(layout).length).toBe(6); }); flashList.unmount(); }; // vertical list runCacheUpdateTest(false); // horizontal list runCacheUpdateTest(true); }); it("expires if column count or padding changes", () => { const flashList = mountFlashList(); const baseProps = flashList.instance.props; expect( flashList.instance.state.layoutProvider.updateProps({ ...baseProps, contentContainerStyle: { paddingTop: 10 }, }).hasExpired ).toBe(false); expect( flashList.instance.state.layoutProvider.updateProps({ ...baseProps, contentContainerStyle: { paddingBottom: 10 }, }).hasExpired ).toBe(false); expect( flashList.instance.state.layoutProvider.updateProps({ ...baseProps, contentContainerStyle: { paddingLeft: 10 }, }).hasExpired ).toBe(true); flashList.instance.state.layoutProvider["_hasExpired"] = false; expect( flashList.instance.state.layoutProvider.updateProps({ ...baseProps, numColumns: 2, }).hasExpired ).toBe(true); }); });