How do I deal with localStorage in jest tests?

后端 未结 17 1686
长情又很酷
长情又很酷 2020-11-28 02:01

I keep getting \"localStorage is not defined\" in Jest tests which makes sense but what are my options? Hitting brick walls.

相关标签:
17条回答
  • 2020-11-28 02:48

    You need to mock local storage with this snippets

    // localStorage.js

    var localStorageMock = (function() {
        var store = {};
    
        return {
            getItem: function(key) {
                return store[key] || null;
            },
            setItem: function(key, value) {
                store[key] = value.toString();
            },
            clear: function() {
                store = {};
            }
        };
    
    })();
    
    Object.defineProperty(window, 'localStorage', {
         value: localStorageMock
    });
    

    And in the jest config:

    "setupFiles":["localStorage.js"]
    

    Feel free to ask anything .

    0 讨论(0)
  • 2020-11-28 02:51

    Unfortunately, the solutions that I've found here didn't work for me.

    So I was looking at Jest GitHub issues and found this thread

    The most upvoted solutions were these ones:

    const spy = jest.spyOn(Storage.prototype, 'setItem');
    
    // or
    
    Storage.prototype.getItem = jest.fn(() => 'bla');
    
    0 讨论(0)
  • 2020-11-28 02:52

    If you are looking for a mock and not a stub, here is the solution I use:

    export const localStorageMock = {
       getItem: jest.fn().mockImplementation(key => localStorageItems[key]),
       setItem: jest.fn().mockImplementation((key, value) => {
           localStorageItems[key] = value;
       }),
       clear: jest.fn().mockImplementation(() => {
           localStorageItems = {};
       }),
       removeItem: jest.fn().mockImplementation((key) => {
           localStorageItems[key] = undefined;
       }),
    };
    
    export let localStorageItems = {}; // eslint-disable-line import/no-mutable-exports
    

    I export the storage items for easy initialization. I.E. I can easily set it to an object

    In the newer versions of Jest + JSDom it is not possible to set this, but the localstorage is already available and you can spy on it it like so:

    const setItemSpy = jest.spyOn(Object.getPrototypeOf(window.localStorage), 'setItem');
    
    0 讨论(0)
  • 2020-11-28 02:52

    As @ck4 suggested documentation has clear explanation for using localStorage in jest. However the mock functions were failing to execute any of the localStorage methods.

    Below is the detailed example of my react component which make uses of abstract methods for writing and reading data,

    //file: storage.js
    const key = 'ABC';
    export function readFromStore (){
        return JSON.parse(localStorage.getItem(key));
    }
    export function saveToStore (value) {
        localStorage.setItem(key, JSON.stringify(value));
    }
    
    export default { readFromStore, saveToStore };
    

    Error:

    TypeError: _setupLocalStorage2.default.setItem is not a function
    

    Fix:
    Add below mock function for jest (path: .jest/mocks/setUpStore.js )

    let mockStorage = {};
    
    module.exports = window.localStorage = {
      setItem: (key, val) => Object.assign(mockStorage, {[key]: val}),
      getItem: (key) => mockStorage[key],
      clear: () => mockStorage = {}
    };
    

    Snippet is referenced from here

    0 讨论(0)
  • 2020-11-28 02:54

    Figured it out with help from this: https://groups.google.com/forum/#!topic/jestjs/9EPhuNWVYTg

    Setup a file with the following contents:

    var localStorageMock = (function() {
      var store = {};
      return {
        getItem: function(key) {
          return store[key];
        },
        setItem: function(key, value) {
          store[key] = value.toString();
        },
        clear: function() {
          store = {};
        },
        removeItem: function(key) {
          delete store[key];
        }
      };
    })();
    Object.defineProperty(window, 'localStorage', { value: localStorageMock });
    

    Then you add the following line to your package.json under your Jest configs

    "setupTestFrameworkScriptFile":"PATH_TO_YOUR_FILE",

    0 讨论(0)
  • 2020-11-28 02:54

    Currently (Oct '19) localStorage can not be mocked or spied on by jest as you usually would, and as outlined in the create-react-app docs. This is due to changes made in jsdom. You can read about it in the jest and jsdom issue trackers.

    As a workaround, you can spy on the prototype instead:

    // does not work:
    jest.spyOn(localStorage, "setItem");
    localStorage.setItem = jest.fn();
    
    // works:
    jest.spyOn(window.localStorage.__proto__, 'setItem');
    window.localStorage.__proto__.setItem = jest.fn();
    
    // assertions as usual:
    expect(localStorage.setItem).toHaveBeenCalled();
    
    0 讨论(0)
提交回复
热议问题