iT邦幫忙

2023 iThome 鐵人賽

DAY 29
0

我們主要就測兩個功能:

  1. initial render有正確呼叫useEffect call api
  2. intersection 有讓PostId增加一

一開始,一樣先做假的intersection替代global環境真實的Intersection

const mockCallbacks: IntersectionObserverCallback[] = [];

class MockIntersectionObserver implements IntersectionObserver {
  readonly root: Element | null = null;
  readonly rootMargin: string = "";
  readonly thresholds: ReadonlyArray<number> = [];

  constructor(callback: IntersectionObserverCallback) {
    mockCallbacks.push(callback);
  }

  observe(target: Element): void {}
  unobserve(target: Element): void {}
  disconnect(): void {}
  takeRecords(): IntersectionObserverEntry[] {
    return [];
  }
}

(global as any).IntersectionObserver = MockIntersectionObserver;

為了測試方便,我有回傳出了postId

return { loading, comments, intersectioningRef, postId };

剩下的就跟以前一樣,用mock做假資料,使用renderHook, act, waitFor這三個最主要的方法去做測試

import { renderHook, act, waitFor } from "@testing-library/react";
import MockAdapter from "axios-mock-adapter";
import axios from "axios";
import useGetComments from "./useGetComments";

const mockCallbacks: IntersectionObserverCallback[] = [];

class MockIntersectionObserver implements IntersectionObserver {
  readonly root: Element | null = null;
  readonly rootMargin: string = "";
  readonly thresholds: ReadonlyArray<number> = [];

  constructor(callback: IntersectionObserverCallback) {
    mockCallbacks.push(callback);
  }

  observe(target: Element): void {}
  unobserve(target: Element): void {}
  disconnect(): void {}
  takeRecords(): IntersectionObserverEntry[] {
    return [];
  }
}

(global as any).IntersectionObserver = MockIntersectionObserver;

// This sets up the mock adapter on the default instance
const mock = new MockAdapter(axios);

describe("useGetComments", () => {
  afterEach(() => {
    mock.reset();
  });

  it("should fetch comments on initial render", async () => {
    const { result } = renderHook(() => useGetComments());

    const mockData = [
      {
        postId: 1,
        id: 1,
        name: "Comment 1",
        email: "test1@example.com",
        body: "Body 1",
      },
      // ... other mock comments
    ];

    mock
      .onGet("https://jsonplaceholder.typicode.com/comments?postId=1")
      .reply(200, mockData);

    expect(result.current.loading).toBe(true);

    waitFor(() => {
      expect(result.current.comments).toEqual(mockData);
      expect(result.current.loading).toBe(false);
    });
  });

  it("should increment postId when an element intersects", async () => {
    const { result } = renderHook(() => useGetComments());

    // 使用 act 來模擬交互事件
    act(() => {
      if (mockCallbacks.length > 0) {
        mockCallbacks[0](
          [{ isIntersecting: true } as IntersectionObserverEntry],
          {} as IntersectionObserver
        );
      }
    });
    waitFor(() => {
      expect(result.current.postId).toBe(2);
    });
  });
 
});

上一篇
[Day 28] useIntersection實戰 做出infinite scroll吧
下一篇
[Day 30] 懶得每次都npm test,用Husky幫忙吧 && 結語
系列文
React進階班,用typescript與jest製作自己的custom hooks庫30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言