在Jest测试中,我一直得到“localStorage is not defined”,这是有意义的,但我的选项是什么?碰壁。
当前回答
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);
});
});
创建一个模拟并将其添加到全局对象
其他回答
一个更好的替代方法,它处理未定义的值(它不需要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.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');
});
});
});
在这里引用了一些其他的答案来解决一个用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类,我使用它来访问应用程序中的所有本地存储,而不是直接访问全局本地存储变量。便于在包装器中为测试设置模拟。
正如Niket Pathak在评论中提到的, 从jest@24 / jsdom@11.12.0及以上开始,localStorage将自动被模拟。
一个使用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)
})
})
推荐文章
- 我如何使用Jest模拟JavaScript的“窗口”对象?
- 如何重置笑话模拟函数调用计数之前,每次测试
- 在单元测试中禁用控制台的更好方法
- 如何在单个测试基础上更改模拟实现?
- 如何处理玩笑测试中的localStorage ?
- 如何使用Jest测试对象键和值是否相等?
- 如何清除笑话缓存?
- 如何解决“不能在模块外使用导入语句”在开玩笑
- 如何使用Jest获得代码覆盖率报告?
- Console.log语句在Jest中不输出任何内容
- 测试过程。环境与玩笑
- 如何按顺序运行Jest测试?
- 如何在Jest中设置模拟约会?
- 如何使用jest和react-testing-library测试元素是否不存在?
- 如何使用ESLint与Jest