Я продолжаю получать "localStorage не определено" в тестах Jest, что имеет смысл, но каковы мои варианты? Нанесение кирпичных стен.
Как я могу работать с localStorage в тестах шутки?
Ответ 1
Отличное решение от @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;
Ответ 2
Разобрался с помощью этого: 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 });
Затем вы добавляете следующую строку в свой package.json под вашими конфигами Jest
"setupTestFrameworkScriptFile":"PATH_TO_YOUR_FILE",
Ответ 3
При использовании create-реагировать-приложение есть более простое и понятное решение, объясненное в документации.
Создайте src/setupTests.js
и поместите в него это:
const localStorageMock = {
getItem: jest.fn(),
setItem: jest.fn(),
clear: jest.fn()
};
global.localStorage = localStorageMock;
Вклад Тома Мерца в комментарии ниже:
Затем вы можете проверить, что ваши функции 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
Ответ 4
В настоящее время (январь 19 года) localStorage нельзя шутить или шпионить за шутками, как вы это обычно делаете, и как описано в документации create-реагировать на приложение. Это связано с изменениями, внесенными в JSDOM. Вы можете прочитать об этом здесь https://github.com/facebook/jest/issues/6798 и здесь https://github.com/jsdom/jsdom/issues/2318.
В качестве обходного пути вы можете шпионить за прототипом:
// 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();
Ответ 5
или вы просто возьмите макет пакета, как это:
https://www.npmjs.com/package/jest-localstorage-mock
он обрабатывает не только функциональность хранилища, но и позволяет вам проверить, действительно ли хранилище было вызвано.
Ответ 6
Лучшая альтернатива, которая обрабатывает значения 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
Ответ 7
Поскольку @ck4 предлагает документацию, есть четкое объяснение использования localStorage
в jest. Однако фиктивные функции не выполнялись ни одним из методов localStorage
.
Ниже приведен подробный пример моего компонента реагирования, который использует абстрактные методы для записи и чтения данных,
//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
Fix:
Добавьте ниже макет функции для шутки (путь: .jest/mocks/setUpStore.js
)
let mockStorage = {};
module.exports = window.localStorage = {
setItem: (key, val) => Object.assign(mockStorage, {[key]: val}),
getItem: (key) => mockStorage[key],
clear: () => mockStorage = {}
};
Фрагмент ссылки здесь
Ответ 8
Сбросил некоторые другие ответы здесь, чтобы решить его для проекта с 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, который я использую для доступа к локальному хранилищу в приложении вместо прямого доступа к глобальной локальной переменной хранилища. Легко было установить макет в обертку для тестов.
Ответ 9
Если вы ищете макет, а не заглушку, вот решение, которое я использую:
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 + JSDom это невозможно установить, но локальное хранилище уже доступно, и вы можете следить за ним следующим образом:
const setItemSpy = jest.spyOn(Object.getPrototypeOf(window.localStorage), 'setItem');
Ответ 10
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
объект.
Ответ 11
Я нашел это решение от 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
});
Вы можете вставить этот код в свои установочные тесты, и он должен работать нормально.
Я проверил это в проекте с typesctipt.
Ответ 12
Следующее решение совместимо для тестирования с более строгими конфигурациями 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/fooobar.com/questions/1012562/... для того, как обновить global.localStorage
Ответ 13
Вы должны следить за прототипом объекта Storage.
const spy = jest.spyOn(Storage.prototype, 'getItem');
И после этого утверждать это как:
expect(spy).toHaveBeenCalledWith(somevalue);