使用预加载状态在 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/>)
...
}
现在..测试的时候会发生什么运行好像是这样的
- utils.ts 被读取并读取行 import store from 'state/store',这将创建并保存一个存储尚未定义用户的变量。
- utils.test.tsx 被调用并且 运行 调用 const store = makeStore({ user: { id_token: '1' } }).
- renderWithProvider() 渲染 SomeComponent 进而调用 userIsDefined 函数。
- 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
并且组件将在该存储值更改时正确重新呈现。
我正在使用 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
);
})
})
SomeComponent.tsx
const SomeComponent = () => {
if (userIsDefined() === false) return (<Forbidden/>)
...
}
现在..测试的时候会发生什么运行好像是这样的
- utils.ts 被读取并读取行 import store from 'state/store',这将创建并保存一个存储尚未定义用户的变量。
- utils.test.tsx 被调用并且 运行 调用 const store = makeStore({ user: { id_token: '1' } }).
- renderWithProvider() 渲染 SomeComponent 进而调用 userIsDefined 函数。
- 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
并且组件将在该存储值更改时正确重新呈现。