Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I've an issue on unit testing a simple component (even more simplified here) :

import React, { Component } from 'react';
import Logout from '../auth/Logout';
import { logoutUser } from '../../actions/auth';
export default class Navbar extends Component {
  render() {
    const { dispatch, isAuthenticated } = this.props;
    if (isAuthenticated) {
      logStatus = <Logout onLogoutClick={() => dispatch(logoutUser())} />;
    } else {
      logStatus = (
        <Link to="/login/">
          <Button>Login</Button>
        </Link>
    return (
      <AppBar>        
        {logStatus}
      </AppBar>

in import { logoutUser } from '../../actions/auth';
I have a function removeItem on localStorage. I won't be using it for my test but that's where I have an error.

My test is :

test('Navbar test series', () => {
  //Enzyme testing
  it('show the login button', () => {
    const wrapper = shallow(<Navbar isAuthenticated={true} />);
    expect(wrapper.find(Login)).to.have.length(1);

I got :

ReferenceError: localStorage is not defined      
      at Object.<anonymous> (src/axios/axios.js:8:15) [I don't know why this is here...]
      at Object.<anonymous> (src/actions/auth.js:89:38) [my logoutUser using localStorage is here ]
      at Object.<anonymous> (src/components/UI/Navbar.js:3:13)
      at Object.<anonymous> (src/components/UI/Navbar.test.js:2:15)

Doing something like suggested here How do I deal with localStorage in jest tests? :

var localStorageMock = (function () { [...]})();
Object.defineProperty(window, 'localStorage', { value: localStorageMock });

is not helping.

What I don't get is that I'm not even calling dispatch(logoutUser()) so why trying to access localStorage ?? Is the issue due to redux through dispatch ?

Thanks a lot for your help !

EDIT1 : Logout component :

import React from 'react';
import Button from '@material-ui/core/Button';
const Logout = props => (
  <Button onClick={() => props.onLogoutClick()}     color="secondary">LOGOUT</Button>
export default Logout;

And code from actions/auth.js and logoutUser() :

export function logoutUser() {
  return dispatch => {
    dispatch(requestLogout());
    localStorage.removeItem('token');
    dispatch(receiveLogout());
                I don't think so, I've tried to "simulate" a localStorage using the post you links and it didn't change. I think the issue is more on why this logoutUser function is call in the first place ?
– pierreaurelemartin
                Jul 20, 2018 at 9:40
                I've found out that I have this error just by importing my component. Even without shallowing it... Strange, I'll dig that.
– pierreaurelemartin
                Jul 20, 2018 at 11:42
  //Enzyme testing
  it('show the login button', () => {
    const wrapper = shallow(<Navbar isAuthenticated={true} />);
    expect(wrapper.find(Login)).to.have.length(1);
                Again, I've tried with this exact snippet to emulate localStorage stackoverflow.com/a/32911774/1565738 and it's not the issue here. Thanks anyway :)
– pierreaurelemartin
                Jul 20, 2018 at 9:56

Have you tried mocking ../../actions/auth entirely for that test?

jest.setMock('../../actions/auth', () => ({ logoutUser: jest.fn() I just tried, I'm still blocked on that localStorage error :) It was a good idea though ! – pierreaurelemartin Jul 20, 2018 at 11:40 A little off topic, but you should try react-testing-library. Shallow rendering is a real pain. In my tests I mock localStorage with global.localStorage = { setItem: jest.fn() }; and it does the trick. Hope you find the solution! – bamse Jul 20, 2018 at 11:52

So the solution was in :

      at Object.<anonymous> (src/axios/axios.js:8:15) [I don't know why this is here...]

Where I've found a const using localstorage on runtime. Just put it in a condition and it solved the issue.

Thanks all for the effort, it was my mistake :-(

but why didn't the mock implementation get invoked? were you referring it by window.localstorage or something else? – dubes Jul 20, 2018 at 12:30 because the const token = localStorage.get[...] was invoke at the root of my axios/axios.js and therefore call in the import chain. And so before the mock implementation of localStorage. – pierreaurelemartin Jul 20, 2018 at 12:47 Even if I though I had tested once with the mock on first line but I guess I did it poorly... – pierreaurelemartin Jul 20, 2018 at 12:47

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.