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


当前回答

这对我很有效,

delete global.localStorage;
global.localStorage = {
getItem: () => 
 }

其他回答

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

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

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

正如@ck4所建议的那样,文档已经清楚地解释了如何使用localStorage。然而,模拟函数无法执行任何localStorage方法。

下面是我的react组件的详细示例,它使用抽象方法来写入和读取数据,

//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 };

错误:

TypeError: _setupLocalStorage2.default.setItem is not a function

解决办法: 为jest添加以下mock函数(路径:.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从这里引用

首先,我创建了一个名为localStorage.ts(localStorage.js)的文件

class LocalStorageMock {
  store: Store;
  length: number;

  constructor() {
    this.store = {};
    this.length = 0;
  }

  key(n: number): any {
    if (typeof n === 'undefined') {
      throw new Error(
        "Uncaught TypeError: Failed to execute 'key' on 'Storage': 1 argument required, but only 0 present."
      );
    }

    if (n >= Object.keys(this.store).length) {
      return null;
    }

    return Object.keys(this.store)[n];
  }

  getItem(key: string): Store | null {
    if (!Object.keys(this.store).includes(key)) {
      return null;
    }

    return this.store[key];
  }

  setItem(key: string, value: any): undefined {
    if (typeof key === 'undefined' && typeof value === 'undefined') {
      throw new Error(
        "Uncaught TypeError: Failed to execute 'setItem' on 'Storage': 2 arguments required, but only 0 present."
      );
    }

    if (typeof value === 'undefined') {
      throw new Error(
        "Uncaught TypeError: Failed to execute 'setItem' on 'Storage': 2 arguments required, but only 1 present."
      );
    }

    if (!key) return undefined;

    this.store[key] = value.toString() || '';
    this.length = Object.keys(this.store).length;

    return undefined;
  }

  removeItem(key: string): undefined {
    if (typeof key === 'undefined') {
      throw new Error(
        "Uncaught TypeError: Failed to execute 'removeItem' on 'Storage': 1 argument required, but only 0 present."
      );
    }

    delete this.store[key];
    this.length = Object.keys(this.store).length;
    return undefined;
  }

  clear(): undefined {
    this.store = {};
    this.length = 0;

    return undefined;
  }
}

export const getLocalStorageMock = (): any => {
  return new LocalStorageMock();
};

global.localStorage = new LocalStorageMock();

然后创建名为session.test.ts的测试文件(session.test.js)

import { getLocalStorageMock } from '../localstorage';
describe('session storage', () => {
  let localStorage;
  beforeEach(() => {
    localStorage = getLocalStorageMock();
  });

  describe('getItem', () => {
    it('should return null if the item is undefined', () => {
      expect(localStorage.getItem('item')).toBeNull();
    });
    it("should return '' instead of null", () => {
      localStorage.setItem('item', '');
      expect(localStorage.getItem('item')).toBe('');
    });
    it('should return navid', () => {
      localStorage.setItem('item', 'navid');
      expect(localStorage.getItem('item')).toBe('navid');
    });

  });
});

我从github找到了这个解决方案

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
});

您可以在setupTests中插入这段代码,它应该可以正常工作。

我在一个使用typesctipt的项目中测试了它。

一个使用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)
      })
    })