Qroon

IntersectionObserverを使用したコードをvitestでテスト

2025/03/07

    IntersectionObserverを使用したコードをvitestでテストする方法を検討しました。
    考え方としては、スクロールをシミュレーションするのではなく、new IntersectionObserver で指定したコールバック関数を発火させることでテストします。

    import { Mock } from "vitest";
    import { act, render, screen } from "@testing-library/react";
    
    describe("ImageList", () => {
      let mocObserve: Mock;
      let mocDisconnect: Mock;
      let IntersectionObserverMock: Mock<
        [cb: IntersectionObserverCallback],
        {
          disconnect: Mock;
          observe: Mock;
          trigger: (opt: { isIntersecting: boolean }[]) => void;
        }
      >;
    
      beforeAll(() => {
        IntersectionObserverMock = vi.fn((cb) => ({
          disconnect: (mocDisconnect = vi.fn()),
          observe: (mocObserve = vi.fn()),
          trigger: (opt: { isIntersecting: boolean }[]) => {
            cb(
              opt as IntersectionObserverEntry[],
              {
                disconnect: (mocDisconnect = vi.fn()),
              } as unknown as IntersectionObserver
            );
          },
        }));
    
        vi.stubGlobal("IntersectionObserver", IntersectionObserverMock);
      });
    
      afterEach(() => {
        vi.clearAllMocks();
      });
    
      test("should get more images when scrolling to the bottom", async () => {
        render(<SampleComponent />);
    
        expect(mocObserve).toHaveBeenCalledOnce();
    
        const obs = IntersectionObserverMock.mock.results[0];
    
        act(() => {
          obs.value.trigger([{ isIntersecting: true }]);
        });
    
            // some test
    
        expect(mocDisconnect).toHaveBeenCalledOnce();
      });
    });