123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- import {reactHooks, waitFor} from 'sentry-test/reactTestingLibrary';
- import {useVirtualizedTree} from 'sentry/utils/profiling/hooks/useVirtualizedTree/useVirtualizedTree';
- const n = d => {
- return {...d, children: []};
- };
- // Creates a tree with N nodes where each node has only one child
- const chain = (prefix: string, depth: number) => {
- let node = n({id: `${prefix}-0`});
- let start = 1;
- // Keep a root reference so we can return it
- const root = node;
- // Build a tree of nodes with each node having only one child
- while (start < depth) {
- const child = n({id: `${prefix}-${start}`});
- node.children = [child];
- // Swap the current node
- node = child;
- start++;
- }
- return root;
- };
- class ResizeObserver {
- observe() {}
- unobserve() {}
- disconnect() {}
- }
- window.ResizeObserver = ResizeObserver;
- window.requestAnimationFrame = (cb: Function) => cb();
- const makeScrollContainerMock = ({height}: {height: number}) => {
- return {
- getBoundingClientRect: () => {
- return {height};
- },
- addEventListener: () => {},
- removeEventListener: () => {},
- } as unknown as HTMLElement;
- };
- describe('useVirtualizedTree', () => {
- it('returns a tree', () => {
- const results = reactHooks.renderHook(() =>
- useVirtualizedTree({
- overscroll: 0,
- rowHeight: 10,
- tree: [],
- scrollContainer: null,
- renderRow: () => <div />,
- })
- );
- expect(results.result.current.items).toEqual([]);
- });
- it('shows first 10 items', () => {
- const mockScrollContainer = makeScrollContainerMock({height: 100});
- const tree = [chain('child', 10)];
- const {result} = reactHooks.renderHook(() =>
- useVirtualizedTree({
- rowHeight: 10,
- scrollContainer: mockScrollContainer,
- overscroll: 0,
- tree,
- renderRow: () => <div />,
- })
- );
- reactHooks.act(() => {
- result.current.handleExpandTreeNode(result.current.tree.roots[0], {
- expandChildren: true,
- });
- });
- for (let i = 0; i < 10; i++) {
- expect(result.current.items[i].item.node.id).toEqual(`child-${i}`);
- }
- expect(result.current.items.length).toBe(10);
- });
- it('shows 5-15 items', async () => {
- const mockScrollContainer = makeScrollContainerMock({height: 100});
- const tree = [chain('child', 20)];
- const {result} = reactHooks.renderHook(() =>
- useVirtualizedTree({
- rowHeight: 10,
- scrollContainer: mockScrollContainer,
- overscroll: 0,
- tree,
- renderRow: () => <div />,
- })
- );
- reactHooks.act(() => {
- result.current.handleExpandTreeNode(result.current.tree.roots[0], {
- expandChildren: true,
- });
- result.current.dispatch({type: 'set scroll top', payload: 50});
- });
- await waitFor(() => {
- expect(result.current.items.length).toBe(10);
- });
- for (let i = 0; i < 10; i++) {
- expect(result.current.items[i].item.node.id).toEqual(`child-${i + 5}`);
- }
- expect(result.current.items.length).toBe(10);
- });
- it('shows last 10 items', async () => {
- const mockScrollContainer = makeScrollContainerMock({height: 100});
- const tree = [chain('child', 20)];
- const {result} = reactHooks.renderHook(() =>
- useVirtualizedTree({
- rowHeight: 10,
- scrollContainer: mockScrollContainer,
- overscroll: 0,
- tree,
- renderRow: () => <div />,
- })
- );
- reactHooks.act(() => {
- result.current.handleExpandTreeNode(result.current.tree.roots[0], {
- expandChildren: true,
- });
- result.current.dispatch({type: 'set scroll top', payload: 100});
- });
- await waitFor(() => {
- expect(result.current.items.length).toBe(10);
- });
- for (let i = 0; i < 10; i++) {
- expect(result.current.items[i].item.node.id).toEqual(`child-${i + 10}`);
- }
- expect(result.current.items.length).toBe(10);
- });
- it('shows overscroll items', () => {
- const mockScrollContainer = makeScrollContainerMock({height: 100});
- const tree = [chain('child', 20)];
- const {result} = reactHooks.renderHook(() =>
- useVirtualizedTree({
- rowHeight: 10,
- scrollContainer: mockScrollContainer,
- overscroll: 2,
- tree,
- renderRow: () => <div />,
- })
- );
- reactHooks.act(() => {
- result.current.handleExpandTreeNode(result.current.tree.roots[0], {
- expandChildren: true,
- });
- result.current.dispatch({type: 'set scroll top', payload: 50});
- });
- for (let i = 3; i < 17; i++) {
- // Should display nodes 5-15, but since we use overscroll, it should display nodes 3-17
- expect(result.current.items[i - 3].item.node.id).toEqual(`child-${i}`);
- }
- expect(result.current.items.length).toBe(14);
- });
- it('items have a stable key', () => {
- const mockScrollContainer = makeScrollContainerMock({height: 100});
- const tree = [chain('child', 20)];
- const {result} = reactHooks.renderHook(() =>
- useVirtualizedTree({
- rowHeight: 10,
- scrollContainer: mockScrollContainer,
- overscroll: 0,
- tree,
- renderRow: () => <div />,
- })
- );
- reactHooks.act(() => {
- result.current.handleExpandTreeNode(result.current.tree.roots[0], {
- expandChildren: true,
- });
- result.current.dispatch({type: 'set scroll top', payload: 50});
- });
- const stableKeys = result.current.items.map(item => item.key);
- reactHooks.act(() => {
- result.current.dispatch({type: 'set scroll top', payload: 60});
- });
- // First 9 items should be the same, the last item should be different
- for (let i = 1; i < stableKeys.length; i++) {
- expect(stableKeys[i]).toBe(result.current.items[i - 1].key);
- }
- // Last item should be different
- expect(result.current.items[result.current.items.length - 1].key).toBe(
- stableKeys[stableKeys.length - 1] + 1
- );
- });
- });
|