React-router: How to write tests for react-router ?

Created on 15 Jan 2017  路  10Comments  路  Source: ReactTraining/react-router

I'm sorry for a question but i looked everywhere and i don't found anything for it. I'd like to know how to write test for react-router functionality. I use react-router v4 and i use karma test runner. How can i make my Link works to navigate to other routes?
My current code is

'use strict';
import React from 'react';
import { BrowserRouter, Match, Redirect } from 'react-router';
import { shallow, mount } from 'enzyme';
import sinon from 'sinon';
import chai, { expect } from 'chai';
import axios from 'axios';
import Main_Store from '../../main.store';
import Base from '../../components/base.component';

describe.only('--Routing--', () => {
   let main_store, wrap;
   beforeEach(() => {
      main_store = new Main_Store();
      wrap = mount(
         <BrowserRouter>
            <Match pattern={'/:district'} render={(props) => {
                  console.log('trigger match');
                  return <Base {...props} main_store={main_store} />
               }
            } />
         </BrowserRouter>
      );
   });

   describe('click on link', () => {
      beforeEach(() => {
         wrap.find('Link').findWhere(n => n.prop('to') === '/kit/user-1/type-created').simulate('click');
      });

      it('render Profile Bar', () => {
         console.log('current html', wrap.html())
         expect(wrap.find('.personSidebar')).to.have.length(1);
      });
   });
});

'use strict';
import React, { Component } from 'react';
import { observer, Provider } from 'mobx-react';
import { Match, Miss, Redirect, Link } from 'react-router';

@observer
class Base extends Component {
   render() {
      const { main_store, params, location, pathname } = this.props;
      const { view_type } = params;
      const { UserId } = main_store.profile;
      console.log('render Base', pathname)
      const routes = (
         <main className={is_kit}>
            <Match
               pattern={'user-:id'} isExactly={false}
               render={(props) => {
                  console.log('this match');
                  return <User_Page {...props} main_store={main_store} />
               }} />
         </main>
      );
      return (
         <div>
            <Provider main_store={main_store}>
               <div>
                  { routes }
               </div>
            </Provider>
         </div>
      );
   }
   constructor(props) {
      super(props);
   }
   componentWillMount(nextProps) {
      this._update(this.props);
   }
   componentWillUpdate(nextProps) {
      if (nextProps.pathname !== this.props.pathname) {
         this._update(nextProps);
      }
   }
   _update(props) {
      const { main_store, location, params } = props;
      main_store.set_location(location);
      main_store.set_router(this.context.router);
      main_store.set_view_type(params.view_type);
   }
}

Base.contextTypes = {
   router: React.PropTypes.object
};

export default Base;


when i click on Link it triggers onClick event but doesn't force to rerender

Most helpful comment

Could we maybe get a link on here to the aforementioned SO post?

All 10 comments

Instead of a <BrowserRouter>, you should be using a <MemoryRouter>. You can use the initialEntries and initialIndex props to simulate the desired history state.

For a reference, you can check the integration tests.

Hi @pshrmn. Thanks for ur answer. I did it. But i got this error:

    __-__ "before each" hook for "render Link"
      Chrome 55.0.2883 (Windows 8.1 0.0.0)
    TypeError: Cannot read property 'pathname' of undefined
        at createRouterLocation (webpack:///~/react-router/LocationUtils.js:27:0 <- tests.webpack.js:33023:23)
        at StaticRouter.createLocation (webpack:///~/react-router/StaticRouter.js:67:0 <- tests.webpack.js:32703:53)
        at StaticRouter.componentWillMount (webpack:///~/react-router/StaticRouter.js:87:0 <- tests.webpack.js:32723:23)
        at ReactCompositeComponentWrapper.mountComponent (webpack:///~/react/lib/ReactCompositeComponent.js:210:0 <- tests.webpack.js:17577:13)
        at ReactCompositeComponentWrapper.wrapper [as mountComponent] (webpack:///~/react/lib/ReactPerf.js:66:0 <- tests.webpack.js:11705:22)
        at Object.mountComponent (webpack:///~/react/lib/ReactReconciler.js:37:0 <- tests.webpack.js:15897:36)
        at ReactCompositeComponentWrapper.mountComponent (webpack:///~/react/lib/ReactCompositeComponent.js:225:0 <- tests.webpack.js:17592:35)
        at ReactCompositeComponentWrapper.wrapper [as mountComponent] (webpack:///~/react/lib/ReactPerf.js:66:0 <- tests.webpack.js:11705:22)
        at Object.mountComponent (webpack:///~/react/lib/ReactReconciler.js:37:0 <- tests.webpack.js:15897:36)
        at ReactCompositeComponentWrapper.mountComponent (webpack:///~/react/lib/ReactCompositeComponent.js:225:0 <- tests.webpack.js:17592:35)

and my current code is

describe.only('__Routing : Zone__', () => {
   let main_store, wrap;
   beforeEach(() => {
      main_store = new Main_Store();
      wrap = mount(
         <MemoryRouter initialIndex={'/kit/'} initialEntries={['/', 'kit']}>
            <Match pattern={'/:view_type'} render={(props) => {
                  console.log('render it')
                  return <Base {...props} main_store={main_store} />
               }
            } />
         </MemoryRouter>
      );
   });
});

initialIndex should be a number.

Thank u @pshrmn . Now it doesn't show error. However, it still doesn't re-render components tree after click on Link. Current event log is next:
1) After mount component recognize that it match current pathname.
2) component is rendered first time .
3) onClick event on is fired
and there is nothing else. In my browser i receive 1 and 2 point again which means that component tree is re-rendered after click on Link. But in my test inv. nothing happend after 3-d point.

I saw that you have a similar question on stackoverflow. I believe that now that the main question is answered (Q: How to test? A: Use <MemoryRouter>) and the remaining issues seem to be debugging, it would be best to move the conversation there. It would also be helpful if you updated your question there with your latest code.

ok, thank u. I'll update it now

Could we maybe get a link on here to the aforementioned SO post?

@optimatex try to use something like this wrapper.find('a').props().onClick(new MouseEvent('click')); instead of wrapper.find('a').simulate('click');. In my tests I found that simulate doesn't work.

@optimatex @michalkvasnicak simulate does not actually simulate a click event. It simply calls the onClick prop on the component which you call simulate on. Read the last section of the page https://github.com/airbnb/enzyme/blob/master/docs/api/ShallowWrapper/simulate.md#common-gotchas

I have some issues testing components inside react-router's HOCs as well. I found the stackoverflow post that was mentioned in the thread and linked here for others that stumble into this issue.

https://stackoverflow.com/questions/41656100/react-router-v4-link-doesnt-work-in-karma-test-runner

Was this page helpful?
0 / 5 - 0 ratings