如何使用 jest.fn() 模拟调度

Рич*_*ман 2 javascript reactjs jestjs react-testing-library

例如,我想知道已经调度了什么以及参数。动作创建者是异步的,但我不关心它的实现,我只想知道组件是否使用正确的参数调度正确的动作创建者。我尝试过这种方法:

store.dispatch = jest.fn()
Run Code Online (Sandbox Code Playgroud)

但我无法获得任何有用的信息:

这是我可以从 store.dispatch.mock 得到的

我尝试通过这种方式解决问题:

expect(store.dispatch.mock.calls[0].toString()).toBe(requestArticles().toString())
Run Code Online (Sandbox Code Playgroud)

但我不知道这个论点,但我确信有更好的方法来做到这一点。另外值得注意的是,我正在使用react-testing-library,所以我不能使用wrapper.instance().propsEnzyme。

Sun*_*n34 8

这是一个对我有用的例子(2022):

(导航栏.test.js)

import store from "../../store/redux-store";
import { useDispatch, useSelector } from "react-redux";
import { Provider } from "react-redux";

import configureStore from "redux-mock-store";
import { render, screen, cleanup, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

import Navbar from "../navbar/Navbar";

describe("Navbar", () => {

  beforeEach(() => {
    // ! WE MAKE SURE THE MOCKS ARE CLEARED BEFORE EACH TEST CASE
    useSelectorMock.mockClear();
    useDispatchMock.mockClear();
  });

  afterAll(() => {
    cleanup();
  });

  // ! SETUP THE SPY ON USESELECTOR / USE DISPATCH
  // ! WE DO THIS TO BE ABLE TO CHECK IF THE DISPATCH MOCK GOT CALLED AND HOW MANY TIMES
  const reactRedux = { useDispatch, useSelector }
  const useDispatchMock = jest.spyOn(reactRedux, "useDispatch");
  const useSelectorMock = jest.spyOn(reactRedux, "useSelector");

[...]

  test("cliking the sign-out button should sign out user", async () => {
    const mockStore = configureStore();
    const initialState = {
      auth: {
        isAuthModalOpen: false,
        user: { id: 1, email: "test@test.com" },
        notification: null,
        isLoggedIn: true,
        token: "ABC123",
      },
    };
    let updatedStore = mockStore(initialState);

    const mockDispatch = jest.fn();
    useDispatchMock.mockReturnValue(mockDispatch);
    updatedStore.dispatch = mockDispatch;
    // ? HERE THE INITIAL CONTENT OF THE MOCK
    // console.log(updatedStore.dispatch.mock);


    render(<Provider store={updatedStore}><Navbar /></Provider>);
    const signOutBtn = screen.getByTestId("button-sign-out");
    expect(signOutBtn).toBeInTheDocument();

    expect(updatedStore.dispatch).not.toHaveBeenCalled();
    userEvent.click(signOutBtn);
    // ? HERE THE CONTENT OF THE MOCK CHANGED
    // console.log(updatedStore.dispatch.mock);

    expect(updatedStore.dispatch).toHaveBeenCalledTimes(1);
    expect(updatedStore.dispatch.mock.lastCall[0].type).toMatch("destroySession");
    screen.debug()

    console.log(updatedStore.getActions());
  });
Run Code Online (Sandbox Code Playgroud)

请注意从react-redux 导入“useDispatch”的方式的差异。另外,请注意“mockDispatch”附加到“updatedStore.dispatch”的方式。

这两个改变使它对我有用。