Jest mock localStorage methods
Asked Answered
L

5

7

I would like to mock localStorage methods in jest for error simulation. I have localstorage getter and setter methods defined in utility.js. I would like to mock localStorage.setItem to throw an error when utility.setItem is called.

//file: utility.js
export default {
  getItem(key) {
    return localStorage.getItem(key);
  },
  setItem(key, value) {
    localStorage.setItem(key, value);
  }
};

In jest,

test('throw error', () => {
  localStorage.setItem = jest.fn(() => {
    console.log(" called ");
    throw new Error('ERROR');
  });

  utility.setItem('123', 'value');
});

However localStorage.setItem mock is never getting called. I have also tried doing

window.localStorage.setItem = jest.genMockFunction(()=>{console.log(" Mock Called")});
global.localStorage.setItem = jest.fn(()=>{console.log(" Mock Called")});
Laguna answered 18/10, 2018 at 21:48 Comment(2)
What is localStorage you're referring? There's no LS global in Node. And Jest (JSDOM) doesn't add it, afaik. I would expect this code to cause an error because of that.Sclerous
DOM localStorage, I upon calling utility.setItem i can set the value but instead i want to handle the sad case doing mockLaguna
L
6

This goes inline with what Andreas suggested in the answer, but i was able to mock it using Storage interface. I did something like this,

In jest,

test('throw error', () => {
  Storage.prototype.setItem = jest.fn(() => {
    console.log(" called "); // <-- was called 
    throw new Error('ERROR');
  });

  utility.setItem('123', 'value');
});

Also this PR discussion was helpful.

Laguna answered 19/10, 2018 at 19:8 Comment(1)
i tried this but return ReferenceError: Storage is not definedPrimer
H
24

jest.spyOn(window.localStorage.__proto__, 'setItem'); works with nothing else at all needed, as noted here: https://github.com/facebook/jest/issues/6798#issuecomment-440988627

Hux answered 21/12, 2018 at 0:35 Comment(1)
This also worked for me using sinonPreparative
L
6

This goes inline with what Andreas suggested in the answer, but i was able to mock it using Storage interface. I did something like this,

In jest,

test('throw error', () => {
  Storage.prototype.setItem = jest.fn(() => {
    console.log(" called "); // <-- was called 
    throw new Error('ERROR');
  });

  utility.setItem('123', 'value');
});

Also this PR discussion was helpful.

Laguna answered 19/10, 2018 at 19:8 Comment(1)
i tried this but return ReferenceError: Storage is not definedPrimer
A
3

If you want to test localStorage functions then I would like to suggest the jest-localstorage-mock npm package.

After configuring this package in your setup test file as per documentation, then you could do this after.

test('should save to localStorage', () => {
  const KEY = 'foo',
    VALUE = 'bar';
  dispatch(action.update(KEY, VALUE));
  expect(localStorage.setItem).toHaveBeenLastCalledWith(KEY, VALUE);
  expect(localStorage.__STORE__[KEY]).toBe(VALUE);
  expect(Object.keys(localStorage.__STORE__).length).toBe(1);
});


test('should have cleared the sessionStorage', () => {
  dispatch(action.reset());
  expect(sessionStorage.clear).toHaveBeenCalledTimes(1);
  expect(sessionStorage.__STORE__).toEqual({}); // check store values
  expect(sessionStorage.length).toBe(0); // or check length
});
Abolish answered 19/10, 2018 at 2:48 Comment(0)
W
1

To access something that is in the global scope of your module under test, you need to use the global namespace. So to access localStorage use global.localStorage:

global.storage = {
  store:{},
  getItem: (key)=>this.store[key],
  setItem: (key, value)=> this.store[key] = value
}
Wardship answered 19/10, 2018 at 6:49 Comment(0)
B
0

Here is the TS version of https://github.com/facebook/jest/issues/6798#issuecomment-440988627

import { afterAll, beforeAll } from '@jest/globals';

const mockWindowProperty = <P extends keyof Window>(property: P, value: Partial<Window[P]>) => {
  const { [property]: originalProperty } = window;
  delete window[property];
  beforeAll(() => {
    Object.defineProperty(window, property, {
      configurable: true,
      writable: true,
      value,
    });
  });
  afterAll(() => {
    window[property] = originalProperty;
  });
};

export default mockWindowProperty;
Bahadur answered 18/4 at 9:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.