How to mock localStorage in JavaScript unit tests?

前端 未结 14 1602
南笙
南笙 2020-11-29 18:46

Are there any libraries out there to mock localStorage?

I\'ve been using Sinon.JS for most of my other javascript mocking and have found it is really gr

14条回答
  •  挽巷
    挽巷 (楼主)
    2020-11-29 19:20

    I decided to reiterate my comment to Pumbaa80's answer as separate answer so that it'll be easier to reuse it as a library.

    I took Pumbaa80's code, refined it a bit, added tests and published it as an npm module here: https://www.npmjs.com/package/mock-local-storage.

    Here is a source code: https://github.com/letsrock-today/mock-local-storage/blob/master/src/mock-localstorage.js

    Some tests: https://github.com/letsrock-today/mock-local-storage/blob/master/test/mock-localstorage.js

    Module creates mock localStorage and sessionStorage on the global object (window or global, which of them is defined).

    In my other project's tests I required it with mocha as this: mocha -r mock-local-storage to make global definitions available for all code under test.

    Basically, code looks like follows:

    (function (glob) {
    
        function createStorage() {
            let s = {},
                noopCallback = () => {},
                _itemInsertionCallback = noopCallback;
    
            Object.defineProperty(s, 'setItem', {
                get: () => {
                    return (k, v) => {
                        k = k + '';
                        _itemInsertionCallback(s.length);
                        s[k] = v + '';
                    };
                }
            });
            Object.defineProperty(s, 'getItem', {
                // ...
            });
            Object.defineProperty(s, 'removeItem', {
                // ...
            });
            Object.defineProperty(s, 'clear', {
                // ...
            });
            Object.defineProperty(s, 'length', {
                get: () => {
                    return Object.keys(s).length;
                }
            });
            Object.defineProperty(s, "key", {
                // ...
            });
            Object.defineProperty(s, 'itemInsertionCallback', {
                get: () => {
                    return _itemInsertionCallback;
                },
                set: v => {
                    if (!v || typeof v != 'function') {
                        v = noopCallback;
                    }
                    _itemInsertionCallback = v;
                }
            });
            return s;
        }
    
        glob.localStorage = createStorage();
        glob.sessionStorage = createStorage();
    }(typeof window !== 'undefined' ? window : global));
    

    Note that all methods added via Object.defineProperty so that them won't be iterated, accessed or removed as regular items and won't count in length. Also I added a way to register callback which is called when an item is about to be put into object. This callback may be used to emulate quota exceeded error in tests.

提交回复
热议问题