use-page-window.test.tsx3.1 KBView on GitHub
import { act, renderHook } from '@testing-library/react';
import { usePageWindow } from '@/modules/threads/threadList/hooks/use-page-window';

describe('usePageWindow', () => {
  it('starts at index 0', () => {
    const { result } = renderHook(() =>
      usePageWindow({
        pageCount: 1,
        hasNextPage: false,
        isFetchingNextPage: false,
        fetchNextPage: jest.fn(),
      }),
    );
    expect(result.current.pageIndex).toBe(0);
    expect(result.current.canPrev).toBe(false);
  });

  it('goPrev is a no-op at index 0', () => {
    const { result } = renderHook(() =>
      usePageWindow({
        pageCount: 1,
        hasNextPage: false,
        isFetchingNextPage: false,
        fetchNextPage: jest.fn(),
      }),
    );
    act(() => {
      result.current.goPrev();
    });
    expect(result.current.pageIndex).toBe(0);
  });

  it('disables canNext when at last page and no more', () => {
    const { result } = renderHook(() =>
      usePageWindow({
        pageCount: 1,
        hasNextPage: false,
        isFetchingNextPage: false,
        fetchNextPage: jest.fn(),
      }),
    );
    expect(result.current.canNext).toBe(false);
  });

  it('advances within cached pages without fetching', async () => {
    const fetchNextPage = jest.fn().mockResolvedValue(undefined);
    const { result } = renderHook(() =>
      usePageWindow({
        pageCount: 3,
        hasNextPage: true,
        isFetchingNextPage: false,
        fetchNextPage,
      }),
    );
    await act(async () => {
      await result.current.goNext();
    });
    expect(result.current.pageIndex).toBe(1);
    expect(fetchNextPage).not.toHaveBeenCalled();
  });

  it('fetches when stepping past last cached page', async () => {
    const fetchNextPage = jest.fn().mockResolvedValue(undefined);
    const { result } = renderHook(() =>
      usePageWindow({
        pageCount: 1,
        hasNextPage: true,
        isFetchingNextPage: false,
        fetchNextPage,
      }),
    );
    await act(async () => {
      await result.current.goNext();
    });
    expect(fetchNextPage).toHaveBeenCalledTimes(1);
    expect(result.current.pageIndex).toBe(1);
  });

  it('goPrev decrements after a goNext', async () => {
    const fetchNextPage = jest.fn().mockResolvedValue(undefined);
    const { result } = renderHook(() =>
      usePageWindow({
        pageCount: 2,
        hasNextPage: false,
        isFetchingNextPage: false,
        fetchNextPage,
      }),
    );
    await act(async () => {
      await result.current.goNext();
    });
    expect(result.current.pageIndex).toBe(1);
    act(() => {
      result.current.goPrev();
    });
    expect(result.current.pageIndex).toBe(0);
  });

  it('does nothing while a fetch is in flight', async () => {
    const fetchNextPage = jest.fn().mockResolvedValue(undefined);
    const { result } = renderHook(() =>
      usePageWindow({
        pageCount: 1,
        hasNextPage: true,
        isFetchingNextPage: true,
        fetchNextPage,
      }),
    );
    await act(async () => {
      await result.current.goNext();
    });
    expect(fetchNextPage).not.toHaveBeenCalled();
    expect(result.current.pageIndex).toBe(0);
  });
});