Answers:
来自的绝佳解决方案 @chiedo的
但是,我们使用ES2015语法,所以我觉得用这种方式编写它要干净一些。
class LocalStorageMock {
constructor() {
this.store = {};
}
clear() {
this.store = {};
}
getItem(key) {
return this.store[key] || null;
}
setItem(key, value) {
this.store[key] = value.toString();
}
removeItem(key) {
delete this.store[key];
}
};
global.localStorage = new LocalStorageMock;
|| null
这就是为什么我的测试失败了,因为在我的测试中我正在使用not.toBeDefined()
。@Chiedo解决方案使其再次起作用
在以下帮助下找到了答案:https : //groups.google.com/forum/#!topic/ jestjs/9EPhuNWVYTg
设置具有以下内容的文件:
var localStorageMock = (function() {
var store = {};
return {
getItem: function(key) {
return store[key];
},
setItem: function(key, value) {
store[key] = value.toString();
},
clear: function() {
store = {};
},
removeItem: function(key) {
delete store[key];
}
};
})();
Object.defineProperty(window, 'localStorage', { value: localStorageMock });
然后将以下行添加到Jest配置下的package.json中
"setupTestFrameworkScriptFile":"PATH_TO_YOUR_FILE",
"setupFiles": [...]
也可以。使用array选项,可以将模拟文件分离到单独的文件中。例如:"setupFiles": ["<rootDir>/__mocks__/localStorageMock.js"]
getItem
如果未针对特定键设置任何数据,则返回值与浏览器返回的值略有不同。getItem("foo")
例如,当未设置时调用会null
在浏览器中返回,但是undefined
通过这种模拟-这导致我的测试之一失败。对我来说,简单的解决方案是返回store[key] || null
该getItem
函数
localStorage['test'] = '123'; localStorage.getItem('test')
如果使用create-react-app,则文档中介绍了一个更简单明了的解决方案。
创建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)
如果您想确保它被调用,请在测试中进行。查看https://facebook.github.io/jest/docs/en/mock-functions.html
localStorage
您在代码中使用的内容。(如果您使用create-react-app
它自然提供的所有自动脚本)
expect(localStorage.getItem).toBeCalledWith('token')
或expect(localStorage.getItem.mock.calls.length).toBe(1)
内部的操作来测试其是否已使用。看看facebook.github.io/jest/docs/en/mock-functions.html
localStorage
吗?您是否不想在每次测试后重置间谍以防止“溢出”到其他测试中?
当前(19年10月)不能像平常那样,以开玩笑的方式嘲笑或监视localStorage,正如create-react-app文档中所述。这是由于jsdom中所做的更改。您可以在玩笑和jsdom中阅读有关它的信息问题跟踪器中。
作为解决方法,您可以监视原型:
// does not work:
jest.spyOn(localStorage, "setItem");
localStorage.setItem = jest.fn();
// works:
jest.spyOn(window.localStorage.__proto__, 'setItem');
window.localStorage.__proto__.setItem = jest.fn();
// assertions as usual:
expect(localStorage.setItem).toHaveBeenCalled();
jest.spyOn(window.localStorage.__proto__, 'setItem');
一个更好的替代方法,可以处理undefined
值(不包含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
removeItem
:developer.mozilla.org/en-US/docs/Web/API/Storage/removeItem
如果您正在寻找模拟而不是存根,这是我使用的解决方案:
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
我导出存储项目以便于初始化。IE浏览器,我可以轻松地将其设置为对象
在Jest + JSm的较新版本中,无法进行设置,但是localstorage已经可用,您可以像这样监视它:
const setItemSpy = jest.spyOn(Object.getPrototypeOf(window.localStorage), 'setItem');
我从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中,并且应该可以正常工作。
我在一个带有typectipt的项目中对其进行了测试。
正如@ 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/mocks/setUpStore.js
)
let mockStorage = {};
module.exports = window.localStorage = {
setItem: (key, val) => Object.assign(mockStorage, {[key]: val}),
getItem: (key) => mockStorage[key],
clear: () => mockStorage = {}
};
从此处引用代码段
在这里找到其他答案,以解决带有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类,该类用于所有对应用程序中本地存储的访问,而不是直接访问全局本地存储变量。轻松在包装器中设置模拟以进行测试。
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
对象
您需要使用此代码段模拟本地存储
// 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"]
随便问什么。
以下解决方案兼容使用更严格的TypeScript,ESLint,TSLint和Prettier配置进行测试{ "proseWrap": "always", "semi": false, "singleQuote": 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 / https://stackoverflow.com/a/51583401/101290了解如何更新global.localStorage
要在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中
"setupTestFrameworkScriptFile":"PATH_TO_YOUR_FILE",
或者,您可以在要模拟本地存储的测试用例中导入此文件。
value + ''
在setter中正确地处理null和undefined值