在Jest测试中,我一直得到“localStorage is not defined”,这是有意义的,但我的选项是什么?碰壁。
当前回答
首先,我创建了一个名为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');
});
});
});
其他回答
对于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);
}
以下解决方案兼容更严格的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和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)
})
})
不需要模拟localStorage—只需使用jsdom环境,这样您的测试就可以在类似浏览器的条件下运行。
在你的joke。config。js中,
module.exports = {
// ...
testEnvironment: "jsdom"
}
这对我很有效,
delete global.localStorage;
global.localStorage = {
getItem: () =>
}