Réponses:
Excellente solution de @chiedo
Cependant, nous utilisons la syntaxe ES2015 et j'ai trouvé que c'était un peu plus propre de l'écrire de cette façon.
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
c'est pourquoi mon test a échoué, car dans mon test, j'utilisais not.toBeDefined()
. Solution @Chiedo le faire fonctionner à nouveau
Je l'ai compris avec l'aide de ceci: https://groups.google.com/forum/#!topic/jestjs/9EPhuNWVYTg
Configurez un fichier avec le contenu suivant:
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 });
Ensuite, vous ajoutez la ligne suivante à votre package.json sous vos configs Jest
"setupTestFrameworkScriptFile":"PATH_TO_YOUR_FILE",
"setupFiles": [...]
fonctionne aussi bien. Avec l'option array, permet de séparer les simulacres en fichiers séparés. Ex:"setupFiles": ["<rootDir>/__mocks__/localStorageMock.js"]
getItem
diffère légèrement de ce qui serait renvoyé par un navigateur si aucune donnée n'est définie sur une clé spécifique. appeler getItem("foo")
quand il n'est pas défini retournera par exemple null
dans un navigateur, mais undefined
par ce simulacre - cela provoquait l'échec d'un de mes tests. La solution simple pour moi était de revenir store[key] || null
dans la getItem
fonction
localStorage['test'] = '123'; localStorage.getItem('test')
Si vous utilisez create-react-app, il existe une solution plus simple et directe expliquée dans la documentation .
Créez src/setupTests.js
et mettez-y ceci:
const localStorageMock = {
getItem: jest.fn(),
setItem: jest.fn(),
clear: jest.fn()
};
global.localStorage = localStorageMock;
Contribution de Tom Mertz dans un commentaire ci-dessous:
Vous pouvez ensuite tester que les fonctions de votre localStorageMock sont utilisées en faisant quelque chose comme
expect(localStorage.getItem).toBeCalledWith('token')
// or
expect(localStorage.getItem.mock.calls.length).toBe(1)
à l'intérieur de vos tests si vous vouliez vous assurer qu'il a été appelé. Découvrez https://facebook.github.io/jest/docs/en/mock-functions.html
localStorage
vous utilisez dans votre code. (si vous utilisez create-react-app
et tous les scripts automatiques qu'il fournit naturellement)
expect(localStorage.getItem).toBeCalledWith('token')
ou à l' expect(localStorage.getItem.mock.calls.length).toBe(1)
intérieur de vos tests si vous vouliez vous assurer qu'il a été appelé. Découvrez facebook.github.io/jest/docs/en/mock-functions.html
localStorage
? Ne voudriez-vous pas réinitialiser les espions après chaque test pour éviter un «débordement» dans d'autres tests?
Actuellement (octobre 19) localStorage ne peut pas être ridiculisé ou espionné par plaisanterie comme vous le feriez habituellement, et comme indiqué dans la documentation de create-react-app. Cela est dû aux modifications apportées à jsdom. Vous pouvez en savoir plus dans le trackers de problèmes jest et jsdom .
Pour contourner le problème, vous pouvez à la place espionner le prototype:
// 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');
ou vous prenez simplement un faux paquet comme celui-ci:
https://www.npmjs.com/package/jest-localstorage-mock
il gère non seulement la fonctionnalité de stockage, mais vous permet également de tester si le magasin a été réellement appelé.
Une meilleure alternative qui gère les undefined
valeurs (elle n'a pas toString()
) et retourne null
si la valeur n'existe pas. Testé ceci avec la react
v15, redux
etredux-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
Si vous recherchez une maquette et non un talon, voici la solution que j'utilise:
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
J'exporte les éléments de stockage pour une initialisation facile. IE je peux facilement le définir sur un objet
Dans les nouvelles versions de Jest + JSDom, il n'est pas possible de définir cela, mais le stockage local est déjà disponible et vous pouvez l'espionner comme ceci:
const setItemSpy = jest.spyOn(Object.getPrototypeOf(window.localStorage), 'setItem');
J'ai trouvé cette solution de 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
});
Vous pouvez insérer ce code dans vos setupTests et cela devrait fonctionner correctement.
Je l'ai testé dans un projet avec typesctipt.
Malheureusement, les solutions que j'ai trouvées ici n'ont pas fonctionné pour moi.
Donc, je regardais les problèmes de Jest GitHub et j'ai trouvé ce fil
Les solutions les plus appréciées étaient celles-ci:
const spy = jest.spyOn(Storage.prototype, 'setItem');
// or
Storage.prototype.getItem = jest.fn(() => 'bla');
window
ni Storage
défini ni défini. C'est peut-être l'ancienne version de Jest que j'utilise.
Comme @ ck4 l'a suggéré, la documentation a une explication claire de l'utilisation localStorage
dans jest. Cependant, les fonctions simulées ne parvenaient à exécuter aucune des localStorage
méthodes.
Vous trouverez ci-dessous l'exemple détaillé de mon composant react qui utilise des méthodes abstraites pour écrire et lire des données,
//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 };
Erreur:
TypeError: _setupLocalStorage2.default.setItem is not a function
Correction:
Ajouter ci - dessous pour fonction simulée plaisanterie (chemin: .jest/mocks/setUpStore.js
)
let mockStorage = {};
module.exports = window.localStorage = {
setItem: (key, val) => Object.assign(mockStorage, {[key]: val}),
getItem: (key) => mockStorage[key],
clear: () => mockStorage = {}
};
L'extrait est référencé à partir d' ici
Riffé quelques autres réponses ici pour le résoudre pour un projet avec Typescript. J'ai créé un LocalStorageMock comme ceci:
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]
}
}
Ensuite, j'ai créé une classe LocalStorageWrapper que j'utilise pour tous les accès au stockage local dans l'application au lieu d'accéder directement à la variable de stockage local globale. Facilité de mise en place de la maquette dans l'emballage pour les tests.
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);
});
});
Créez une maquette et ajoutez-la à l' global
objet
Vous devez simuler le stockage local avec ces extraits
// 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
});
Et dans la configuration de plaisanterie:
"setupFiles":["localStorage.js"]
N'hésitez pas à demander quoi que ce soit.
La solution suivante est compatible pour les tests avec une configuration TypeScript, ESLint, TSLint et Prettier plus stricte { "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 pour savoir comment mettre à jour global.localStorage
Pour faire la même chose dans le TypeScript, procédez comme suit:
Configurez un fichier avec le contenu suivant:
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 });
Ensuite, vous ajoutez la ligne suivante à votre package.json sous vos configs Jest
"setupTestFrameworkScriptFile":"PATH_TO_YOUR_FILE",
Ou vous importez ce fichier dans votre scénario de test où vous souhaitez simuler le stockage local.
value + ''
dans le setter pour gérer correctement les valeurs nulles et non définies