嘲笑 zustand 商店进行玩笑测试

noo*_*oob 10 reactjs jestjs zustand

嘿,也许有人可以帮我解决这个问题?我尝试使用自定义值和操作来模拟 zustand 商店。我想在我的测试文件中进行模拟。但我却惨遭失败。

这是我的反应应用程序的简化示例。

组件.jsx

import React from "react";
import useStore from "@app/component_store";

export default function Component() {
  const foo = useStore((state) => state.foo);
  const setFoo = useStore((state) => state.foo_set);

  return (
    <>
      <div data-testid="foo">{foo}</div>

      <button data-testid="btn-foo" onClick={() => setFoo("new foo")}>
        set foo
      </button>
    </>
  );
}
Run Code Online (Sandbox Code Playgroud)

组件存储.jsx

import create from "zustand";

const useStore = create((set) => ({
  foo: "foo",
  foo_set: (value) => set(() => ({ foo: value })),
}));
export default useStore;
Run Code Online (Sandbox Code Playgroud)

组件.test.jsx

/* global  afterEach, expect, jest, test  */
import React from "react";
import { cleanup, fireEvent, render } from "@testing-library/react";
import "@testing-library/jest-dom";
import mockCreate from "zustand";

import Component from "@app/component";

jest.mock("@app/component_store", () => (args) => {
  const useStore = mockCreate((set, get) => ({
    foo: "mocked foo",
    foo_set: (value) => set(() => ({ foo: "mocked set foo" })),
  }));
  return useStore(args);
});

afterEach(cleanup);

test("override store values and actions", () => {
  const { container, getByTestId } = render(<Component />);

  const foo = getByTestId("foo");
  const btnFoo = getByTestId("btn-foo");

  expect(foo.textContent).toBe("mocked foo");

  fireEvent.click(btnFoo);
  expect(foo.textContent).toBe("mocked set foo");
});
Run Code Online (Sandbox Code Playgroud)

这失败了。expect(foo.textContent).toBe("mocked set foo");仍然会有“mocked foo”作为值,尽管模拟foo_set被调用(例如添加控制台日志确实被记录)。但同样, 的值foo不会更新。

但是,如果我将商店模拟部分移到自己的文件中并将其导入到我的测试中,一切都会按预期工作。

component_store_mocked.jsx

注意:这与 component.test.jsx 中的相同

import create from "zustand";

const useStore = create((set, get) => ({
  foo: "mocked foo",
  foo_set: (value) => set(() => ({ foo: "mocked set foo" })),
}));
export default useStore;
Run Code Online (Sandbox Code Playgroud)

更新了component.test.jsx

/* global  afterEach, expect, jest, test  */
import React from "react";
import { cleanup, fireEvent, render } from "@testing-library/react";
import "@testing-library/jest-dom";
import mockCreate from "zustand";

import Component from "@app/component";

// this part here
import mockComponentStore from "@app/component_store_mocked";

jest.mock("@app/component_store", () => (args) => {
  const useStore = mockComponentStore;
  return useStore(args);
});

afterEach(cleanup);

test("override store values and actions", () => {
  const { container, getByTestId } = render(<Component />);

  const foo = getByTestId("foo");
  const btnFoo = getByTestId("btn-foo");

  expect(foo.textContent).toBe("mocked foo");

  fireEvent.click(btnFoo);
  expect(foo.textContent).toBe("mocked set foo");
});
Run Code Online (Sandbox Code Playgroud)

我很乐意在测试文件中进行模拟,而不是用数十个模拟商店来污染我的系统进行测试......同样,这只是一个更大的应用程序的简化设置。

小智 0

我有同样的问题,我是这样解决的:

我正在使用 React Native,因此我插入了 Zustand 的模拟来重置每个测试的状态。https://docs.pmnd.rs/zustand/guides/testing

我在存储中创建了一个名为 _mock 的操作,它接收一个对象并将其插入到存储中。

模拟动作:

_mock(store) {
  set({
    state: { ...get().state, ...store },
    actions: get().actions,
 });
},
Run Code Online (Sandbox Code Playgroud)

模拟动作类型:

_mock: (store: Partial<RootStateAuth>) => void;
Run Code Online (Sandbox Code Playgroud)

用法:

useAuthStore.getState().actions._mock({
  role: 'purchases',
  registrationCompleted: false,
  name: 'Fulano',
});
Run Code Online (Sandbox Code Playgroud)

我希望它有帮助。