Jestjs 如何在jest测试中处理localStorage?
我在Jest测试中不断得到“localStorage未定义”,这很有意义,但我的选择是什么?撞到砖墙。在以下帮助下找到了答案: 设置包含以下内容的文件:Jestjs 如何在jest测试中处理localStorage?,jestjs,Jestjs,我在Jest测试中不断得到“localStorage未定义”,这很有意义,但我的选择是什么?撞到砖墙。在以下帮助下找到了答案: 设置包含以下内容的文件: let localStorageMock = (function() { let store = new Map() return { getItem(key: string):string { return store.get(key); }, setItem: function(key: st
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 });
var localStorageMock=(函数(){
var-store={};
返回{
getItem:函数(键){
返回存储[键];
},
setItem:函数(键、值){
store[key]=value.toString();
},
清除:函数(){
存储={};
},
removeItem:功能(键){
删除存储[密钥];
}
};
})();
defineProperty(窗口'localStorage',{value:localStorageMock});
然后将以下行添加到Jest配置下的package.json中
“SetupTestFrameworkScript文件”:“指向您的文件的路径”,
来自
然而,我们使用ES2015语法,我觉得这样写比较干净
类LocalStorageMock{
构造函数(){
this.store={};
}
清除(){
this.store={};
}
getItem(键){
返回此。存储[键]| |空;
}
setItem(键、值){
this.store[key]=字符串(值);
}
removeItem(键){
删除此项。存储[密钥];
}
};
global.localStorage=新的LocalStorageMock;
一个更好的选择,它处理未定义的值(它没有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
或者你只需要像这样的模拟包:
export class LocalStorageMock {
private store = {}
clear() {
this.store = {}
}
getItem(key: string) {
return this.store[key] || null
}
setItem(key: string, value: string) {
this.store[key] = value
}
removeItem(key: string) {
delete this.store[key]
}
}
它不仅处理存储功能,还允许您测试是否实际调用了该存储。在这里提取一些其他答案,以解决Typescript项目的问题。我创建了一个LocalStorageMock,如下所示:
export class LocalStorageMock {
private store = {}
clear() {
this.store = {}
}
getItem(key: string) {
return this.store[key] || null
}
setItem(key: string, value: string) {
this.store[key] = value
}
removeItem(key: string) {
delete this.store[key]
}
}
然后,我创建了一个LocalStorageWrapper类,用于访问应用程序中的本地存储,而不是直接访问全局本地存储变量。使在包装器中为测试设置模拟变得容易。如果使用createreact应用程序,则在中介绍了一种简单明了的解决方案
创建src/setupTests.js
并将其放入其中:
const localStorageMock = {
getItem: jest.fn(),
setItem: jest.fn(),
clear: jest.fn()
};
global.localStorage = localStorageMock;
Tom Mertz在以下评论中的贡献:
然后,您可以通过执行以下操作来测试localStorageMock的函数是否被使用
expect(localStorage.getItem).toBeCalledWith('token')
// or
expect(localStorage.getItem.mock.calls.length).toBe(1)
如果你想确保它被调用的话。正如@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 };
错误:
修复:
为jest添加以下模拟函数(路径:.jest/mocks/setUpStore.js
)
代码段引用自当前(19年10月)的本地存储不能像您通常所做的那样被jest模仿或监视,正如创建react应用程序文档中所述。这是由于jsdom中所做的更改。您可以在问题和跟踪程序中阅读相关内容
作为一种解决方法,您可以监视原型:
//不起作用:
jest.spyOn(localStorage,setItem);
localStorage.setItem=jest.fn();
//作品:
jest.spyOn(window.localStorage;
window.localStorage.\uuuu proto\uuuuu.setItem=jest.fn();
//一如既往的断言:
expect(localStorage.setItem).toHaveBeenCalled();
如果您正在寻找模拟而不是存根,以下是我使用的解决方案:
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
我导出存储项以便于初始化。也就是说,我可以轻松地将其设置为对象
在Jest+JSDom的较新版本中,无法设置此选项,但localstorage已经可用,您可以像这样监视它:
const setItemSpy = jest.spyOn(Object.getPrototypeOf(window.localStorage), 'setItem');
以下解决方案与更严格的TypeScript、ESLint、TSLint和更漂亮的配置测试兼容:{“proseWrap”:“始终”、“半”:false、“单引号”:true、“trailingComma”:“es5”}
:
class LocalStorageMock {
public store: {
[key: string]: string
}
constructor() {
this.store = {}
}
public clear() {
this.store = {}
}
public getItem(key: string) {
return this.store[key] || undefined
}
public setItem(key: string, value: string) {
this.store[key] = value.toString()
}
public removeItem(key: string) {
delete this.store[key]
}
}
/* tslint:disable-next-line:no-any */
;(global as any).localStorage = new LocalStorageMock()
HT/了解如何更新global.localStorage
describe('getToken', () => {
const Auth = new AuthService();
const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Ik1yIEpvc2VwaCIsImlkIjoiNWQwYjk1Mzg2NTVhOTQ0ZjA0NjE5ZTA5IiwiZW1haWwiOiJ0cmV2X2pvc0Bob3RtYWlsLmNvbSIsInByb2ZpbGVVc2VybmFtZSI6Ii9tcmpvc2VwaCIsInByb2ZpbGVJbWFnZSI6Ii9Eb3Nlbi10LUdpci1sb29rLWN1dGUtbnVrZWNhdDMxNnMtMzExNzAwNDYtMTI4MC04MDAuanBnIiwiaWF0IjoxNTYyMzE4NDA0LCJleHAiOjE1OTM4NzYwMDR9.YwU15SqHMh1nO51eSa0YsOK-YLlaCx6ijceOKhZfQZc';
beforeEach(() => {
global.localStorage = jest.fn().mockImplementation(() => {
return {
getItem: jest.fn().mockReturnValue(token)
}
});
});
it('should get the token from localStorage', () => {
const result = Auth.getToken();
expect(result).toEqual(token);
});
});
创建一个模拟并将其添加到我从中找到此解决方案的global
objectt
您可以在setupTests中插入此代码,它应该可以正常工作
我在一个项目中使用typesctipt对其进行了测试。要在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 });
然后将以下行添加到Jest配置下的package.json中
“SetupTestFrameworkScript文件”:“指向您的文件的路径”,
或者,您可以在测试用例中导入此文件,以便模拟本地存储。您可以使用此方法,以避免模拟
Storage.prototype.getItem = jest.fn(() => expectedPayload);
您需要用这些代码片段模拟本地存储
//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
});
在笑话中:
"setupFiles":["localStorage.js"]
请随便问任何问题。不幸的是,我在这里找到的解决方案并不适合我
所以我在研究Jest GitHub的问题时发现了这一点
投票最多的解决方案是:
constspy=jest.spyOn(Storage.prototype,'setItem');
//或
Storage.prototype.getItem=jest.fn(()=>bla');
这对我很有效
delete global.localStorage;
global.localStorage = {
getItem: () =>
}
我想我会在TypeScript w/React中添加另一个非常适合我的解决方案:
我创建了一个mockLocalStorage.ts
export const mockLocalStorage=()=>{
const setItemMock=jest.fn();
const getItemMock=jest.fn();
在每个之前(()=>{
Storage.prototype.setItem=setItemMock;
Storage.prototype.getItem=getItemMock;
});
之后(()=>{
setItemMock.mockRestore();
getItemMock.mockRestore();
});
返回{setItemMock,getItemMock};
};
我的组成部分:
export const Component=()=>{
const foo=localStorage.getItem('foo')
返回{foo}
}
然后在我的测试中,我这样使用它:
const setItemSpy = jest.spyOn(Object.getPrototypeOf(window.localStorage), 'setItem');
从“React”导入React;
重要的
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)
})
})