Reactjs 单元测试对访问全局存储的组件进行反应
首先,请让我知道这是不是提出这个问题的正确地方,或者把它移到正确的地方 我开始为一些React组件编写单元测试。其中一个没有任何道具,但依赖于Reactjs 单元测试对访问全局存储的组件进行反应,reactjs,unit-testing,jestjs,react-testing-library,Reactjs,Unit Testing,Jestjs,React Testing Library,首先,请让我知道这是不是提出这个问题的正确地方,或者把它移到正确的地方 我开始为一些React组件编写单元测试。其中一个没有任何道具,但依赖于商店: const PlayerSelector = () => { const classes = useStyles(); const divRef = useRef(null); const [{ playerList }, dispatch] = useStore(); ... 其中userStore()来自: export c
商店
:
const PlayerSelector = () => {
const classes = useStyles();
const divRef = useRef(null);
const [{ playerList }, dispatch] = useStore();
...
其中userStore()
来自:
export const StateContext = createContext(null);
export const StoreProvider = ({ initialState, reducer, children }) => (
<StateContext.Provider
value={useReducer(reducer, initialState)}
>
{children}
</StateContext.Provider>
);
export const useStore = () => useContext(StateContext);
结果是TypeError:objectnull不可iterable(无法读取属性符号(Symbol.iterator))
指向此行:
const [{ firmList }, dispatch] = useStore();
在谷歌搜索了很多之后,我发现了一些有用的资源,说明了如何模拟上下文,但没有说明如何对减速机进行同样的操作。我不知道我是否把事情复杂化了,是否应该找到另一种测试方法,或者我是否遗漏了一个明显的答案。在任何情况下,我都非常感谢您提供的任何提示或指导。当您测试一个组件,该组件使用来自提供者的上下文时,您还需要呈现提供者以提供上下文。
render
接受第二个options参数,该参数可以包含一个用于包装正在测试的组件的参数
例如:
const customWrapper = ({ children }) => <SomeProvider>{children}</SomeProvider>;
it('loads component', () => {
const { queryByRole } = render(
<PlayerSelector />,
{
wrapper: customWrapper
},
);
expect(queryByRole('button')).toHaveAttribute('aria-label');
});
如果您发现自己需要大量编写包装器实用程序,您还可以创建一个,它或多或少地重复了上述内容
const StateProvider = ({ children }) => (
<StoreProvider
initialState={{}} // <-- any initial state object
reducer={rootReducerFunction} // <-- any reducer function
>
{children}
</StoreProvider>
);
export const renderWithState = (ui, options) => {
return render(ui, { wrapper: StateProvider, ...options });
}
const StateProvider=({children})=>(
{
const{queryByRole}=renderWithState();
expect(queryByRole('button')).toHaveAttribute('aria-label');
});
你是救命恩人!我实现了您的建议,然后通过导入包含存储内容的.js文件来模拟initialState。最后,我不得不将PlayerSelection组件封装在MemoryRouter中。我想让你知道,我非常感谢你花时间回答我的问题,为我指出正确的方向。非常感谢你!
it('loads component', () => {
const { queryByRole } = render(
<PlayerSelector />,
{
wrapper: ({ children }) => (
<StoreProvider
initialState={{}} // <-- any initial state object
reducer={rootReducerFunction} // <-- any reducer function
>
{children}
</StoreProvider>
),
},
);
expect(queryByRole('button')).toHaveAttribute('aria-label');
});
const StateProvider = ({ children }) => (
<StoreProvider
initialState={{}} // <-- any initial state object
reducer={rootReducerFunction} // <-- any reducer function
>
{children}
</StoreProvider>
);
export const renderWithState = (ui, options) => {
return render(ui, { wrapper: StateProvider, ...options });
}
import { renderWithState } from '../path/to/utils';
...
it('loads component', () => {
const { queryByRole } = renderWithState(<PlayerSelector />);
expect(queryByRole('button')).toHaveAttribute('aria-label');
});