import { afterEach, it, expect, describe, vitest } from "vitest"; import { render, cleanup } from "@testing-library/react"; import { WindowVirtualizer } from "./WindowVirtualizer"; import { Profiler, ReactElement, forwardRef, useEffect, useState } from "react"; import { CustomItemComponentProps } from "./types"; import { setupJsDomEnv } from "../../scripts/spec"; setupJsDomEnv({ itemWidth: 100, itemHeight: 50, }); afterEach(cleanup); it("should pass index to items", () => { const Item = forwardRef( ({ index, ...rest }, ref) => { return (
); } ); const { asFragment } = render(
0
1
2
3
4
); expect(asFragment()).toMatchSnapshot(); }); it("should render with render prop", () => { const items = Array.from({ length: 1000 }).map((_, i) => ({ id: i, label: "This is " + i, })); const { asFragment } = render( {(i) => { const item = items[i]!; return
{item.label}
; }}
); expect(asFragment()).toMatchSnapshot(); }); describe("vertical", () => { it("should render 1 children", () => { const { asFragment } = render(
0
); expect(asFragment()).toMatchSnapshot(); }); it("should render 5 children", () => { const { asFragment } = render(
0
1
2
3
4
); expect(asFragment()).toMatchSnapshot(); }); it("should render 100 children", () => { const { asFragment } = render( {Array.from({ length: 100 }).map((_, i) => (
{i}
))}
); expect(asFragment()).toMatchSnapshot(); }); it("should render 1000 children", () => { const { asFragment } = render( {Array.from({ length: 1000 }).map((_, i) => (
{i}
))}
); expect(asFragment()).toMatchSnapshot(); }); it("should render 10000 children", () => { const { asFragment } = render( {Array.from({ length: 10000 }).map((_, i) => (
{i}
))}
); expect(asFragment()).toMatchSnapshot(); }); it("should render non elements", () => { const { asFragment } = render( string {true} {false} {null} {undefined} {123} ); expect(asFragment()).toMatchSnapshot(); }); it("should render fragments", () => { const { asFragment } = render( <>
fragment
fragment
fragment
<>
fragment
); expect(asFragment()).toMatchSnapshot(); }); it("should render component", () => { const Comp = ({ children }: { children: React.ReactNode }) => (
{children}
); const { asFragment } = render( component component component ); expect(asFragment()).toMatchSnapshot(); }); it("should render with given width / height", () => { const { asFragment } = render(
0
1
2
3
4
); expect(asFragment()).toMatchSnapshot(); }); }); describe("horizontal", () => { it("should render 1 children", () => { const { asFragment } = render(
0
); expect(asFragment()).toMatchSnapshot(); }); it("should render 5 children", () => { const { asFragment } = render(
0
1
2
3
4
); expect(asFragment()).toMatchSnapshot(); }); it("should render 100 children", () => { const { asFragment } = render( {Array.from({ length: 100 }).map((_, i) => (
{i}
))}
); expect(asFragment()).toMatchSnapshot(); }); it("should render 1000 children", () => { const { asFragment } = render( {Array.from({ length: 1000 }).map((_, i) => (
{i}
))}
); expect(asFragment()).toMatchSnapshot(); }); it("should render 10000 children", () => { const { asFragment } = render( {Array.from({ length: 10000 }).map((_, i) => (
{i}
))}
); expect(asFragment()).toMatchSnapshot(); }); it("should render non elements", () => { const { asFragment } = render( string {true} {false} {null} {undefined} {123} ); expect(asFragment()).toMatchSnapshot(); }); it("should render fragments", () => { const { asFragment } = render( <>
fragment
fragment
fragment
<>
fragment
); expect(asFragment()).toMatchSnapshot(); }); it("should render component", () => { const Comp = ({ children }: { children: React.ReactNode }) => (
{children}
); const { asFragment } = render( component component component ); expect(asFragment()).toMatchSnapshot(); }); it("should render with given width / height", () => { const { asFragment } = render(
0
1
2
3
4
); expect(asFragment()).toMatchSnapshot(); }); }); describe("render count", () => { it("should render on mount", () => { const rootFn = vitest.fn(); const itemCount = 4; const itemFns = Array.from({ length: itemCount }, (_) => vitest.fn()); render( {Array.from({ length: itemCount }, (_, i) => { const key = `item-${i}`; return (
{i}
); })}
); expect(rootFn).toBeCalledTimes(2); itemFns.forEach((itemFn) => { expect(itemFn).toHaveBeenCalledTimes(1); }); }); it("should render on mount many items", () => { const rootFn = vitest.fn(); const itemCount = 100; const itemFns = Array.from({ length: itemCount }, (_) => vitest.fn()); render( {Array.from({ length: itemCount }, (_, i) => { const key = `item-${i}`; return (
{i}
); })}
); expect(rootFn).toBeCalledTimes(3); itemFns.forEach((itemFn) => { expect(itemFn.mock.calls.length).toBeLessThanOrEqual(1); }); }); it("should render on length change", () => { let ready = false; const wrap = (f: (...args: any[]) => void) => { return (...args: any[]) => { if (!ready) return; f(...args); }; }; const rootFn = vitest.fn(); const itemCount = 4; const itemFns = Array.from({ length: itemCount }, (_) => vitest.fn()); const Mounter = ({ children, count: initialCount, }: { children: (count: number) => ReactElement; count: number; }): ReactElement => { const [count, setCount] = useState(initialCount); useEffect(() => { ready = true; setCount((prev) => { return prev - 1; }); }, []); return children(count); }; render( {(count) => ( {Array.from({ length: count }, (_, i) => { const key = `item-${i}`; return (
{i}
); })}
)}
); expect(rootFn).toBeCalledTimes(2); itemFns.forEach((itemFn, i) => { expect(itemFn).toBeCalledTimes(i === itemFns.length - 1 ? 0 : 1); }); }); it("should render on length change many items", () => { let ready = false; const wrap = (f: (...args: any[]) => void) => { return (...args: any[]) => { if (!ready) return; f(...args); }; }; const rootFn = vitest.fn(); const itemCount = 100; const itemFns = Array.from({ length: itemCount }, (_) => vitest.fn()); const Mounter = ({ children, count: initialCount, }: { children: (count: number) => ReactElement; count: number; }): ReactElement => { const [count, setCount] = useState(initialCount); useEffect(() => { ready = true; setCount((prev) => { return prev - 1; }); }, []); return children(count); }; render( {(count) => ( {Array.from({ length: count }, (_, i) => { const key = `item-${i}`; return (
{i}
); })}
)}
); expect(rootFn).toBeCalledTimes(3); itemFns.forEach((itemFn) => { expect(itemFn.mock.calls.length).toBeLessThanOrEqual(2); // TODO: should be 1 }); }); });