Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NextJS Router & Jest: How can I mock router change event

I am using next-routes and in my React component I am using below useEffect code block to detect Router change event:

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);
  };
}, []);

I am using jest to write unit test case for this component and facing below error:

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);

Can anybody please help me with mocking the Router Change event? Thanks

like image 907
Rahul Gupta Avatar asked Oct 27 '22 02:10

Rahul Gupta


2 Answers

For anyone who is stuck with testing the Router change events in nextjs here is an example.

Short Answer

You can use Router.events.emit to emit the event from your test then assert the callback you are expecting to get fired.

Long Answer

Following is the scenario I am using in the example, however you can modify it to your needs.

Scenario: In my main app, I am using NProgress to display a progress bar on each route change. The custom app looks like this

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() {
   ...
}

Now, in my test, I want to test that the callbacks are called appropriately. The jest test looks like this:

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();
});

like image 86
Subash Avatar answered Nov 01 '22 18:11

Subash


You can trigger the relevant change event by using Router.events.emit('event-name');

The code was taken from the router implementation.

like image 45
felixmosh Avatar answered Nov 01 '22 19:11

felixmosh