6

I am trying to test localStorage using sinon. Basically I am very new to unit testing so this might be very basic.

Update

I managed to come up with this but now its giving me a new error Should wrap property of object

Test

describe('Initial State', () => {
    it('should set the initial state for the component', () => {
const props = {
        currentUser: {}
      };
      sinon.stub(window.localStorage, 'setItem');
      window.localStorage.setItem('none', 'nothing');
    });
  });
Umair Sarfraz
  • 5,284
  • 4
  • 22
  • 38
  • @anoop I've gone through that. Previously I tested the `location` object with the same procedure and its working fine. However, in this case its giving me `Attempted to wrap undefined property setItem as function` – Umair Sarfraz Aug 15 '16 at 10:44
  • @DmitriyNevzorov Agreed, no need. But if I don't test it all the other tests fail and throw an error that `localStorage` is not defined. – Umair Sarfraz Aug 15 '16 at 10:44

2 Answers2

8

I managed to resolve it. Thanks to @anoop because his answer was of help but I had to manage it with a major workaround. I am using jsdom and it currently DOES NOT support localStorage. I added a fake in my jsdom configuration.

if (!global.window.localStorage) {
  global.window.localStorage = {
    getItem() { return '{}'; },
    setItem() {}
  };
}

And asserted it with:

it('should fetch from local storage', () => {
      const props = {
        currentUser: 'UMAIR',
        user: {
          is_key: false
        }
      };

      const spy = sinon.spy(global.window.localStorage, "setItem");
      spy(props);
      expect(spy.calledWith( {
        currentUser: 'UMAIR',
        user: {
          is_key: false
        }
      }));
      spy.restore();

      const stub = sinon.stub(global.window.localStorage, 'getItem');
      stub(props);
      expect(stub.calledWith(Object.keys(props)));
// stub.restore();
    });

Also see: How to mock localStorage in JavaScript unit tests?

https://github.com/gor181/webpack-react-babel-mocha-boilerplate/tree/master/test/utils

I also found an internal issue in Sinon a week ago related to this but that has been resolved.

See: https://github.com/sinonjs/sinon/issues/1129

Hope this helps someone.

Community
  • 1
  • 1
Umair Sarfraz
  • 5,284
  • 4
  • 22
  • 38
2

You can use babel-plugin-rewire to replace localStorage with mocked version in all your tests.

This is how I use it:

import {unauth, signOut, __RewireAPI__} from 'modules/auth/actions';

const rewrite = __RewireAPI__.__Rewire__;

const local = {}; // object where you store all values localStorage needs to return
const storage = {
  get(key) {
    return local[key];
  },
  set: sinon.spy(),
  remove: sinon.spy()
};

rewrite('storage', storage); // rewrite storage package with your mocked version

// in you test add values you want to get from localStorage
local.credentials = constants.CREDENTIALS;
local.authToken = constants.TOKEN;
Dmitriy Nevzorov
  • 6,042
  • 1
  • 20
  • 28
  • I've seen other packages as well to mock localStore. This might be right but what I'm trying to achieve is to mock it manually with a global object. Something like global.window = { localStorage: {.. – Umair Sarfraz Aug 15 '16 at 11:09