在Jest测试中,我一直得到“localStorage is not defined”,这是有意义的,但我的选项是什么?碰壁。
当前回答
这对我来说是可行的,只需要一行代码
const setItem = jest.spyOn(Object.getPrototypeOf(localStorage), 'setItem');
其他回答
2022年12月:Nx 14使用Angular 14 Jest。 我们有一个测试设置。Ts文件在每个app和libs文件夹。我们设置本地存储模拟全局。
import 'jest-preset-angular/setup-jest';
Storage.prototype.getItem = jest.fn();
Storage.prototype.setItem = jest.fn();
Storage.prototype.removeItem = jest.fn();
然后localStorage.service.spec.ts文件如下所示:
import { LocalStorageService } from './localstorage.service';
describe('LocalStorageService', () => {
let localStorageService: LocalStorageService;
beforeEach(() => {
localStorageService = new LocalStorageService();
});
it('should set "identityKey" in localStorage', async () => {
localStorageService.saveData('identityKey', '99');
expect(window.localStorage.setItem).toHaveBeenCalled();
expect(window.localStorage.setItem).toHaveBeenCalledWith('identityKey', '99');
expect(window.localStorage.setItem).toHaveBeenCalledTimes(1);
});
it('should get "identityKey" from localStorage', async () => {
localStorageService.getData('identityKey');
expect(window.localStorage.getItem).toHaveBeenCalled();
expect(window.localStorage.getItem).toHaveBeenCalledWith('identityKey');
expect(window.localStorage.getItem).toHaveBeenCalledTimes(1);
});
it('should remove "identityKey" from localStorage', async () => {
localStorageService.removeData('identityKey');
expect(window.localStorage.removeItem).toHaveBeenCalled();
expect(window.localStorage.removeItem).toHaveBeenCalledWith('identityKey');
expect(window.localStorage.removeItem).toHaveBeenCalledTimes(1);
});
});
注:不好意思,这个SatckOverflow窗口很糟糕。
@chiedo的好解决方案
然而,我们使用ES2015语法,我觉得这样写会更简洁一些。
class LocalStorageMock {
constructor() {
this.store = {};
}
clear() {
this.store = {};
}
getItem(key) {
return this.store[key] || null;
}
setItem(key, value) {
this.store[key] = String(value);
}
removeItem(key) {
delete this.store[key];
}
}
global.localStorage = new LocalStorageMock;
如果使用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
答:
目前(7月22日)localStorage不能像你通常会被嘲笑或监视,并在创建-反应-应用程序文档中概述。这是由于jsdom中所做的更改。你可以在jest和jsdom问题跟踪器中读到它。
作为一种变通方法,你可以监视原型:
// does not work:
jest.spyOn(localStorage, "setItem");
localStorage.setItem = jest.fn();
// either of these lines will work, different syntax that does the same thing:
jest.spyOn(Storage.prototype, 'setItem');
Storage.prototype.setItem = jest.fn();
// assertions as usual:
expect(localStorage.setItem).toHaveBeenCalled();
关于监视原型机的注意事项:
监视实例使您能够观察和模拟特定对象的行为。
另一方面,监视原型,将同时观察/操作该类的每个实例。除非您有一个特殊的用例,否则这可能不是您想要的。
但是,在本例中没有区别,因为localStorage只存在一个实例。
对于Jest, React和TypeScript用户:
我创建了一个mockLocalStorage.ts
export const mockLocalStorage = () => {
const setItemMock = jest.fn();
const getItemMock = jest.fn();
beforeEach(() => {
Storage.prototype.setItem = setItemMock;
Storage.prototype.getItem = getItemMock;
});
afterEach(() => {
setItemMock.mockRestore();
getItemMock.mockRestore();
});
return { setItemMock, getItemMock };
};
我的组件:
export const Component = () => {
const foo = localStorage.getItem('foo')
localStorage.setItem('bar', 'true')
return <h1>{foo}</h1>
}
然后在我的测试中,我这样使用它:
import React from 'react';
import { mockLocalStorage } from '../../test-utils';
import { Component } from './Component';
const { getItemMock, setItemMock } = mockLocalStorage();
it('fetches something from localStorage', () => {
getItemMock.mockReturnValue('bar');
render(<Component />);
expect(getItemMock).toHaveBeenCalled();
expect(getByText(/bar/i)).toBeInTheDocument()
});
it('expects something to be set in localStorage' () => {
const value = "true"
const key = "bar"
render(<Component />);
expect(setItemMock).toHaveBeenCalledWith(key, value);
}
推荐文章
- 我如何使用Jest模拟JavaScript的“窗口”对象?
- 如何重置笑话模拟函数调用计数之前,每次测试
- 在单元测试中禁用控制台的更好方法
- 如何在单个测试基础上更改模拟实现?
- 如何处理玩笑测试中的localStorage ?
- 如何使用Jest测试对象键和值是否相等?
- 如何清除笑话缓存?
- 如何解决“不能在模块外使用导入语句”在开玩笑
- 如何使用Jest获得代码覆盖率报告?
- Console.log语句在Jest中不输出任何内容
- 测试过程。环境与玩笑
- 如何按顺序运行Jest测试?
- 如何在Jest中设置模拟约会?
- 如何使用jest和react-testing-library测试元素是否不存在?
- 如何使用ESLint与Jest