import * as React from "react"; import { renderHook, render, act } from "@testing-library/react-native"; import { View } from "react-native"; import { useSequentialLoader, useSequentialRenderItem } from ".."; describe("flatList hooks", () => { describe("useSequentialRenderItem", () => { it("returns function and loading indicator ", () => { const mockData = [{ test: true }]; const { result } = renderHook(() => useSequentialRenderItem(mockData)); expect(typeof result.current.renderItem).toBe("function"); expect(typeof result.current.allLoaded).toBeTruthy(); }); it("returns works with empty data", () => { const mockData = []; const { result } = renderHook(() => useSequentialRenderItem(mockData)); expect(typeof result.current.renderItem).toBe("function"); expect(typeof result.current.allLoaded).toBeTruthy(); }); describe("Data passed to renderItem function", () => { it("passes correct item element over", () => { const element = { id: 1 }; const mockData = [element]; const { result } = renderHook(() => useSequentialRenderItem(mockData)); result.current.renderItem(({ item }) => { expect(item).toBe(element); }); }); it("passes onLoadFinished method to renderItem", () => { const element = { id: 1 }; const mockData = [element]; const { result } = renderHook(() => useSequentialRenderItem(mockData)); result.current.renderItem(({ onLoadFinished }) => { expect(onLoadFinished).toBeDefined(); }); }); }); describe("Calling onLoadFinished callback", () => { it("allLoaded return true after onLoadFinished is called for all components", () => { const element1 = { id: 1 }; const element2 = { id: 2 }; const mockData = [element1, element2]; const { result } = renderHook(() => useSequentialRenderItem(mockData)); expect(result.current.allLoaded).toBe(false); result.current.renderItem( ({ onLoadFinished }) => { onLoadFinished(); }, { index: 0 } ); expect(result.current.allLoaded).toBe(false); act(() => { result.current.renderItem( ({ onLoadFinished }) => { onLoadFinished(); }, { index: 1 } ); }); expect(result.current.allLoaded).toBe(true); }); }); describe("Rendering wrapper", () => { it("wraps the elements in the View with display: none style", async () => { const element1 = { id: 1 }; const element2 = { id: 2 }; const mockData = [element1, element2]; const { result } = renderHook(() => useSequentialRenderItem(mockData)); const res = render( result.current.renderItem( () => { return ; }, { item: element1 } ) ); const element = res.root.findByProps({ testID: "sequential-river-wrapper-1", }); expect(element.props.style.display).toEqual("none"); }); it("calling on LoadFinish flips the View style to flex", () => { const element1 = { id: 1 }; const element2 = { id: 2 }; const mockData = [element1, element2]; const { result } = renderHook(() => useSequentialRenderItem(mockData)); act(() => { result.current.renderItem( ({ onLoadFinished }) => { onLoadFinished(); }, { item: element1, index: 0 } ); }); const { root } = render( result.current.renderItem( ({ onLoadFinished }) => { onLoadFinished(); return ; }, { item: element1, index: 1 } ) ); const element = root.findByProps({ testID: "sequential-river-wrapper-1", }); expect(element.props.style.display).toEqual("flex"); }); it("View stays hidden if previous views are not loaded", () => { const element1 = { id: 1 }; const element2 = { id: 2 }; const mockData = [element1, element2]; const { result } = renderHook(() => useSequentialRenderItem(mockData)); const { root } = render( result.current.renderItem( ({ onLoadFinished }) => { onLoadFinished(); return ; }, { item: element1, index: 1 } ) ); const element = root.findByProps({ testID: "sequential-river-wrapper-1", }); expect(element.props.style.display).toEqual("none"); }); }); }); describe("useSequentialLoader", () => { it("returns correct elements", () => { const mockData = [{ test: true }]; const { result } = renderHook(() => useSequentialLoader(true, mockData.length) ); expect(typeof result.current.isReadyToRender).toBe("function"); expect(typeof result.current.onLoadFinished).toBe("function"); expect(typeof result.current.onViewableItemsChanged).toBe("function"); expect(typeof result.current.isRendered).toBe("function"); expect(typeof result.current.allLoaded).toBe("boolean"); }); }); describe("isReadyToRender", () => { const viewableMock = { viewableItems: [ { index: 0, item: 1, key: "1", isViewable: true }, { index: 1, item: 2, key: "2", isViewable: true }, ], changed: [], }; it("returns true when element is flagged as rendered", () => { const mockData = [1, 2]; const { result } = renderHook(() => useSequentialLoader(true, mockData.length) ); act(() => { result.current.onViewableItemsChanged(viewableMock); result.current.onLoadFinished(1)(); }); expect(result.current.isReadyToRender(1)).toBe(true); }); it("returns false when element is not flagged as rendered", () => { const mockData = [1, 2]; const { result } = renderHook(() => useSequentialLoader(true, mockData.length) ); act(() => { result.current.onViewableItemsChanged(viewableMock); }); expect(result.current.isReadyToRender(1)).toBe(false); }); it("always returns true for index 0", () => { const mockData = [1, 2]; const { result } = renderHook(() => useSequentialLoader(true, mockData.length) ); expect(result.current.isReadyToRender(0)).toBe(true); }); it("returns false if there are no viewable items", () => { const mockData = [1, 2]; const { result } = renderHook(() => useSequentialLoader(true, mockData.length) ); act(() => { result.current.onLoadFinished(1)(); }); expect(result.current.isReadyToRender(1)).toBe(false); }); it("returns true if it's in the viewport and previous element is loaded", () => { const mockData = [1, 2, 3]; const { result } = renderHook(() => useSequentialLoader(true, mockData.length) ); act(() => { result.current.onViewableItemsChanged(viewableMock); result.current.onLoadFinished(0)(); result.current.onLoadFinished(1)(); }); expect(result.current.isReadyToRender(2)).toBe(true); }); it("returns true if it's first, second or third component outside the viewport and previous element are loaded", () => { const mockData = [1, 2, 3, 4, 5]; const { result } = renderHook(() => useSequentialLoader(true, mockData.length) ); act(() => { result.current.onViewableItemsChanged(viewableMock); result.current.onLoadFinished(0)(); result.current.onLoadFinished(1)(); }); expect(result.current.isReadyToRender(2)).toBe(true); act(() => { result.current.onLoadFinished(2)(); }); expect(result.current.isReadyToRender(2)).toBe(true); act(() => { result.current.onLoadFinished(3)(); }); expect(result.current.isReadyToRender(3)).toBe(true); act(() => { result.current.onLoadFinished(4)(); }); expect(result.current.isReadyToRender(4)).toBe(true); expect(result.current.isReadyToRender(5)).toBe(false); }); describe("allLoaded", () => { it("returns true if onLoadFinished was called for all elements", () => { const mockData = [1, 2]; const { result } = renderHook(() => useSequentialLoader(true, mockData.length) ); act(() => { result.current.onLoadFinished(0)(); result.current.onLoadFinished(1)(); }); expect(result.current.allLoaded).toBe(true); }); it("returns true if onLoadFinished wasn't called for all elements", () => { const mockData = [1, 2]; const { result } = renderHook(() => useSequentialLoader(true, mockData.length) ); expect(result.current.allLoaded).toBe(false); }); }); describe("isRendered", () => { it("returns true if onLoadFinished was called for x element", () => { const mockData = [1, 2]; const { result } = renderHook(() => useSequentialLoader(true, mockData.length) ); act(() => { result.current.onLoadFinished(1)(); }); expect(result.current.isRendered(1)).toBe(true); }); it("returns true if onLoadFinished wasn't called for x element", () => { const mockData = [1, 2, 3]; const { result } = renderHook(() => useSequentialLoader(true, mockData.length) ); act(() => { result.current.onLoadFinished(1)(); }); expect(result.current.isRendered(2)).toBe(false); }); }); }); });