@react-native-ohos/flash-list 1.6.4-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +7 -0
- package/README.OpenSource +11 -0
- package/README.md +9 -0
- package/dist/AnimatedFlashList.d.ts +6 -0
- package/dist/AnimatedFlashList.d.ts.map +1 -0
- package/dist/AnimatedFlashList.js +8 -0
- package/dist/AnimatedFlashList.js.map +1 -0
- package/dist/FlashList.d.ts +126 -0
- package/dist/FlashList.d.ts.map +1 -0
- package/dist/FlashList.js +524 -0
- package/dist/FlashList.js.map +1 -0
- package/dist/FlashListProps.d.ts +256 -0
- package/dist/FlashListProps.d.ts.map +1 -0
- package/dist/FlashListProps.js +9 -0
- package/dist/FlashListProps.js.map +1 -0
- package/dist/GridLayoutProviderWithProps.d.ts +42 -0
- package/dist/GridLayoutProviderWithProps.d.ts.map +1 -0
- package/dist/GridLayoutProviderWithProps.js +115 -0
- package/dist/GridLayoutProviderWithProps.js.map +1 -0
- package/dist/MasonryFlashList.d.ts +51 -0
- package/dist/MasonryFlashList.d.ts.map +1 -0
- package/dist/MasonryFlashList.js +252 -0
- package/dist/MasonryFlashList.js.map +1 -0
- package/dist/PureComponentWrapper.d.ts +22 -0
- package/dist/PureComponentWrapper.d.ts.map +1 -0
- package/dist/PureComponentWrapper.js +37 -0
- package/dist/PureComponentWrapper.js.map +1 -0
- package/dist/__tests__/AverageWindow.test.d.ts +2 -0
- package/dist/__tests__/AverageWindow.test.d.ts.map +1 -0
- package/dist/__tests__/AverageWindow.test.js +69 -0
- package/dist/__tests__/AverageWindow.test.js.map +1 -0
- package/dist/__tests__/ContentContainerUtils.test.d.ts +2 -0
- package/dist/__tests__/ContentContainerUtils.test.d.ts.map +1 -0
- package/dist/__tests__/ContentContainerUtils.test.js +85 -0
- package/dist/__tests__/ContentContainerUtils.test.js.map +1 -0
- package/dist/__tests__/FlashList.test.d.ts +2 -0
- package/dist/__tests__/FlashList.test.d.ts.map +1 -0
- package/dist/__tests__/FlashList.test.js +792 -0
- package/dist/__tests__/FlashList.test.js.map +1 -0
- package/dist/__tests__/GridLayoutProviderWithProps.test.d.ts +2 -0
- package/dist/__tests__/GridLayoutProviderWithProps.test.d.ts.map +1 -0
- package/dist/__tests__/GridLayoutProviderWithProps.test.js +143 -0
- package/dist/__tests__/GridLayoutProviderWithProps.test.js.map +1 -0
- package/dist/__tests__/MasonryFlashList.test.d.ts +2 -0
- package/dist/__tests__/MasonryFlashList.test.d.ts.map +1 -0
- package/dist/__tests__/MasonryFlashList.test.js +254 -0
- package/dist/__tests__/MasonryFlashList.test.js.map +1 -0
- package/dist/__tests__/PlatformHelper.web.test.d.ts +2 -0
- package/dist/__tests__/PlatformHelper.web.test.d.ts.map +1 -0
- package/dist/__tests__/PlatformHelper.web.test.js +33 -0
- package/dist/__tests__/PlatformHelper.web.test.js.map +1 -0
- package/dist/__tests__/ViewabilityHelper.test.d.ts +2 -0
- package/dist/__tests__/ViewabilityHelper.test.d.ts.map +1 -0
- package/dist/__tests__/ViewabilityHelper.test.js +187 -0
- package/dist/__tests__/ViewabilityHelper.test.js.map +1 -0
- package/dist/__tests__/helpers/mountFlashList.d.ts +19 -0
- package/dist/__tests__/helpers/mountFlashList.d.ts.map +1 -0
- package/dist/__tests__/helpers/mountFlashList.js +44 -0
- package/dist/__tests__/helpers/mountFlashList.js.map +1 -0
- package/dist/__tests__/helpers/mountMasonryFlashList.d.ts +18 -0
- package/dist/__tests__/helpers/mountMasonryFlashList.d.ts.map +1 -0
- package/dist/__tests__/helpers/mountMasonryFlashList.js +49 -0
- package/dist/__tests__/helpers/mountMasonryFlashList.js.map +1 -0
- package/dist/__tests__/useBlankAreaTracker.test.d.ts +2 -0
- package/dist/__tests__/useBlankAreaTracker.test.d.ts.map +1 -0
- package/dist/__tests__/useBlankAreaTracker.test.js +177 -0
- package/dist/__tests__/useBlankAreaTracker.test.js.map +1 -0
- package/dist/benchmark/AutoScrollHelper.d.ts +18 -0
- package/dist/benchmark/AutoScrollHelper.d.ts.map +1 -0
- package/dist/benchmark/AutoScrollHelper.js +68 -0
- package/dist/benchmark/AutoScrollHelper.js.map +1 -0
- package/dist/benchmark/JSFPSMonitor.d.ts +23 -0
- package/dist/benchmark/JSFPSMonitor.d.ts.map +1 -0
- package/dist/benchmark/JSFPSMonitor.js +65 -0
- package/dist/benchmark/JSFPSMonitor.js.map +1 -0
- package/dist/benchmark/roundToDecimalPlaces.d.ts +2 -0
- package/dist/benchmark/roundToDecimalPlaces.d.ts.map +1 -0
- package/dist/benchmark/roundToDecimalPlaces.js +9 -0
- package/dist/benchmark/roundToDecimalPlaces.js.map +1 -0
- package/dist/benchmark/useBenchmark.d.ts +35 -0
- package/dist/benchmark/useBenchmark.d.ts.map +1 -0
- package/dist/benchmark/useBenchmark.js +167 -0
- package/dist/benchmark/useBenchmark.js.map +1 -0
- package/dist/benchmark/useBlankAreaTracker.d.ts +34 -0
- package/dist/benchmark/useBlankAreaTracker.d.ts.map +1 -0
- package/dist/benchmark/useBlankAreaTracker.js +67 -0
- package/dist/benchmark/useBlankAreaTracker.js.map +1 -0
- package/dist/benchmark/useDataMultiplier.d.ts +9 -0
- package/dist/benchmark/useDataMultiplier.d.ts.map +1 -0
- package/dist/benchmark/useDataMultiplier.js +25 -0
- package/dist/benchmark/useDataMultiplier.js.map +1 -0
- package/dist/benchmark/useFlatListBenchmark.d.ts +13 -0
- package/dist/benchmark/useFlatListBenchmark.d.ts.map +1 -0
- package/dist/benchmark/useFlatListBenchmark.js +100 -0
- package/dist/benchmark/useFlatListBenchmark.js.map +1 -0
- package/dist/errors/CustomError.d.ts +8 -0
- package/dist/errors/CustomError.d.ts.map +1 -0
- package/dist/errors/CustomError.js +14 -0
- package/dist/errors/CustomError.js.map +1 -0
- package/dist/errors/ExceptionList.d.ts +24 -0
- package/dist/errors/ExceptionList.d.ts.map +1 -0
- package/dist/errors/ExceptionList.js +26 -0
- package/dist/errors/ExceptionList.js.map +1 -0
- package/dist/errors/Warnings.d.ts +9 -0
- package/dist/errors/Warnings.d.ts.map +1 -0
- package/dist/errors/Warnings.js +13 -0
- package/dist/errors/Warnings.js.map +1 -0
- package/dist/fabric/AutoLayoutNativeComponent.d.ts +19 -0
- package/dist/fabric/AutoLayoutNativeComponent.d.ts.map +1 -0
- package/dist/fabric/AutoLayoutNativeComponent.js +29 -0
- package/dist/fabric/AutoLayoutNativeComponent.js.map +1 -0
- package/dist/fabric/CellContainerNativeComponent.d.ts +8 -0
- package/dist/fabric/CellContainerNativeComponent.d.ts.map +1 -0
- package/dist/fabric/CellContainerNativeComponent.js +29 -0
- package/dist/fabric/CellContainerNativeComponent.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/native/auto-layout/AutoLayoutView.d.ts +22 -0
- package/dist/native/auto-layout/AutoLayoutView.d.ts.map +1 -0
- package/dist/native/auto-layout/AutoLayoutView.js +48 -0
- package/dist/native/auto-layout/AutoLayoutView.js.map +1 -0
- package/dist/native/auto-layout/AutoLayoutViewNativeComponent.android.d.ts +4 -0
- package/dist/native/auto-layout/AutoLayoutViewNativeComponent.android.d.ts.map +1 -0
- package/dist/native/auto-layout/AutoLayoutViewNativeComponent.android.js +6 -0
- package/dist/native/auto-layout/AutoLayoutViewNativeComponent.android.js.map +1 -0
- package/dist/native/auto-layout/AutoLayoutViewNativeComponent.d.ts +5 -0
- package/dist/native/auto-layout/AutoLayoutViewNativeComponent.d.ts.map +1 -0
- package/dist/native/auto-layout/AutoLayoutViewNativeComponent.harmony.d.ts +4 -0
- package/dist/native/auto-layout/AutoLayoutViewNativeComponent.harmony.d.ts.map +1 -0
- package/dist/native/auto-layout/AutoLayoutViewNativeComponent.harmony.js +29 -0
- package/dist/native/auto-layout/AutoLayoutViewNativeComponent.harmony.js.map +1 -0
- package/dist/native/auto-layout/AutoLayoutViewNativeComponent.ios.d.ts +4 -0
- package/dist/native/auto-layout/AutoLayoutViewNativeComponent.ios.d.ts.map +1 -0
- package/dist/native/auto-layout/AutoLayoutViewNativeComponent.ios.js +6 -0
- package/dist/native/auto-layout/AutoLayoutViewNativeComponent.ios.js.map +1 -0
- package/dist/native/auto-layout/AutoLayoutViewNativeComponent.js +6 -0
- package/dist/native/auto-layout/AutoLayoutViewNativeComponent.js.map +1 -0
- package/dist/native/auto-layout/AutoLayoutViewNativeComponentProps.d.ts +16 -0
- package/dist/native/auto-layout/AutoLayoutViewNativeComponentProps.d.ts.map +1 -0
- package/dist/native/auto-layout/AutoLayoutViewNativeComponentProps.js +3 -0
- package/dist/native/auto-layout/AutoLayoutViewNativeComponentProps.js.map +1 -0
- package/dist/native/cell-container/CellContainer.android.d.ts +6 -0
- package/dist/native/cell-container/CellContainer.android.d.ts.map +1 -0
- package/dist/native/cell-container/CellContainer.android.js +9 -0
- package/dist/native/cell-container/CellContainer.android.js.map +1 -0
- package/dist/native/cell-container/CellContainer.d.ts +8 -0
- package/dist/native/cell-container/CellContainer.d.ts.map +1 -0
- package/dist/native/cell-container/CellContainer.harmony.d.ts +6 -0
- package/dist/native/cell-container/CellContainer.harmony.d.ts.map +1 -0
- package/dist/native/cell-container/CellContainer.harmony.js +32 -0
- package/dist/native/cell-container/CellContainer.harmony.js.map +1 -0
- package/dist/native/cell-container/CellContainer.ios.d.ts +6 -0
- package/dist/native/cell-container/CellContainer.ios.d.ts.map +1 -0
- package/dist/native/cell-container/CellContainer.ios.js +9 -0
- package/dist/native/cell-container/CellContainer.ios.js.map +1 -0
- package/dist/native/cell-container/CellContainer.js +11 -0
- package/dist/native/cell-container/CellContainer.js.map +1 -0
- package/dist/native/cell-container/CellContainer.web.d.ts +7 -0
- package/dist/native/cell-container/CellContainer.web.d.ts.map +1 -0
- package/dist/native/cell-container/CellContainer.web.js +13 -0
- package/dist/native/cell-container/CellContainer.web.js.map +1 -0
- package/dist/native/config/PlatformHelper.android.d.ts +26 -0
- package/dist/native/config/PlatformHelper.android.d.ts.map +1 -0
- package/dist/native/config/PlatformHelper.android.js +23 -0
- package/dist/native/config/PlatformHelper.android.js.map +1 -0
- package/dist/native/config/PlatformHelper.d.ts +26 -0
- package/dist/native/config/PlatformHelper.d.ts.map +1 -0
- package/dist/native/config/PlatformHelper.harmony.d.ts +26 -0
- package/dist/native/config/PlatformHelper.harmony.d.ts.map +1 -0
- package/dist/native/config/PlatformHelper.harmony.js +22 -0
- package/dist/native/config/PlatformHelper.harmony.js.map +1 -0
- package/dist/native/config/PlatformHelper.ios.d.ts +26 -0
- package/dist/native/config/PlatformHelper.ios.d.ts.map +1 -0
- package/dist/native/config/PlatformHelper.ios.js +22 -0
- package/dist/native/config/PlatformHelper.ios.js.map +1 -0
- package/dist/native/config/PlatformHelper.js +23 -0
- package/dist/native/config/PlatformHelper.js.map +1 -0
- package/dist/native/config/PlatformHelper.web.d.ts +27 -0
- package/dist/native/config/PlatformHelper.web.d.ts.map +1 -0
- package/dist/native/config/PlatformHelper.web.js +25 -0
- package/dist/native/config/PlatformHelper.web.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/utils/AverageWindow.d.ts +21 -0
- package/dist/utils/AverageWindow.d.ts.map +1 -0
- package/dist/utils/AverageWindow.js +49 -0
- package/dist/utils/AverageWindow.js.map +1 -0
- package/dist/utils/ContentContainerUtils.d.ts +27 -0
- package/dist/utils/ContentContainerUtils.d.ts.map +1 -0
- package/dist/utils/ContentContainerUtils.js +48 -0
- package/dist/utils/ContentContainerUtils.js.map +1 -0
- package/dist/viewability/ViewToken.d.ts +8 -0
- package/dist/viewability/ViewToken.d.ts.map +1 -0
- package/dist/viewability/ViewToken.js +3 -0
- package/dist/viewability/ViewToken.js.map +1 -0
- package/dist/viewability/ViewabilityHelper.d.ts +25 -0
- package/dist/viewability/ViewabilityHelper.d.ts.map +1 -0
- package/dist/viewability/ViewabilityHelper.js +104 -0
- package/dist/viewability/ViewabilityHelper.js.map +1 -0
- package/dist/viewability/ViewabilityManager.d.ts +24 -0
- package/dist/viewability/ViewabilityManager.d.ts.map +1 -0
- package/dist/viewability/ViewabilityManager.js +94 -0
- package/dist/viewability/ViewabilityManager.js.map +1 -0
- package/harmony/flash_list/BuildProfile.ets +5 -0
- package/harmony/flash_list/LICENSE +7 -0
- package/harmony/flash_list/build-profile.json5 +8 -0
- package/harmony/flash_list/hvigorfile.ts +1 -0
- package/harmony/flash_list/index.ets +29 -0
- package/harmony/flash_list/obfuscation-rules.txt +18 -0
- package/harmony/flash_list/oh-package-lock.json5 +17 -0
- package/harmony/flash_list/oh-package.json5 +13 -0
- package/harmony/flash_list/src/main/cpp/AutoLayoutNode.cpp +63 -0
- package/harmony/flash_list/src/main/cpp/AutoLayoutNode.h +57 -0
- package/harmony/flash_list/src/main/cpp/AutoLayoutShadow.cpp +140 -0
- package/harmony/flash_list/src/main/cpp/AutoLayoutShadow.h +66 -0
- package/harmony/flash_list/src/main/cpp/AutoLayoutViewComponentInstance.cpp +208 -0
- package/harmony/flash_list/src/main/cpp/AutoLayoutViewComponentInstance.h +78 -0
- package/harmony/flash_list/src/main/cpp/AutoLayoutViewEventEmitRequestHandler.h +53 -0
- package/harmony/flash_list/src/main/cpp/AutoLayoutViewJSIBinder.h +50 -0
- package/harmony/flash_list/src/main/cpp/CMakeLists.txt +7 -0
- package/harmony/flash_list/src/main/cpp/CellContainerComponentInstance.cpp +80 -0
- package/harmony/flash_list/src/main/cpp/CellContainerComponentInstance.h +67 -0
- package/harmony/flash_list/src/main/cpp/CellContainerJSIBinder.h +39 -0
- package/harmony/flash_list/src/main/cpp/ComponentDescriptors.h +40 -0
- package/harmony/flash_list/src/main/cpp/EventEmitters.cpp +40 -0
- package/harmony/flash_list/src/main/cpp/EventEmitters.h +48 -0
- package/harmony/flash_list/src/main/cpp/FlashListPackage.h +78 -0
- package/harmony/flash_list/src/main/cpp/FlashListStackNode.cpp +89 -0
- package/harmony/flash_list/src/main/cpp/FlashListStackNode.h +59 -0
- package/harmony/flash_list/src/main/cpp/Props.cpp +52 -0
- package/harmony/flash_list/src/main/cpp/Props.h +64 -0
- package/harmony/flash_list/src/main/cpp/ShadowNodes.cpp +34 -0
- package/harmony/flash_list/src/main/cpp/ShadowNodes.h +48 -0
- package/harmony/flash_list/src/main/ets/Logger.ets +64 -0
- package/harmony/flash_list/src/main/ets/RNAutoLayoutShadow.ets +154 -0
- package/harmony/flash_list/src/main/ets/RNAutoLayoutView.ets +252 -0
- package/harmony/flash_list/src/main/ets/RNCellContainer.ets +113 -0
- package/harmony/flash_list/src/main/module.json5 +7 -0
- package/harmony/flash_list/src/main/resources/base/element/color.json +8 -0
- package/harmony/flash_list/src/main/resources/base/element/string.json +16 -0
- package/harmony/flash_list/src/main/resources/base/media/icon.png +0 -0
- package/harmony/flash_list/src/main/resources/base/profile/main_pages.json +5 -0
- package/harmony/flash_list/src/main/resources/en_US/element/string.json +16 -0
- package/harmony/flash_list/src/main/resources/zh_CN/element/string.json +16 -0
- package/harmony/flash_list.har +0 -0
- package/jestSetup.js +16 -0
- package/package.json +88 -0
- package/src/AnimatedFlashList.ts +11 -0
- package/src/FlashList.tsx +870 -0
- package/src/FlashListProps.ts +335 -0
- package/src/GridLayoutProviderWithProps.ts +180 -0
- package/src/MasonryFlashList.tsx +476 -0
- package/src/PureComponentWrapper.tsx +42 -0
- package/src/__tests__/AverageWindow.test.ts +80 -0
- package/src/__tests__/ContentContainerUtils.test.ts +130 -0
- package/src/__tests__/FlashList.test.tsx +886 -0
- package/src/__tests__/GridLayoutProviderWithProps.test.ts +179 -0
- package/src/__tests__/MasonryFlashList.test.ts +292 -0
- package/src/__tests__/PlatformHelper.web.test.ts +45 -0
- package/src/__tests__/ViewabilityHelper.test.ts +283 -0
- package/src/__tests__/helpers/mountFlashList.tsx +62 -0
- package/src/__tests__/helpers/mountMasonryFlashList.tsx +70 -0
- package/src/__tests__/useBlankAreaTracker.test.tsx +204 -0
- package/src/benchmark/AutoScrollHelper.ts +70 -0
- package/src/benchmark/JSFPSMonitor.ts +74 -0
- package/src/benchmark/roundToDecimalPlaces.ts +4 -0
- package/src/benchmark/useBenchmark.ts +240 -0
- package/src/benchmark/useBlankAreaTracker.ts +117 -0
- package/src/benchmark/useDataMultiplier.ts +19 -0
- package/src/benchmark/useFlatListBenchmark.ts +107 -0
- package/src/errors/CustomError.ts +10 -0
- package/src/errors/ExceptionList.ts +28 -0
- package/src/errors/Warnings.ts +15 -0
- package/src/fabric/AutoLayoutNativeComponent.ts +51 -0
- package/src/fabric/CellContainerNativeComponent.ts +34 -0
- package/src/index.ts +43 -0
- package/src/native/auto-layout/AutoLayoutView.tsx +73 -0
- package/src/native/auto-layout/AutoLayoutViewNativeComponent.android.ts +7 -0
- package/src/native/auto-layout/AutoLayoutViewNativeComponent.harmony.ts +30 -0
- package/src/native/auto-layout/AutoLayoutViewNativeComponent.ios.ts +7 -0
- package/src/native/auto-layout/AutoLayoutViewNativeComponent.ts +7 -0
- package/src/native/auto-layout/AutoLayoutViewNativeComponentProps.ts +17 -0
- package/src/native/cell-container/CellContainer.android.ts +7 -0
- package/src/native/cell-container/CellContainer.harmony.ts +30 -0
- package/src/native/cell-container/CellContainer.ios.ts +6 -0
- package/src/native/cell-container/CellContainer.tsx +14 -0
- package/src/native/cell-container/CellContainer.web.tsx +9 -0
- package/src/native/config/PlatformHelper.android.ts +29 -0
- package/src/native/config/PlatformHelper.harmony.ts +51 -0
- package/src/native/config/PlatformHelper.ios.ts +28 -0
- package/src/native/config/PlatformHelper.ts +29 -0
- package/src/native/config/PlatformHelper.web.ts +34 -0
- package/src/utils/AverageWindow.ts +49 -0
- package/src/utils/ContentContainerUtils.ts +92 -0
- package/src/viewability/ViewToken.ts +7 -0
- package/src/viewability/ViewabilityHelper.ts +162 -0
- package/src/viewability/ViewabilityManager.ts +134 -0
|
@@ -0,0 +1,886 @@
|
|
|
1
|
+
import React, { useEffect } from "react";
|
|
2
|
+
import { Animated, ScrollView, Text, View } from "react-native";
|
|
3
|
+
import "@quilted/react-testing/matchers";
|
|
4
|
+
import { ProgressiveListView } from "recyclerlistview";
|
|
5
|
+
|
|
6
|
+
import Warnings from "../errors/Warnings";
|
|
7
|
+
import AutoLayoutView from "../native/auto-layout/AutoLayoutView";
|
|
8
|
+
import CellContainer from "../native/cell-container/CellContainer";
|
|
9
|
+
import { ListRenderItemInfo, RenderTargetOptions } from "../FlashListProps";
|
|
10
|
+
|
|
11
|
+
import { mountFlashList } from "./helpers/mountFlashList";
|
|
12
|
+
|
|
13
|
+
jest.mock("../native/cell-container/CellContainer", () => {
|
|
14
|
+
return jest.requireActual("../native/cell-container/CellContainer.ios.ts")
|
|
15
|
+
.default;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe("FlashList", () => {
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
jest.clearAllMocks();
|
|
21
|
+
jest.useFakeTimers();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("renders items", () => {
|
|
25
|
+
const flashList = mountFlashList();
|
|
26
|
+
expect(flashList).toContainReactComponent(Text, { children: "One" });
|
|
27
|
+
expect(flashList).toContainReactComponent(ProgressiveListView, {
|
|
28
|
+
isHorizontal: false,
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("sets ProgressiveListView to horizontal", () => {
|
|
33
|
+
const flashList = mountFlashList({ horizontal: true });
|
|
34
|
+
expect(flashList).toContainReactComponent(ProgressiveListView, {
|
|
35
|
+
isHorizontal: true,
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("calls prepareForLayoutAnimationRender", () => {
|
|
40
|
+
const flashList = mountFlashList({
|
|
41
|
+
keyExtractor: (item) => item,
|
|
42
|
+
});
|
|
43
|
+
const warn = jest.spyOn(console, "warn").mockReturnValue();
|
|
44
|
+
const prepareForLayoutAnimationRender = jest.spyOn(
|
|
45
|
+
flashList.instance!.recyclerlistview_unsafe!,
|
|
46
|
+
"prepareForLayoutAnimationRender"
|
|
47
|
+
);
|
|
48
|
+
flashList.instance.prepareForLayoutAnimationRender();
|
|
49
|
+
expect(prepareForLayoutAnimationRender).toHaveBeenCalledTimes(1);
|
|
50
|
+
expect(warn).not.toHaveBeenCalled();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("sends a warning when prepareForLayoutAnimationRender without keyExtractor", () => {
|
|
54
|
+
const flashList = mountFlashList();
|
|
55
|
+
const warn = jest.spyOn(console, "warn").mockReturnValue();
|
|
56
|
+
const prepareForLayoutAnimationRender = jest.spyOn(
|
|
57
|
+
flashList.instance!.recyclerlistview_unsafe!,
|
|
58
|
+
"prepareForLayoutAnimationRender"
|
|
59
|
+
);
|
|
60
|
+
flashList.instance.prepareForLayoutAnimationRender();
|
|
61
|
+
expect(prepareForLayoutAnimationRender).not.toHaveBeenCalled();
|
|
62
|
+
expect(warn).toHaveBeenCalledWith(Warnings.missingKeyExtractor);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("disables initial scroll correction on recyclerlistview if initialScrollIndex is in first row", () => {
|
|
66
|
+
let flashList = mountFlashList({ initialScrollIndex: 0, numColumns: 3 });
|
|
67
|
+
expect(
|
|
68
|
+
flashList.instance["getUpdatedWindowCorrectionConfig"]()
|
|
69
|
+
.applyToInitialOffset
|
|
70
|
+
).toBe(false);
|
|
71
|
+
|
|
72
|
+
flashList = mountFlashList({ initialScrollIndex: 3, numColumns: 3 });
|
|
73
|
+
expect(
|
|
74
|
+
flashList.instance["getUpdatedWindowCorrectionConfig"]()
|
|
75
|
+
.applyToInitialOffset
|
|
76
|
+
).toBe(true);
|
|
77
|
+
|
|
78
|
+
flashList = mountFlashList({ initialScrollIndex: 2, numColumns: 3 });
|
|
79
|
+
expect(
|
|
80
|
+
flashList.instance["getUpdatedWindowCorrectionConfig"]()
|
|
81
|
+
.applyToInitialOffset
|
|
82
|
+
).toBe(false);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("assigns distance from window to window correction object", () => {
|
|
86
|
+
const flashList = mountFlashList({ estimatedFirstItemOffset: 100 });
|
|
87
|
+
expect(
|
|
88
|
+
flashList.instance["getUpdatedWindowCorrectionConfig"]().value.windowShift
|
|
89
|
+
).toBe(-100);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("only forwards onBlankArea prop to AutoLayout when needed", () => {
|
|
93
|
+
const flashList = mountFlashList();
|
|
94
|
+
const autoLayoutView = flashList.find(AutoLayoutView)?.instance;
|
|
95
|
+
expect(autoLayoutView.props.onBlankAreaEvent).toBeUndefined();
|
|
96
|
+
flashList.setProps({ onBlankArea: () => {} });
|
|
97
|
+
expect(autoLayoutView.props.onBlankAreaEvent).not.toBeUndefined();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("calls render item only when data of the items has changed", () => {
|
|
101
|
+
const renderItemMock = jest.fn(({ item }) => {
|
|
102
|
+
return <Text>{item}</Text>;
|
|
103
|
+
});
|
|
104
|
+
const flashList = mountFlashList({
|
|
105
|
+
renderItem: renderItemMock,
|
|
106
|
+
data: ["One", "Two", "Three", "Four"],
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// because we have 4 data items
|
|
110
|
+
expect(renderItemMock).toHaveBeenCalledTimes(4);
|
|
111
|
+
// reset counter
|
|
112
|
+
renderItemMock.mockClear();
|
|
113
|
+
// changes layout of all four items
|
|
114
|
+
flashList.setProps({ numColumns: 2 });
|
|
115
|
+
// render item should be called 0 times because only layout of items would have changed
|
|
116
|
+
expect(renderItemMock).toHaveBeenCalledTimes(0);
|
|
117
|
+
flashList.unmount();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("keeps component mounted based on prepareForLayoutAnimationRender being called", () => {
|
|
121
|
+
// Tracks components being unmounted
|
|
122
|
+
const unmountMock = jest.fn();
|
|
123
|
+
const Item = ({ text }: { text: string }) => {
|
|
124
|
+
useEffect(() => {
|
|
125
|
+
return unmountMock;
|
|
126
|
+
}, []);
|
|
127
|
+
return <Text>{text}</Text>;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const flashList = mountFlashList({
|
|
131
|
+
keyExtractor: (item) => item,
|
|
132
|
+
renderItem: ({ item }) => {
|
|
133
|
+
return <Item text={item} />;
|
|
134
|
+
},
|
|
135
|
+
data: ["One", "Two", "Three", "Four"],
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Change data without prepareForLayoutAnimationRender
|
|
139
|
+
flashList.setProps({ data: ["One", "Two", "Three", "Five"] });
|
|
140
|
+
expect(unmountMock).not.toHaveBeenCalled();
|
|
141
|
+
|
|
142
|
+
// Before changing data, we run prepareForLayoutAnimationRender.
|
|
143
|
+
// This ensures component gets unmounted instead of being recycled to ensure layout animations run as expected.
|
|
144
|
+
flashList.instance.prepareForLayoutAnimationRender();
|
|
145
|
+
flashList.setProps({ data: ["One", "Two", "Three", "Six"] });
|
|
146
|
+
expect(unmountMock).toHaveBeenCalledTimes(1);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("fires onLoad event", () => {
|
|
150
|
+
const onLoadMock = jest.fn();
|
|
151
|
+
|
|
152
|
+
// empty list
|
|
153
|
+
mountFlashList({ data: [], onLoad: onLoadMock });
|
|
154
|
+
expect(onLoadMock).toHaveBeenCalledWith({
|
|
155
|
+
elapsedTimeInMs: expect.any(Number),
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
onLoadMock.mockClear();
|
|
159
|
+
|
|
160
|
+
// non-empty list
|
|
161
|
+
const flashList = mountFlashList({ onLoad: onLoadMock });
|
|
162
|
+
flashList.find(ProgressiveListView)?.instance.onItemLayout(0);
|
|
163
|
+
expect(onLoadMock).toHaveBeenCalledWith({
|
|
164
|
+
elapsedTimeInMs: expect.any(Number),
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it("loads an empty state", () => {
|
|
169
|
+
const EmptyComponent = () => {
|
|
170
|
+
return <Text>Empty</Text>;
|
|
171
|
+
};
|
|
172
|
+
const flashList = mountFlashList({
|
|
173
|
+
data: [],
|
|
174
|
+
ListEmptyComponent: EmptyComponent,
|
|
175
|
+
});
|
|
176
|
+
expect(flashList).toContainReactComponent(EmptyComponent);
|
|
177
|
+
});
|
|
178
|
+
it("loads header and footer in empty state", () => {
|
|
179
|
+
const HeaderComponent = () => {
|
|
180
|
+
return <Text>Empty</Text>;
|
|
181
|
+
};
|
|
182
|
+
const FooterComponent = () => {
|
|
183
|
+
return <Text>Empty</Text>;
|
|
184
|
+
};
|
|
185
|
+
const flashList = mountFlashList({
|
|
186
|
+
data: [],
|
|
187
|
+
ListHeaderComponent: HeaderComponent,
|
|
188
|
+
ListFooterComponent: FooterComponent,
|
|
189
|
+
});
|
|
190
|
+
expect(flashList).toContainReactComponent(HeaderComponent);
|
|
191
|
+
expect(flashList).toContainReactComponent(FooterComponent);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it("reports layout changes to the layout provider", () => {
|
|
195
|
+
const flashList = mountFlashList();
|
|
196
|
+
const reportItemLayoutMock = jest.spyOn(
|
|
197
|
+
flashList.instance.state.layoutProvider,
|
|
198
|
+
"reportItemLayout"
|
|
199
|
+
);
|
|
200
|
+
flashList.find(ProgressiveListView)?.instance.onItemLayout(0);
|
|
201
|
+
expect(reportItemLayoutMock).toHaveBeenCalledWith(0);
|
|
202
|
+
flashList.unmount();
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("should prefer overrideItemLayout over estimate and average", () => {
|
|
206
|
+
const flashList = mountFlashList({
|
|
207
|
+
overrideItemLayout: (layout) => {
|
|
208
|
+
layout.size = 50;
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
expect(flashList.instance.state.layoutProvider.averageItemSize).toBe(200);
|
|
212
|
+
expect(
|
|
213
|
+
flashList.instance.state
|
|
214
|
+
.layoutProvider!.getLayoutManager()!
|
|
215
|
+
.getLayouts()[0].height
|
|
216
|
+
).toBe(50);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it("should override span with overrideItemLayout", () => {
|
|
220
|
+
const renderItemMock = jest.fn(({ item }) => {
|
|
221
|
+
return <Text>{item}</Text>;
|
|
222
|
+
});
|
|
223
|
+
mountFlashList({
|
|
224
|
+
overrideItemLayout: (layout) => {
|
|
225
|
+
layout.span = 2;
|
|
226
|
+
},
|
|
227
|
+
numColumns: 2,
|
|
228
|
+
estimatedItemSize: 300,
|
|
229
|
+
renderItem: renderItemMock,
|
|
230
|
+
});
|
|
231
|
+
expect(renderItemMock).toHaveBeenCalledTimes(3);
|
|
232
|
+
|
|
233
|
+
renderItemMock.mockClear();
|
|
234
|
+
mountFlashList({
|
|
235
|
+
overrideItemLayout: (layout, _, index) => {
|
|
236
|
+
if (index > 2) {
|
|
237
|
+
layout.span = 2;
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
data: new Array(20).fill(""),
|
|
241
|
+
numColumns: 3,
|
|
242
|
+
estimatedItemSize: 100,
|
|
243
|
+
renderItem: renderItemMock,
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
expect(renderItemMock).toHaveBeenCalledTimes(11);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it("overrideItemLayout should consider 0 as a valid span", () => {
|
|
250
|
+
const renderItemMock = jest.fn(({ item }) => {
|
|
251
|
+
return <Text>{item}</Text>;
|
|
252
|
+
});
|
|
253
|
+
mountFlashList({
|
|
254
|
+
overrideItemLayout: (layout, _, index) => {
|
|
255
|
+
if (index < 4) {
|
|
256
|
+
layout.span = 0;
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
data: new Array(20).fill(""),
|
|
260
|
+
numColumns: 2,
|
|
261
|
+
renderItem: renderItemMock,
|
|
262
|
+
});
|
|
263
|
+
expect(renderItemMock).toHaveBeenCalledTimes(14);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it("reports onViewableItemsChanged for viewable items", () => {
|
|
267
|
+
const onViewableItemsChanged = jest.fn();
|
|
268
|
+
const onViewableItemsChangedForItemVisiblePercentThreshold = jest.fn();
|
|
269
|
+
const flashList = mountFlashList({
|
|
270
|
+
estimatedItemSize: 300,
|
|
271
|
+
viewabilityConfig: {
|
|
272
|
+
minimumViewTime: 250,
|
|
273
|
+
},
|
|
274
|
+
viewabilityConfigCallbackPairs: [
|
|
275
|
+
{
|
|
276
|
+
onViewableItemsChanged:
|
|
277
|
+
onViewableItemsChangedForItemVisiblePercentThreshold,
|
|
278
|
+
viewabilityConfig: {
|
|
279
|
+
itemVisiblePercentThreshold: 50,
|
|
280
|
+
waitForInteraction: true,
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
],
|
|
284
|
+
onViewableItemsChanged,
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// onViewableItemsChanged is not called before 250 ms have elapsed
|
|
288
|
+
expect(onViewableItemsChanged).not.toHaveBeenCalled();
|
|
289
|
+
|
|
290
|
+
jest.advanceTimersByTime(250);
|
|
291
|
+
// Initial viewable items
|
|
292
|
+
expect(onViewableItemsChanged).toHaveBeenCalledWith({
|
|
293
|
+
changed: [
|
|
294
|
+
{
|
|
295
|
+
index: 0,
|
|
296
|
+
isViewable: true,
|
|
297
|
+
item: "One",
|
|
298
|
+
key: "0",
|
|
299
|
+
timestamp: expect.any(Number),
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
index: 1,
|
|
303
|
+
isViewable: true,
|
|
304
|
+
item: "Two",
|
|
305
|
+
key: "1",
|
|
306
|
+
timestamp: expect.any(Number),
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
index: 2,
|
|
310
|
+
isViewable: true,
|
|
311
|
+
item: "Three",
|
|
312
|
+
key: "2",
|
|
313
|
+
timestamp: expect.any(Number),
|
|
314
|
+
},
|
|
315
|
+
],
|
|
316
|
+
viewableItems: [
|
|
317
|
+
{
|
|
318
|
+
index: 0,
|
|
319
|
+
isViewable: true,
|
|
320
|
+
item: "One",
|
|
321
|
+
key: "0",
|
|
322
|
+
timestamp: expect.any(Number),
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
index: 1,
|
|
326
|
+
isViewable: true,
|
|
327
|
+
item: "Two",
|
|
328
|
+
key: "1",
|
|
329
|
+
timestamp: expect.any(Number),
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
index: 2,
|
|
333
|
+
isViewable: true,
|
|
334
|
+
item: "Three",
|
|
335
|
+
key: "2",
|
|
336
|
+
timestamp: expect.any(Number),
|
|
337
|
+
},
|
|
338
|
+
],
|
|
339
|
+
});
|
|
340
|
+
expect(
|
|
341
|
+
onViewableItemsChangedForItemVisiblePercentThreshold
|
|
342
|
+
).not.toHaveBeenCalled();
|
|
343
|
+
|
|
344
|
+
// onViewableItemsChangedForItemVisiblePercentThreshold waits for interaction before reporting viewable items
|
|
345
|
+
flashList.instance.recordInteraction();
|
|
346
|
+
jest.advanceTimersByTime(250);
|
|
347
|
+
expect(
|
|
348
|
+
onViewableItemsChangedForItemVisiblePercentThreshold
|
|
349
|
+
).toHaveBeenCalledWith({
|
|
350
|
+
changed: [
|
|
351
|
+
{
|
|
352
|
+
index: 0,
|
|
353
|
+
isViewable: true,
|
|
354
|
+
item: "One",
|
|
355
|
+
key: "0",
|
|
356
|
+
timestamp: expect.any(Number),
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
index: 1,
|
|
360
|
+
isViewable: true,
|
|
361
|
+
item: "Two",
|
|
362
|
+
key: "1",
|
|
363
|
+
timestamp: expect.any(Number),
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
index: 2,
|
|
367
|
+
isViewable: true,
|
|
368
|
+
item: "Three",
|
|
369
|
+
key: "2",
|
|
370
|
+
timestamp: expect.any(Number),
|
|
371
|
+
},
|
|
372
|
+
],
|
|
373
|
+
viewableItems: [
|
|
374
|
+
{
|
|
375
|
+
index: 0,
|
|
376
|
+
isViewable: true,
|
|
377
|
+
item: "One",
|
|
378
|
+
key: "0",
|
|
379
|
+
timestamp: expect.any(Number),
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
index: 1,
|
|
383
|
+
isViewable: true,
|
|
384
|
+
item: "Two",
|
|
385
|
+
key: "1",
|
|
386
|
+
timestamp: expect.any(Number),
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
index: 2,
|
|
390
|
+
isViewable: true,
|
|
391
|
+
item: "Three",
|
|
392
|
+
key: "2",
|
|
393
|
+
timestamp: expect.any(Number),
|
|
394
|
+
},
|
|
395
|
+
],
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
onViewableItemsChanged.mockReset();
|
|
399
|
+
onViewableItemsChangedForItemVisiblePercentThreshold.mockReset();
|
|
400
|
+
// Mocking a scroll that will make the first item not visible and the last item visible
|
|
401
|
+
jest
|
|
402
|
+
.spyOn(
|
|
403
|
+
flashList.instance!.recyclerlistview_unsafe!,
|
|
404
|
+
"getCurrentScrollOffset"
|
|
405
|
+
)
|
|
406
|
+
.mockReturnValue(200);
|
|
407
|
+
flashList.instance!.recyclerlistview_unsafe!.props.onVisibleIndicesChanged?.(
|
|
408
|
+
[0, 1, 2, 3],
|
|
409
|
+
[],
|
|
410
|
+
[]
|
|
411
|
+
);
|
|
412
|
+
flashList.instance!.recyclerlistview_unsafe!.props.onScroll?.(
|
|
413
|
+
{ nativeEvent: { contentOffset: { x: 0, y: 200 } } },
|
|
414
|
+
0,
|
|
415
|
+
200
|
|
416
|
+
);
|
|
417
|
+
jest.advanceTimersByTime(250);
|
|
418
|
+
expect(onViewableItemsChanged).toHaveBeenCalledWith({
|
|
419
|
+
changed: [
|
|
420
|
+
{
|
|
421
|
+
index: 3,
|
|
422
|
+
isViewable: true,
|
|
423
|
+
item: "Four",
|
|
424
|
+
key: "3",
|
|
425
|
+
timestamp: expect.any(Number),
|
|
426
|
+
},
|
|
427
|
+
],
|
|
428
|
+
viewableItems: [
|
|
429
|
+
{
|
|
430
|
+
index: 0,
|
|
431
|
+
isViewable: true,
|
|
432
|
+
item: "One",
|
|
433
|
+
key: "0",
|
|
434
|
+
timestamp: expect.any(Number),
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
index: 1,
|
|
438
|
+
isViewable: true,
|
|
439
|
+
item: "Two",
|
|
440
|
+
key: "1",
|
|
441
|
+
timestamp: expect.any(Number),
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
index: 2,
|
|
445
|
+
isViewable: true,
|
|
446
|
+
item: "Three",
|
|
447
|
+
key: "2",
|
|
448
|
+
timestamp: expect.any(Number),
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
index: 3,
|
|
452
|
+
isViewable: true,
|
|
453
|
+
item: "Four",
|
|
454
|
+
key: "3",
|
|
455
|
+
timestamp: expect.any(Number),
|
|
456
|
+
},
|
|
457
|
+
],
|
|
458
|
+
});
|
|
459
|
+
expect(
|
|
460
|
+
onViewableItemsChangedForItemVisiblePercentThreshold
|
|
461
|
+
).toHaveBeenCalledWith({
|
|
462
|
+
changed: [
|
|
463
|
+
{
|
|
464
|
+
index: 3,
|
|
465
|
+
isViewable: true,
|
|
466
|
+
item: "Four",
|
|
467
|
+
key: "3",
|
|
468
|
+
timestamp: expect.any(Number),
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
index: 0,
|
|
472
|
+
isViewable: false,
|
|
473
|
+
item: "One",
|
|
474
|
+
key: "0",
|
|
475
|
+
timestamp: expect.any(Number),
|
|
476
|
+
},
|
|
477
|
+
],
|
|
478
|
+
viewableItems: [
|
|
479
|
+
{
|
|
480
|
+
index: 1,
|
|
481
|
+
isViewable: true,
|
|
482
|
+
item: "Two",
|
|
483
|
+
key: "1",
|
|
484
|
+
timestamp: expect.any(Number),
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
index: 2,
|
|
488
|
+
isViewable: true,
|
|
489
|
+
item: "Three",
|
|
490
|
+
key: "2",
|
|
491
|
+
timestamp: expect.any(Number),
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
index: 3,
|
|
495
|
+
isViewable: true,
|
|
496
|
+
item: "Four",
|
|
497
|
+
key: "3",
|
|
498
|
+
timestamp: expect.any(Number),
|
|
499
|
+
},
|
|
500
|
+
],
|
|
501
|
+
});
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
it("viewability reports take into account estimatedFirstItemOffset", () => {
|
|
505
|
+
const onViewableItemsChanged = jest.fn();
|
|
506
|
+
mountFlashList({
|
|
507
|
+
estimatedFirstItemOffset: 200,
|
|
508
|
+
estimatedItemSize: 300,
|
|
509
|
+
onViewableItemsChanged,
|
|
510
|
+
viewabilityConfig: { itemVisiblePercentThreshold: 50 },
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
// onViewableItemsChanged is not called before 250 ms have elapsed
|
|
514
|
+
expect(onViewableItemsChanged).not.toHaveBeenCalled();
|
|
515
|
+
|
|
516
|
+
jest.advanceTimersByTime(250);
|
|
517
|
+
// Initial viewable items
|
|
518
|
+
expect(onViewableItemsChanged).toHaveBeenCalledWith({
|
|
519
|
+
changed: [
|
|
520
|
+
{
|
|
521
|
+
index: 0,
|
|
522
|
+
isViewable: true,
|
|
523
|
+
item: "One",
|
|
524
|
+
key: "0",
|
|
525
|
+
timestamp: expect.any(Number),
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
index: 1,
|
|
529
|
+
isViewable: true,
|
|
530
|
+
item: "Two",
|
|
531
|
+
key: "1",
|
|
532
|
+
timestamp: expect.any(Number),
|
|
533
|
+
},
|
|
534
|
+
],
|
|
535
|
+
viewableItems: [
|
|
536
|
+
{
|
|
537
|
+
index: 0,
|
|
538
|
+
isViewable: true,
|
|
539
|
+
item: "One",
|
|
540
|
+
key: "0",
|
|
541
|
+
timestamp: expect.any(Number),
|
|
542
|
+
},
|
|
543
|
+
{
|
|
544
|
+
index: 1,
|
|
545
|
+
isViewable: true,
|
|
546
|
+
item: "Two",
|
|
547
|
+
key: "1",
|
|
548
|
+
timestamp: expect.any(Number),
|
|
549
|
+
},
|
|
550
|
+
],
|
|
551
|
+
});
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
it("should not overlap header with sitcky index 0", () => {
|
|
555
|
+
const HeaderComponent = () => {
|
|
556
|
+
return <Text>Empty</Text>;
|
|
557
|
+
};
|
|
558
|
+
const flashList = mountFlashList({
|
|
559
|
+
ListHeaderComponent: HeaderComponent,
|
|
560
|
+
stickyHeaderIndices: [0],
|
|
561
|
+
});
|
|
562
|
+
// If sticky renders there'll be 6
|
|
563
|
+
expect(flashList.findAll(Text).length).toBe(5);
|
|
564
|
+
});
|
|
565
|
+
it("rerenders all items when layout manager changes", () => {
|
|
566
|
+
let countMounts = 0;
|
|
567
|
+
let currentId = 0;
|
|
568
|
+
|
|
569
|
+
// Effect will be triggered once per mount
|
|
570
|
+
const RenderComponent = ({ id }: { id?: number }) => {
|
|
571
|
+
useEffect(() => {
|
|
572
|
+
countMounts++;
|
|
573
|
+
}, [id]);
|
|
574
|
+
return <Text>Test</Text>;
|
|
575
|
+
};
|
|
576
|
+
const renderItem = () => {
|
|
577
|
+
return <RenderComponent id={currentId} />;
|
|
578
|
+
};
|
|
579
|
+
const flashList = mountFlashList({
|
|
580
|
+
data: new Array(100).fill("1"),
|
|
581
|
+
estimatedItemSize: 70,
|
|
582
|
+
renderItem,
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
const scrollTo = (y: number) => {
|
|
586
|
+
flashList.find(ScrollView)?.trigger("onScroll", {
|
|
587
|
+
nativeEvent: { contentOffset: { x: 0, y } },
|
|
588
|
+
});
|
|
589
|
+
};
|
|
590
|
+
|
|
591
|
+
// Mocking some scrolls
|
|
592
|
+
scrollTo(200);
|
|
593
|
+
scrollTo(400);
|
|
594
|
+
scrollTo(600);
|
|
595
|
+
scrollTo(3000);
|
|
596
|
+
scrollTo(2000);
|
|
597
|
+
|
|
598
|
+
// changing id will trigger effects if components rerender
|
|
599
|
+
currentId = 1;
|
|
600
|
+
|
|
601
|
+
// capturing current component count to check later
|
|
602
|
+
const currentComponentCount = countMounts;
|
|
603
|
+
|
|
604
|
+
// resetting count
|
|
605
|
+
countMounts = 0;
|
|
606
|
+
|
|
607
|
+
// items widths before layout manager change should be 400
|
|
608
|
+
flashList.findAll(CellContainer).forEach((cell) => {
|
|
609
|
+
if (cell.props.index !== -1) {
|
|
610
|
+
expect(cell.instance.props.style.width).toBe(400);
|
|
611
|
+
}
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
// This will cause a layout manager change
|
|
615
|
+
flashList.find(ScrollView)?.trigger("onLayout", {
|
|
616
|
+
nativeEvent: { layout: { height: 400, width: 900 } },
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
// If counts match, then all components were updated
|
|
620
|
+
expect(countMounts).toBe(currentComponentCount);
|
|
621
|
+
|
|
622
|
+
// items widths after layout manager change should be 900
|
|
623
|
+
flashList.findAll(CellContainer).forEach((cell) => {
|
|
624
|
+
if (cell.props.index !== -1) {
|
|
625
|
+
expect(cell.instance.props.style.width).toBe(900);
|
|
626
|
+
}
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
flashList.unmount();
|
|
630
|
+
});
|
|
631
|
+
it("sends a warning when estimatedItemSize is not set", () => {
|
|
632
|
+
const warn = jest.spyOn(console, "warn").mockReturnValue();
|
|
633
|
+
|
|
634
|
+
const flashList = mountFlashList({
|
|
635
|
+
disableDefaultEstimatedItemSize: true,
|
|
636
|
+
renderItem: ({ item }) => <Text style={{ height: 200 }}>{item}</Text>,
|
|
637
|
+
});
|
|
638
|
+
const layoutData = flashList.instance.state.layoutProvider
|
|
639
|
+
.getLayoutManager()!
|
|
640
|
+
.getLayouts();
|
|
641
|
+
layoutData[0].height = 100;
|
|
642
|
+
layoutData[1].height = 200;
|
|
643
|
+
layoutData[2].height = 300;
|
|
644
|
+
flashList.find(ProgressiveListView)?.instance.onItemLayout(0);
|
|
645
|
+
expect(flashList.instance.state.layoutProvider.averageItemSize).toBe(100);
|
|
646
|
+
flashList.find(ProgressiveListView)?.instance.onItemLayout(1);
|
|
647
|
+
flashList.find(ProgressiveListView)?.instance.onItemLayout(2);
|
|
648
|
+
jest.advanceTimersByTime(1000);
|
|
649
|
+
const averageItemSize =
|
|
650
|
+
flashList.instance.state.layoutProvider.averageItemSize;
|
|
651
|
+
expect(warn).toHaveBeenCalledWith(
|
|
652
|
+
Warnings.estimatedItemSizeMissingWarning.replace(
|
|
653
|
+
"@size",
|
|
654
|
+
averageItemSize.toString()
|
|
655
|
+
)
|
|
656
|
+
);
|
|
657
|
+
expect(flashList.instance.state.layoutProvider.averageItemSize).toBe(175);
|
|
658
|
+
flashList.unmount();
|
|
659
|
+
});
|
|
660
|
+
it("clears size warning timeout on unmount", () => {
|
|
661
|
+
const warn = jest.spyOn(console, "warn").mockReturnValue();
|
|
662
|
+
|
|
663
|
+
const flashList = mountFlashList({
|
|
664
|
+
disableDefaultEstimatedItemSize: true,
|
|
665
|
+
});
|
|
666
|
+
flashList.find(ProgressiveListView)?.instance.onItemLayout(0);
|
|
667
|
+
flashList.unmount();
|
|
668
|
+
jest.advanceTimersByTime(1000);
|
|
669
|
+
expect(warn).toBeCalledTimes(0);
|
|
670
|
+
});
|
|
671
|
+
it("measure size of horizontal list when appropriate", () => {
|
|
672
|
+
let flashList = mountFlashList({
|
|
673
|
+
data: new Array(1).fill("1"),
|
|
674
|
+
horizontal: true,
|
|
675
|
+
});
|
|
676
|
+
const forceUpdate = jest.spyOn(flashList.instance, "forceUpdate");
|
|
677
|
+
// should contain 1 actual text and 1 dummy on mount
|
|
678
|
+
expect(flashList.findAll(Text).length).toBe(2);
|
|
679
|
+
|
|
680
|
+
// Trigger onLoad
|
|
681
|
+
flashList.instance["onItemLayout"](0);
|
|
682
|
+
jest.advanceTimersByTime(600);
|
|
683
|
+
|
|
684
|
+
expect(forceUpdate).toBeCalledTimes(1);
|
|
685
|
+
|
|
686
|
+
// TODO: Investigate why forceUpdate isn't working in tests, forcing an update
|
|
687
|
+
flashList.setProps({ overrideItemLayout: () => {} });
|
|
688
|
+
|
|
689
|
+
// After update the dummy should get removed
|
|
690
|
+
expect(flashList.findAll(Text).length).toBe(1);
|
|
691
|
+
|
|
692
|
+
flashList.unmount();
|
|
693
|
+
|
|
694
|
+
flashList = mountFlashList({
|
|
695
|
+
data: new Array(1).fill("1"),
|
|
696
|
+
horizontal: true,
|
|
697
|
+
disableHorizontalListHeightMeasurement: true,
|
|
698
|
+
});
|
|
699
|
+
// should contain 1 actual text as measurement is disabled
|
|
700
|
+
expect(flashList.findAll(Text).length).toBe(1);
|
|
701
|
+
flashList.unmount();
|
|
702
|
+
});
|
|
703
|
+
it("cancels post load setTimeout on unmount", () => {
|
|
704
|
+
const flashList = mountFlashList({
|
|
705
|
+
data: new Array(1).fill("1"),
|
|
706
|
+
horizontal: true,
|
|
707
|
+
});
|
|
708
|
+
const forceUpdate = jest.spyOn(flashList.instance, "forceUpdate");
|
|
709
|
+
flashList.instance["onItemLayout"](0);
|
|
710
|
+
flashList.unmount();
|
|
711
|
+
jest.advanceTimersByTime(600);
|
|
712
|
+
expect(forceUpdate).toBeCalledTimes(0);
|
|
713
|
+
});
|
|
714
|
+
it("uses 250 as draw distance on Android/iOS", () => {
|
|
715
|
+
const flashList = mountFlashList();
|
|
716
|
+
flashList.find(ProgressiveListView)?.instance.onItemLayout(0);
|
|
717
|
+
jest.advanceTimersByTime(1000);
|
|
718
|
+
expect(
|
|
719
|
+
flashList
|
|
720
|
+
.find(ProgressiveListView)
|
|
721
|
+
?.instance.getCurrentRenderAheadOffset()
|
|
722
|
+
).toBe(250);
|
|
723
|
+
flashList.unmount();
|
|
724
|
+
});
|
|
725
|
+
it("forwards correct renderTarget", () => {
|
|
726
|
+
const renderItem = ({ target }: ListRenderItemInfo<string>) => {
|
|
727
|
+
return <Text>{target}</Text>;
|
|
728
|
+
};
|
|
729
|
+
const flashList = mountFlashList({
|
|
730
|
+
data: ["0"],
|
|
731
|
+
stickyHeaderIndices: [0],
|
|
732
|
+
renderItem,
|
|
733
|
+
});
|
|
734
|
+
expect(flashList.find(Animated.View)?.find(Text)?.props.children).toBe(
|
|
735
|
+
RenderTargetOptions.StickyHeader
|
|
736
|
+
);
|
|
737
|
+
expect(flashList.find(View)?.find(Text)?.props.children).toBe(
|
|
738
|
+
RenderTargetOptions.Cell
|
|
739
|
+
);
|
|
740
|
+
const flashListHorizontal = mountFlashList({
|
|
741
|
+
renderItem,
|
|
742
|
+
horizontal: true,
|
|
743
|
+
});
|
|
744
|
+
expect(
|
|
745
|
+
flashListHorizontal
|
|
746
|
+
.findAllWhere((node: any) => node?.props?.style?.opacity === 0)[0]
|
|
747
|
+
.find(Text)?.props.children
|
|
748
|
+
).toBe("Measurement");
|
|
749
|
+
});
|
|
750
|
+
it("force updates items only when renderItem change", () => {
|
|
751
|
+
const renderItem = jest.fn(() => <Text>Test</Text>);
|
|
752
|
+
const flashList = mountFlashList({
|
|
753
|
+
data: new Array(1).fill("1"),
|
|
754
|
+
renderItem,
|
|
755
|
+
});
|
|
756
|
+
flashList.setProps({ data: new Array(1).fill("1") });
|
|
757
|
+
expect(renderItem).toBeCalledTimes(1);
|
|
758
|
+
const newRenderItem = jest.fn(() => <Text>Test</Text>);
|
|
759
|
+
flashList.setProps({
|
|
760
|
+
data: new Array(1).fill("1"),
|
|
761
|
+
renderItem: newRenderItem,
|
|
762
|
+
});
|
|
763
|
+
expect(newRenderItem).toBeCalledTimes(1);
|
|
764
|
+
});
|
|
765
|
+
it("forwards disableAutoLayout prop correctly", () => {
|
|
766
|
+
const flashList = mountFlashList();
|
|
767
|
+
expect(flashList.find(AutoLayoutView)?.props.disableAutoLayout).toBe(
|
|
768
|
+
undefined
|
|
769
|
+
);
|
|
770
|
+
flashList.setProps({ disableAutoLayout: true });
|
|
771
|
+
expect(flashList.find(AutoLayoutView)?.props.disableAutoLayout).toBe(true);
|
|
772
|
+
});
|
|
773
|
+
it("computes correct scrollTo offset when view position is specified", () => {
|
|
774
|
+
const flashList = mountFlashList({
|
|
775
|
+
data: new Array(40).fill(1).map((_, index) => {
|
|
776
|
+
return index.toString();
|
|
777
|
+
}),
|
|
778
|
+
});
|
|
779
|
+
const plv = flashList.find(ProgressiveListView)
|
|
780
|
+
?.instance as ProgressiveListView;
|
|
781
|
+
const scrollToOffset = jest.spyOn(plv, "scrollToOffset");
|
|
782
|
+
flashList.instance.scrollToIndex({ index: 10, viewPosition: 0.5 });
|
|
783
|
+
|
|
784
|
+
// Each item is 200px in height and to position it in the middle of the window (900 x 400), its offset needs to be
|
|
785
|
+
// reduced by 350px. That gives us 1650. Other test cases follow the same logic.
|
|
786
|
+
expect(scrollToOffset).toBeCalledWith(1650, 1650, false, true);
|
|
787
|
+
flashList.instance.scrollToItem({
|
|
788
|
+
item: "10",
|
|
789
|
+
viewPosition: 0.5,
|
|
790
|
+
});
|
|
791
|
+
expect(scrollToOffset).toBeCalledWith(1650, 1650, false, true);
|
|
792
|
+
flashList.setProps({ horizontal: true });
|
|
793
|
+
flashList.instance.scrollToItem({
|
|
794
|
+
item: "10",
|
|
795
|
+
viewPosition: 0.5,
|
|
796
|
+
});
|
|
797
|
+
expect(scrollToOffset).toBeCalledWith(1900, 1900, false, true);
|
|
798
|
+
flashList.unmount();
|
|
799
|
+
});
|
|
800
|
+
it("computes correct scrollTo offset when view offset is specified", () => {
|
|
801
|
+
const flashList = mountFlashList({
|
|
802
|
+
data: new Array(40).fill(1).map((_, index) => {
|
|
803
|
+
return index.toString();
|
|
804
|
+
}),
|
|
805
|
+
});
|
|
806
|
+
const plv = flashList.find(ProgressiveListView)
|
|
807
|
+
?.instance as ProgressiveListView;
|
|
808
|
+
const scrollToOffset = jest.spyOn(plv, "scrollToOffset");
|
|
809
|
+
|
|
810
|
+
// Each item is 200px in height and to position it in the middle of the window (900 x 400), it's offset needs to be
|
|
811
|
+
// reduced by 350px + 100px offset. That gives us 1550. Other test cases follow the same logic.
|
|
812
|
+
flashList.instance.scrollToIndex({
|
|
813
|
+
index: 10,
|
|
814
|
+
viewPosition: 0.5,
|
|
815
|
+
viewOffset: 100,
|
|
816
|
+
});
|
|
817
|
+
expect(scrollToOffset).toBeCalledWith(1550, 1550, false, true);
|
|
818
|
+
flashList.setProps({ horizontal: true });
|
|
819
|
+
flashList.instance.scrollToItem({
|
|
820
|
+
item: "10",
|
|
821
|
+
viewPosition: 0.5,
|
|
822
|
+
viewOffset: 100,
|
|
823
|
+
});
|
|
824
|
+
expect(scrollToOffset).toBeCalledWith(1800, 1800, false, true);
|
|
825
|
+
flashList.unmount();
|
|
826
|
+
});
|
|
827
|
+
it("applies horizontal content container padding for vertical list", () => {
|
|
828
|
+
const flashList = mountFlashList({
|
|
829
|
+
numColumns: 4,
|
|
830
|
+
contentContainerStyle: { paddingHorizontal: 10 },
|
|
831
|
+
});
|
|
832
|
+
let hasLayoutItems = false;
|
|
833
|
+
flashList.instance.state.layoutProvider
|
|
834
|
+
.getLayoutManager()!
|
|
835
|
+
.getLayouts()
|
|
836
|
+
.forEach((layout) => {
|
|
837
|
+
hasLayoutItems = true;
|
|
838
|
+
expect(layout.width).toBe(95);
|
|
839
|
+
});
|
|
840
|
+
expect(hasLayoutItems).toBe(true);
|
|
841
|
+
flashList.unmount();
|
|
842
|
+
});
|
|
843
|
+
it("applies vertical content container padding for horizontal list", () => {
|
|
844
|
+
const flashList = mountFlashList({
|
|
845
|
+
horizontal: true,
|
|
846
|
+
contentContainerStyle: { paddingVertical: 10 },
|
|
847
|
+
});
|
|
848
|
+
let hasLayoutItems = false;
|
|
849
|
+
flashList.instance.state.layoutProvider
|
|
850
|
+
.getLayoutManager()!
|
|
851
|
+
.getLayouts()
|
|
852
|
+
.forEach((layout) => {
|
|
853
|
+
hasLayoutItems = true;
|
|
854
|
+
expect(layout.height).toBe(880);
|
|
855
|
+
});
|
|
856
|
+
expect(hasLayoutItems).toBe(true);
|
|
857
|
+
flashList.unmount();
|
|
858
|
+
});
|
|
859
|
+
it("warns if rendered size is too small but only when it remain small for a duration", () => {
|
|
860
|
+
const flashList = mountFlashList({
|
|
861
|
+
data: new Array(1).fill("1"),
|
|
862
|
+
});
|
|
863
|
+
const warn = jest.spyOn(console, "warn").mockReturnValue();
|
|
864
|
+
|
|
865
|
+
const triggerLayout = (height: number, time: number) => {
|
|
866
|
+
flashList.find(ScrollView)?.trigger("onLayout", {
|
|
867
|
+
nativeEvent: { layout: { height, width: 900 } },
|
|
868
|
+
});
|
|
869
|
+
jest.advanceTimersByTime(time);
|
|
870
|
+
};
|
|
871
|
+
|
|
872
|
+
triggerLayout(0, 500);
|
|
873
|
+
triggerLayout(100, 1000);
|
|
874
|
+
triggerLayout(0, 1200);
|
|
875
|
+
|
|
876
|
+
expect(warn).toHaveBeenCalledTimes(1);
|
|
877
|
+
|
|
878
|
+
triggerLayout(100, 500);
|
|
879
|
+
triggerLayout(0, 500);
|
|
880
|
+
|
|
881
|
+
flashList.unmount();
|
|
882
|
+
jest.advanceTimersByTime(1200);
|
|
883
|
+
|
|
884
|
+
expect(warn).toHaveBeenCalledTimes(1);
|
|
885
|
+
});
|
|
886
|
+
});
|