首页 > 解决方案 > NextJS Router & Jest:如何模拟路由器更改事件

问题描述

我正在使用next-routes并且在我的 React 组件中我使用下面useEffect的代码块来检测Router更改事件:

useEffect(() => {
  // THIS BLOCK WILL BE EXECUTED WHEN THE COMPONENT IS ALREADY MOUNTED AND SCREEN WOULD BE REDNDERED IN WHEN ROUTED CLIENT SIDE
  const handleRouterChangeComplete = url => {
    // console.log('INNNN handleRouterChangeComplete url = ', url);
    // MY REST OF THE LOGIC HERE
  };

  // THIS BLOCK WILL BE EXECUTED WHEN THE SCREEN WOULD BE REDNDERED IN WHEN ROUTED CLIENT SIDE
  Router.events.on('routeChangeComplete', handleRouterChangeComplete);
  return () => {
    Router.events.off('routeChangeComplete', handleRouterChangeComplete);
  };
}, []);

我正在jest为此组件编写单元测试用例并面临以下错误:

TypeError: Cannot read property 'on' of undefined

      183 |
      184 |     // THIS BLOCK WILL BE EXECUTED WHEN THE SCREEN WOULD BE REDNDERED IN WHEN ROUTED CLIENT SIDE
    > 185 |     Router.events.on('routeChangeComplete', handleRouterChangeComplete);

有人可以帮我嘲笑这个Router Change事件吗?谢谢

标签: reactjsunit-testingmockingjestjsnext.js

解决方案


对于任何坚持在 nextjs 中测试路由器更改事件的人来说,这里是一个示例。

简答

您可以使用Router.events.emit从测试中发出事件,然后断言您期望被触发的回调。

长答案

以下是我在示例中使用的场景,但是您可以根据需要对其进行修改。

场景:在我的主应用程序中,我使用NProgress显示每个路线更改的进度条。自定义应用看起来像这样

import Router from 'next/router';
import NProgress from 'nprogress';

Router.events.on('routeChangeStart', () => NProgress.start());
Router.events.on('routeChangeComplete', () => NProgress.done());
Router.events.on('routeChangeError', () => NProgress.done());

export default CustomApp() {
   ...
}

现在,在我的测试中,我想测试回调是否被正确调用。开玩笑的测试如下所示:

import Router from 'next/router;
import NProgress from 'nprogress;
import { render } from '@testing-library/react';
import CustomApp from 'pages/_app';

const mockStart = jest.spyOn(NProgress, 'start');
const mockDone = jest.spyOn(NProgress, 'done');

it('starts nprogress on router change start', () => {
  render(<CustomApp />)
  Router.events.emit('routeChangeStart');
  expect(mockStart).toHaveBeenCalled();
});

it('ends nprogress on router change complete', () => {
  render(<CustomApp />)
  Router.events.emit('routeChangeComplete');
  expect(mockDone).toHaveBeenCalled();
});


推荐阅读