在Jest测试中,我一直得到“localStorage is not defined”,这是有意义的,但我的选项是什么?碰壁。
当前回答
上面的答案对我都没用。经过一番挖掘,这就是我要做的。这要归功于一些来源和其他答案。
https://www.codeblocq.com/2021/01/Jest-Mock-Local-Storage/ https://github.com/facebook/jest/issues/6798#issuecomment-440988627 https://gist.github.com/mayank23/7b994385eb030f1efb7075c4f1f6ac4c https://github.com/facebook/jest/issues/6798#issuecomment-514266034
我的全部要点:https://gist.github.com/ar-to/01fa07f2c03e7c1b2cfe6b8c612d4c6b
/**
* Build Local Storage object
* @see https://www.codeblocq.com/2021/01/Jest-Mock-Local-Storage/ for source
* @see https://stackoverflow.com/a/32911774/9270352 for source
* @returns
*/
export const fakeLocalStorage = () => {
let store: { [key: string]: string } = {}
return {
getItem: function (key: string) {
return store[key] || null
},
setItem: function (key: string, value: string) {
store[key] = value.toString()
},
removeItem: function (key: string) {
delete store[key]
},
clear: function () {
store = {}
},
}
}
/**
* Mock window properties for testing
* @see https://gist.github.com/mayank23/7b994385eb030f1efb7075c4f1f6ac4c for source
* @see https://github.com/facebook/jest/issues/6798#issuecomment-514266034 for sample implementation
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window#properties for window properties
* @param { string } property window property string but set to any due to some warnings
* @param { Object } value for property
*
* @example
*
* const testLS = {
* id: 5,
* name: 'My Test',
* }
* mockWindowProperty('localStorage', fakeLocalStorage())
* window.localStorage.setItem('currentPage', JSON.stringify(testLS))
*
*/
const mockWindowProperty = (property: string | any, value: any) => {
const { [property]: originalProperty } = window
delete window[property]
beforeAll(() => {
Object.defineProperty(window, property, {
configurable: true,
writable: true,
value,
})
})
afterAll(() => {
window[property] = originalProperty
})
}
export default mockWindowProperty
其他回答
正如@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从这里引用
一个使用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)
})
})
一个更好的替代方法,它处理未定义的值(它不需要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
上面的答案对我都没用。经过一番挖掘,这就是我要做的。这要归功于一些来源和其他答案。
https://www.codeblocq.com/2021/01/Jest-Mock-Local-Storage/ https://github.com/facebook/jest/issues/6798#issuecomment-440988627 https://gist.github.com/mayank23/7b994385eb030f1efb7075c4f1f6ac4c https://github.com/facebook/jest/issues/6798#issuecomment-514266034
我的全部要点:https://gist.github.com/ar-to/01fa07f2c03e7c1b2cfe6b8c612d4c6b
/**
* Build Local Storage object
* @see https://www.codeblocq.com/2021/01/Jest-Mock-Local-Storage/ for source
* @see https://stackoverflow.com/a/32911774/9270352 for source
* @returns
*/
export const fakeLocalStorage = () => {
let store: { [key: string]: string } = {}
return {
getItem: function (key: string) {
return store[key] || null
},
setItem: function (key: string, value: string) {
store[key] = value.toString()
},
removeItem: function (key: string) {
delete store[key]
},
clear: function () {
store = {}
},
}
}
/**
* Mock window properties for testing
* @see https://gist.github.com/mayank23/7b994385eb030f1efb7075c4f1f6ac4c for source
* @see https://github.com/facebook/jest/issues/6798#issuecomment-514266034 for sample implementation
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window#properties for window properties
* @param { string } property window property string but set to any due to some warnings
* @param { Object } value for property
*
* @example
*
* const testLS = {
* id: 5,
* name: 'My Test',
* }
* mockWindowProperty('localStorage', fakeLocalStorage())
* window.localStorage.setItem('currentPage', JSON.stringify(testLS))
*
*/
const mockWindowProperty = (property: string | any, value: any) => {
const { [property]: originalProperty } = window
delete window[property]
beforeAll(() => {
Object.defineProperty(window, property, {
configurable: true,
writable: true,
value,
})
})
afterAll(() => {
window[property] = originalProperty
})
}
export default mockWindowProperty
或者你只是像这样使用一个模拟包:
https://www.npmjs.com/package/jest-localstorage-mock
它不仅处理存储功能,还允许您测试是否实际调用了存储。