簡體   English   中英

如何用 jest 和 react-testing-library 測試 react-toastify

[英]How to test react-toastify with jest and react-testing-library

我有一個帶有某種形式的屏幕,在提交時,我使用 axios 將請求發送到后端。 成功收到響應后,我用 react-toastify 展示了一個 toast。 非常直接的屏幕。 但是,當我嘗試使用 jest 和 react 測試庫的集成測試來測試這種行為時,我似乎無法讓 toast 出現在 DOM 上。

我有一個像這樣的實用程序渲染器來渲染我正在使用 toast 容器測試的組件:

import {render} from "@testing-library/react";
import React from "react";
import {ToastContainer} from "react-toastify";

export const renderWithToastify = (component) => (
  render(
    <div>
      {component}
      <ToastContainer/>
    </div>
  )
);

在測試本身中,我使用 react-testing-library 填寫表單,按下提交按鈕,然后等待 toast 出現。 我正在使用模擬服務人員來模擬響應。 我確認響應返回正常,但由於某種原因,toast 拒絕出現。 我目前的測試如下:

expect(await screen.findByRole("alert")).toBeInTheDocument();

我正在尋找具有角色警報的元素。 但這似乎行不通。 另外,我嘗試做這樣的事情:

...

beforeAll(() => {
  jest.useFakeTimers();
}

...

it("test", () => {
  ...

  act(() =>
    jest.runAllTimers();
  )
  expect(await screen.findByRole("alert")).toBeInTheDocument();
}

我對 JS 有點陌生,問題可能是由於 axios 和 react-toastify 的異步性質,但我不知道如何測試這種行為。 我嘗試了很多東西,包括 mocking 定時器和運行它們,mocking 定時器和推進它們,而不是 mocking 它們和等待等。我什至試圖讓它正常工作,但我無法正常工作。 加上這似乎是一個實現細節,所以我認為我不應該是 mocking 。

我認為問題是我在 axios promise 解決之后顯示吐司,所以計時器不知何故感到困惑。

我試圖搜索很多地方,但未能找到答案。

提前致謝。

謝謝@Estus Flask,但問題要愚蠢得多:) 我必須在我的組件之前渲染 ToastContainer,如下所示:

import {render} from "@testing-library/react";
import React from "react";
import {ToastContainer} from "react-toastify";

export const renderWithToastify = (component) => {
  return (
    render(
      <div>
        <ToastContainer/>
        {component}
      </div>
    )
  );
};

然后,測試很簡單,我只需要等待 toast 的標題:

expect(await screen.findByText("alert text")).toBeInTheDocument();

findByRole 似乎由於某種原因不起作用,但我太累了,無法深入挖掘:) 我不必使用任何假計時器或刷新承諾。 顯然,當您使用 await 和 finBy* 查詢時,RTL 已經執行了這些操作,只是渲染順序是錯誤的。

我要做的是從react-toastify模擬該方法以監視該方法以查看調用它的內容,而不是屏幕上出現的實際組件:

// setupTests.js
jest.mock('react-toastify', () => {
  const actual = jest.requireActual('react-toastify');
  Object.assign(actual, {toast: jest.fn()});
  return actual;
});

然后在實際測試中:

// test.spec.js
import {toast} from 'react-toastify';

const toastCalls = []
const spy = toast.mockImplementation((...args) => {
     toastCalls.push(args)
  }
)

describe('...', () => {
  it('should ...', () => {
    // do something that calls the toast
    ...
    // then
    expect(toastCalls).toEqual(...)
   }
 }
)


另一個建議是將這個mockImplementation放入一個單獨的輔助函數中,您可以輕松調用您需要的測試。 這是一種熊骨方法


function startMonitoring() {
  const monitor = {toast: [], log: [], api: [], navigation: []};

  toast.mockImplementation((...args) => {
    monitor.toast.push(args);
  });
  log.mockImplementation((...args) => {
    monitor.log.push(args);
  });
  api.mockImplementation((...args) => {
    monitor.api.push(args);
  });
  navigation.mockImplementation((...args) => {
    monitor.navigation.push(args);
  });
  return () => monitor;
}

it('should...', () => {
  const getSpyCalls = startMonitoring();
  // do something

  expect(getSpyCalls()).toEqual({
    toast: [...],
    log: [...],
    api: [...],
    navigation: [...]
  });
});

在這里,解決方案是使用 getByText:

await waitFor(() => {
  expect(screen.getByText(/Logged!/i)).toBeTruthy()
})

為了在您無權訪問 DOM 時使用模擬(如 Redux 副作用),您可以執行以下操作:

import { toast } from 'react-toastify'

jest.mock('react-toastify', () => ({
  toast: {
    success: jest.fn(),
  },
}))
expect(toast.success).toHaveBeenCalled()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM