如何测试React组件中Redux的dispatch()被调用(Jest + Enzyme)

2023-12-22

我有很多功能性的 React 组件,它们调用dispatch()(还原)。这dispatch()函数本身是由react-redux传入的useDispatch() hook.

作为一个简化的例子:

const LogoutButton: FC = () => {
  const dispatch: Dispatch = useDispatch();
  
  return (
   <button onClick={() => {
     console.log("Clicked...") // To check that onClick() simulation is working
     dispatch(authActions.logout())  
   }}>
   LOGOUT
   </button> 
  )
}

使用 Jest 和 Enzyme,我需要做什么才能断言expect(dispatch).toHaveBeenCalledWith(authActions.logout)?

我没有模拟商店或使用 redux-mock-store 的功能。相反,我将组件包装在我为测试而制作的根组件中。它与我真正的 Root 组件相同,但需要设置测试的初始存储(和history.location)的道具:

const TestRoot: FC<RootProps> = ({ children, initialState = {}, initialEntries = defaultLocation }) => {
  const store = createStore(reducers, initialState, applyMiddleware(thunk));

  return (
    <Provider store={store}>
      <MemoryRouter initialEntries={initialEntries}>
        <ScrollToTop />
        <StylesProvider jss={jss}>
          <ThemeProvider theme={theme}>{children}</ThemeProvider>
        </StylesProvider>
      </MemoryRouter>
    </Provider>
  );
};

它在测试中用于设置酶包装组件,例如:

wrappedLogoutButton = mount(
  <TestRoot initialState={initialState}>
    <LogoutButton />
  </TestRoot>
);

这个设置对我来说效果很好(到目前为止),如果不需要的话我不想改变它。我确实尝试将 redux-mock-store 模拟存储注入 TestRoot,但这搞乱了我编写的每个测试套件。

我尝试过多种嘲笑或监视两者的方法dispatch() and useDispatch()但我还没有看到模拟被调用。这onClick()模拟正在工作,因为我可以看到“单击...”被记录。这是一个示例测试(真实代码,不是简化示例):

test('should log learner out', () => {
    const event = {
      preventDefault: () => {},
      target: { textContent: en.common['log-out-title'] } as unknown,
    } as React.MouseEvent<HTMLButtonElement, MouseEvent>;

    const wrappedLogOut = wrappedMenuDrawer.find(ListItem).at(3).find('a');

    // @ts-ignore
    act(() => wrappedLogOut.prop('onClick')(event));

    // TODO: test authService.logout is called
    // assert that dispatch was called with authActions.logout()
    expect(amplitude.logAmpEvent).toHaveBeenCalledWith('from main menu', { to: 'LOGOUT' }); // This assertion passes
  });

根据文档、Medium 帖子和 Stack Overflow 上的类似问题,我尝试过在调度时进行模拟/间谍的方法/变体,包括:

import * as reactRedux from 'react-redux'
const spy = jest.spyOn(reactRedux, 'useDispatch'
import store from '../../store';
const spy = jest.spyOn(store, 'dispatch')
const mockUseDispatch = jest.fn();
const mockDispatch = jest.fn();

jest.mock('react-redux', () => ({
  useDispatch: () => mockUseDispatch.mockReturnValue(mockDispatch),
}));

// or...

jest.mock('react-redux', () => ({
  useDispatch: () => mockUseDispatch,
}));

mockUseDispatch.mockReturnValue(mockDispatch) // inside the actual test
  

您可以通过多种方式做到这一点。 AFAIK:

  • 您可以模拟 useDispatch 钩子来返回您自己的假调度函数。 我在我自己的 React 库的测试代码中使用了它来帮助管理到操作的绑定分派。这里是钩子.test.tsx https://github.com/sidecus/roth.js/blob/master/src/hooks.test.tsx.

  • 由于您使用测试 React 存储来包装组件,因此您还可以直接用伪函数替换 store.dispatch。看here https://gist.github.com/krawaller/e5d40217658fa132f3c3904987e467cd进行讨论。

第一个的好处是,您可以根据需要轻松地从 React-Redux 模拟更多东西。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何测试React组件中Redux的dispatch()被调用(Jest + Enzyme) 的相关文章

随机推荐