Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeError: Cannot read property 'location' of undefined (jest)

I have a simple component that uses useLocation hook from React Router.

// App.jsx

import React from 'react';
import { useLocation } from 'react-router-dom';

function App() {
  const location = useLocation();
  const pathName = location.pathname;
  useEffect(() => {
    // Use pathName here
  }, [pathName]);
}

// App.test.js

import App from './App';

describe('App component', () => {
  it('Renders correctly', () => {
    const wrapper = shallow(<App />);

    expect(wrapper).toMatchSnapshot();
  });
});

// Update App.test.js (with jest mock)

import App from './App';

describe('App component', () => {
  jest.mock('react-router-dom', () => ({
    useLocation: jest.fn().mockReturnValue({
      pathname: '/another-route',
      search: '',
      hash: '',
      state: null,
      key: '5nvxpbdafa',
    }),
  }));

  it('Renders correctly', () => {
    const wrapper = shallow(<App />);

    expect(wrapper).toMatchSnapshot();
  });
});

Could you please tell me how I can fix this? Thanks.

like image 457
qwert-poiuy Avatar asked Feb 14 '20 21:02

qwert-poiuy


2 Answers

Just move your jest.mock declaration to the top of the file and it should work:

import App from './App';

jest.mock('react-router-dom', () => ({
    useLocation: jest.fn().mockReturnValue({
      pathname: '/another-route',
      search: '',
      hash: '',
      state: null,
      key: '5nvxpbdafa',
    }),
}));

describe('App component', () => {
  it('Renders correctly', () => {
    const wrapper = shallow(<App />);

    expect(wrapper).toMatchSnapshot();
  });
});
like image 156
mgarcia Avatar answered Sep 22 '22 19:09

mgarcia


In case, anybody else faces a similar problem.

There were 2 issues with my approach. First, I used mock inside describe (thanks Johnny and MGarcia to help me figure that out).

However, I got another error after I moved mock code. Error: React.createElement: type is invalid — expected a string

That was my another Jest newbie mistake, and forgot that it's all JavaScript under the hood. With this approach, the side effect of mocking useLocation is rest of the methods from react-router-dom are made unavailable.

This is the approach that worked for me:

https://github.com/facebook/jest/issues/936#issuecomment-265074320

Final solution:

function mockFunction() {
  const original = require.requireActual('react-router-dom');
  return {
    ...original,
    useLocation: jest.fn().mockReturnValue({
      pathname: '/another-route',
      search: '',
      hash: '',
      state: null,
      key: '5nvxpbdafa',
    }),
  };
}

jest.mock('react-router-dom', () => mockFunction());
like image 25
qwert-poiuy Avatar answered Sep 20 '22 19:09

qwert-poiuy