React 單元測試寫法範例 — 如何正確等待 element 觸發 / 渲染

教你寫如何正確等待「元素」來測試


重點

  • 組件用 findByOOO 來 await 等待。
  • 判斷(expect) 才用 waitFor 來 await 等待。

實作

  • 核心用法大致如下

    // 先用 await findByOOO 拿到需要互動的組件 const joinButton = await screen.findByTestId("join-button"); // await 完確認拿到之後,再去做互動、檢查...等 userEvent.click(joinButton); // 驗證測項,把 expect 裡面的 callback 呼叫後 return 出來即可 await waitFor(() => ( expect(...).toEqual(...) ))
  • 以下為完整測試案例的範例

    it("Join should be called.", () => { const spyJoin = jest.spyOn(Repository.prototype, "join").mockResolvedValue({} as any); // given given_some_api(data); await when_render(); // when userEvent.click(screen.getByTestId("confirm-button")); // 這個是需要等待狀態變化才抓得到的組件 const joinButton = await screen.findByTestId("join-button"); userEvent.click(joinButton); // then const request: Request = { id: 1, name: 'hi' }; await waitFor(() => ( expect(spyJoin).toHaveBeenCalledWith(request) )); await waitFor(() => { expect(screen.getByText("Join Successfully")).toBeInTheDocument(); }); })

容易搞混的誤區

  • waitFor 搭配需等待 element 的行為觸發 >> 這次就是卡在這個坑,讓測試時好時壞。推測是因為這個寫法做測試的組件等待順序不穩定,在測試資源不足的情況下,特別容易出錯(不定時出錯)

    // ❌ await waitFor(() => { userEvent.click(...) }) // ✅ const el = await screen.findByOOO(); userEvent.click(el);

REF