在Jest测试中,我一直得到“localStorage is not defined”,这是有意义的,但我的选项是什么?碰壁。


当前回答

一个更好的替代方法,它处理未定义的值(它不需要toString()),如果值不存在则返回null。用react v15、redux和redux-auth-wrapper进行了测试

class LocalStorageMock {
  constructor() {
    this.store = {}
  }

  clear() {
    this.store = {}
  }

  getItem(key) {
    return this.store[key] || null
  }

  setItem(key, value) {
    this.store[key] = value
  }

  removeItem(key) {
    delete this.store[key]
  }
}

global.localStorage = new LocalStorageMock

其他回答

至少到目前为止,localStorage可以很容易地在你的笑话测试中被监视,例如:

const spyRemoveItem = jest.spyOn(window.localStorage, 'removeItem')

就是这样。你可以像以前一样使用你的间谍。

一个使用TypeScript和Jest的更优雅的解决方案。

    interface Spies {
      [key: string]: jest.SpyInstance
    }
    
    describe('→ Local storage', () => {
    
      const spies: Spies = {}
    
      beforeEach(() => {
        ['setItem', 'getItem', 'clear'].forEach((fn: string) => {
          const mock = jest.fn(localStorage[fn])
          spies[fn] = jest.spyOn(Storage.prototype, fn).mockImplementation(mock)
        })
      })
    
      afterEach(() => {
        Object.keys(spies).forEach((key: string) => spies[key].mockRestore())
      })
    
      test('→ setItem ...', async () => {
          localStorage.setItem( 'foo', 'bar' )
          expect(localStorage.getItem('foo')).toEqual('bar')
          expect(spies.setItem).toHaveBeenCalledTimes(1)
      })
    })

2022年12月:Nx 14使用Angular 14 Jest。 我们有一个测试设置。Ts文件在每个app和libs文件夹。我们设置本地存储模拟全局。

import 'jest-preset-angular/setup-jest';

Storage.prototype.getItem = jest.fn();
Storage.prototype.setItem = jest.fn();
Storage.prototype.removeItem = jest.fn();

然后localStorage.service.spec.ts文件如下所示:

import { LocalStorageService } from './localstorage.service';

describe('LocalStorageService', () => {
    let localStorageService: LocalStorageService;

    beforeEach(() => {
        localStorageService = new LocalStorageService();
    });

    it('should set "identityKey" in localStorage', async () => {
        localStorageService.saveData('identityKey', '99');
        expect(window.localStorage.setItem).toHaveBeenCalled();
 expect(window.localStorage.setItem).toHaveBeenCalledWith('identityKey', '99');
        expect(window.localStorage.setItem).toHaveBeenCalledTimes(1);
});

it('should get "identityKey" from localStorage', async () => {
    localStorageService.getData('identityKey');
    expect(window.localStorage.getItem).toHaveBeenCalled();
    expect(window.localStorage.getItem).toHaveBeenCalledWith('identityKey');
    expect(window.localStorage.getItem).toHaveBeenCalledTimes(1);
});

it('should remove "identityKey" from localStorage', async () => {
    localStorageService.removeData('identityKey');
    expect(window.localStorage.removeItem).toHaveBeenCalled();
expect(window.localStorage.removeItem).toHaveBeenCalledWith('identityKey');
            expect(window.localStorage.removeItem).toHaveBeenCalledTimes(1);
        });
    });

注:不好意思,这个SatckOverflow窗口很糟糕。

不需要模拟localStorage—只需使用jsdom环境,这样您的测试就可以在类似浏览器的条件下运行。

在你的joke。config。js中,

module.exports = {
    // ...
    testEnvironment: "jsdom"
}
    

要在Typescript中做同样的事情,请执行以下步骤:

设置一个包含以下内容的文件:

let localStorageMock = (function() {
  let store = new Map()
  return {

    getItem(key: string):string {
      return store.get(key);
    },

    setItem: function(key: string, value: string) {
      store.set(key, value);
    },

    clear: function() {
      store = new Map();
    },

    removeItem: function(key: string) {
        store.delete(key)
    }
  };
})();
Object.defineProperty(window, 'localStorage', { value: localStorageMock });

然后将以下行添加到包中。json在你的Jest配置

:“setupTestFrameworkScriptFile PATH_TO_YOUR_FILE”,

或者在您想要模拟本地存储的测试用例中导入该文件。