使用预加载状态在 React 中进行测试:在函数中手动导入存储时,redux 存储不同步

Testing in React with preloadedState: redux store gets out of sync when having a manual import of store in a function

我正在使用 react-testing-library 和 jest 为 React 编写测试,在弄清楚如何为我的 redux 商店设置 preloadedState 时遇到了一些问题,当另一个文件导入商店时。

我有一个功能可以像这样设置我的商店

store.ts

  export const history = createBrowserHistory()
  export const makeStore = (initalState?: any) => configureStore({
    reducer: createRootReducer(history),
    preloadedState: initalState
  })
  export const store = makeStore()

还有一个这样的 js 文件

utils.ts

  import store from 'state/store'
  const userIsDefined = () => {
    const state = store.getState()
    if (state.user === undefined) return false
    ...
    return true
  }

然后我有一个看起来像这样的测试:

utils.test.tsx(renderWithProvider 基本上是一个渲染函数,它也将我的组件包装在一个渲染组件中,参见:https://redux.js.org/recipes/writing-tests#connected-components

  describe("Test", () => {
    it("Runs the function when user is defined", async () => {
      const store = makeStore({ user: { id_token: '1' } })
      const { container } = renderWithProvider(
        <SomeComponent></SomeComponent>,
        store
      );
    })
  })

依次调用 utils.ts

中的函数

SomeComponent.tsx

  const SomeComponent = () => {
    if (userIsDefined() === false) return (<Forbidden/>)
    ...
  }

现在..测试的时候会发生什么运行好像是这样的

  1. utils.ts 被读取并读取行 import store from 'state/store',这将创建并保存一个存储尚未定义用户的变量。
  2. utils.test.tsx 被调用并且 运行 调用 const store = makeStore({ user: { id_token: '1' } }).
  3. renderWithProvider() 渲染 SomeComponent 进而调用 userIsDefined 函数。
  4. if (state.user === undefined) returns false because state.user仍然未定义,我认为那是因为 utils.ts 在我调用自己的 makeStore({ user: { id_token: '1' } })?

我想要的答案: 我想确保当再次调用 makeStore() 时,它会更新先前导入的商店版本,该版本正在 utils.ts 中使用。有没有一种方法可以做到这一点而不必使用 useSelector() 并将用户值从组件传递到我的 utils 函数?

例如我可以做这样的事情,但我宁愿不这样做,因为我有更多这些文件和函数,并且非常依赖 import store from 'state/store':

SomeComponent.tsx

  const SomeComponent = () => {
    const user = useSelector((state: IState) => state.user)
    if (userIsDefined(user) === false) return (<Forbidden/>)
    ...
  }

utils.ts

  //import store from 'state/store'
  const userIsDefined = (user) => {
    //const state = store.getState()
    if (user === undefined) return false
    ...
    return true
  }

正如我上面所说,我不希望这样做。


(顺便说一句,我似乎无法为此创建一个 fiddle,因为我不知道如何针对测试和这个用例执行此操作)

感谢您在正确方向上的帮助或推动。

这只是发现您的应用程序中的一个错误:您在 React 组件内使用直接访问 store,这是您不应该 做的事情。当状态发生变化并失去同步时,您的组件将不会重新呈现。

如果您真的想要这样的助手,请使用它自定义一个挂钩:

  import store from 'state/store'
  const useUserIsDefined = () => {
    const user = useSelector(state => state.user)
    if (user === undefined) return false
    ...
    return true
  }

这样您的助手就不需要直接访问 store 并且组件将在该存储值更改时正确重新呈现。