Antworten:
Tolle Lösung von @chiedo
Wir verwenden jedoch die ES2015-Syntax und ich fand es etwas sauberer, sie so zu schreiben.
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
deshalb schlug mein Test fehl, weil ich in meinem Test benutzte not.toBeDefined()
. @ Chiedo Lösung machen es wieder funktionieren
Ich habe es mit Hilfe davon herausgefunden: https://groups.google.com/forum/#!topic/jestjs/9EPhuNWVYTg
Richten Sie eine Datei mit folgendem Inhalt ein:
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 });
Anschließend fügen Sie Ihrer package.json unter Ihren Jest-Konfigurationen die folgende Zeile hinzu
"setupTestFrameworkScriptFile":"PATH_TO_YOUR_FILE",
"setupFiles": [...]
funktioniert auch. Ermöglicht mit der Array-Option das Trennen von Mocks in separate Dateien. ZB:"setupFiles": ["<rootDir>/__mocks__/localStorageMock.js"]
getItem
unterscheidet sich geringfügig von dem, der von einem Browser zurückgegeben wird, wenn für einen bestimmten Schlüssel keine Daten festgelegt werden. Ein Aufruf, getItem("foo")
wenn er nicht festgelegt ist, wird beispielsweise null
in einem Browser zurückgegeben, aber undefined
durch dieses Modell hat dies dazu geführt, dass einer meiner Tests fehlgeschlagen ist. Eine einfache Lösung für mich war, store[key] || null
in die getItem
Funktion zurückzukehren
localStorage['test'] = '123'; localStorage.getItem('test')
Bei Verwendung der Create-React-App wird in der Dokumentation eine einfachere und unkompliziertere Lösung erläutert .
Erstellen Sie dies src/setupTests.js
und fügen Sie es ein:
const localStorageMock = {
getItem: jest.fn(),
setItem: jest.fn(),
clear: jest.fn()
};
global.localStorage = localStorageMock;
Tom Mertz Beitrag in einem Kommentar unten:
Sie können dann testen, ob die Funktionen Ihres localStorageMock verwendet werden, indem Sie Folgendes tun
expect(localStorage.getItem).toBeCalledWith('token')
// or
expect(localStorage.getItem.mock.calls.length).toBe(1)
innerhalb Ihrer Tests, wenn Sie sicherstellen wollten, dass es aufgerufen wurde. Überprüfen Sie https://facebook.github.io/jest/docs/en/mock-functions.html
localStorage
Sie in Ihrem Code verwenden. (Wenn Sie create-react-app
alle automatischen Skripte verwenden, die es natürlich bereitstellt)
expect(localStorage.getItem).toBeCalledWith('token')
oder expect(localStorage.getItem.mock.calls.length).toBe(1)
innerhalb Ihrer Tests ausführen , wenn Sie sicherstellen möchten , dass es aufgerufen wurde. Überprüfen Sie facebook.github.io/jest/docs/en/mock-functions.html
localStorage
? Möchten Sie die Spione nicht nach jedem Test zurücksetzen, um ein "Überlaufen" in andere Tests zu verhindern?
Derzeit (19. Oktober) kann localStorage nicht wie gewohnt und in den Dokumenten zum Erstellen und Reagieren von Apps verspottet oder ausspioniert werden. Dies ist auf Änderungen in jsdom zurückzuführen. Sie können darüber im Scherz und in jsdom lesen Issue Tracker .
Um dieses Problem zu umgehen, können Sie stattdessen den Prototyp ausspionieren:
// 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');
oder du nimmst einfach ein Scheinpaket wie dieses:
https://www.npmjs.com/package/jest-localstorage-mock
Es verwaltet nicht nur die Speicherfunktionalität, sondern ermöglicht Ihnen auch zu testen, ob der Speicher tatsächlich aufgerufen wurde.
Eine bessere Alternative, die undefined
Werte verarbeitet (nicht vorhanden toString()
) und zurückgibt, null
wenn kein Wert vorhanden ist. Getestet mit react
v15 redux
undredux-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
Wenn Sie nach einem Mock und nicht nach einem Stub suchen, ist hier die Lösung, die ich verwende:
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
Ich exportiere die Speicherelemente zur einfachen Initialisierung. IE Ich kann es leicht auf ein Objekt setzen
In den neueren Versionen von Jest + JSDom ist es nicht möglich, dies festzulegen, aber der lokale Speicher ist bereits verfügbar und Sie können ihn wie folgt ausspionieren:
const setItemSpy = jest.spyOn(Object.getPrototypeOf(window.localStorage), 'setItem');
Ich habe diese Lösung von Github gefunden
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
});
Sie können diesen Code in Ihre setupTests einfügen und er sollte einwandfrei funktionieren.
Ich habe es in einem Projekt mit Typoskript getestet.
Leider haben die Lösungen, die ich hier gefunden habe, bei mir nicht funktioniert.
Also habe ich mir Jest GitHub-Probleme angesehen und diesen Thread gefunden
Die am besten bewerteten Lösungen waren diese:
const spy = jest.spyOn(Storage.prototype, 'setItem');
// or
Storage.prototype.getItem = jest.fn(() => 'bla');
window
oder haben auch nicht Storage
definiert. Vielleicht ist es die ältere Version von Jest, die ich benutze.
Wie in @ ck4 vorgeschlagen, enthält die Dokumentation eine klare Erklärung für die Verwendung localStorage
im Scherz. Die Scheinfunktionen konnten jedoch keine der folgenden Funktionen ausführenlocalStorage
Methoden .
Unten ist das detaillierte Beispiel meiner Reaktionskomponente, die abstrakte Methoden zum Schreiben und Lesen von Daten verwendet.
//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 };
Error:
TypeError: _setupLocalStorage2.default.setItem is not a function
Fix:
In unter Mock - Funktion für Scherz (Pfad: .jest/mocks/setUpStore.js
)
let mockStorage = {};
module.exports = window.localStorage = {
setItem: (key, val) => Object.assign(mockStorage, {[key]: val}),
getItem: (key) => mockStorage[key],
clear: () => mockStorage = {}
};
Von hier aus wird auf das Snippet verwiesen
Hier wurden einige andere Antworten abgefragt, um sie für ein Projekt mit Typescript zu lösen. Ich habe einen LocalStorageMock wie folgt erstellt:
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]
}
}
Dann habe ich eine LocalStorageWrapper-Klasse erstellt, die ich für den gesamten Zugriff auf den lokalen Speicher in der App verwende, anstatt direkt auf die globale lokale Speichervariable zuzugreifen. Es war einfach, den Mock für Tests in den Wrapper zu setzen.
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);
});
});
Erstellen Sie ein global
Modell und fügen Sie es dem Objekt hinzu
Sie müssen den lokalen Speicher mit diesen Snippets verspotten
// 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
});
Und in der Scherzkonfiguration:
"setupFiles":["localStorage.js"]
Fühlen Sie sich frei, etwas zu fragen.
Die folgende Lösung ist kompatibel zum Testen mit strengerer Maschinenschrift, ESLint, TSLint und Prettier config: { "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 zum Aktualisieren von global.localStorage
Gehen Sie wie folgt vor, um dasselbe im Typoskript zu tun:
Richten Sie eine Datei mit folgendem Inhalt ein:
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 });
Anschließend fügen Sie Ihrer package.json unter Ihren Jest-Konfigurationen die folgende Zeile hinzu
"setupTestFrameworkScriptFile":"PATH_TO_YOUR_FILE",
Oder Sie importieren diese Datei in Ihren Testfall, in dem Sie den lokalen Speicher verspotten möchten.
value + ''
im Setter tun , um null und undefinierte Werte korrekt zu behandeln