Risposte:
Ottima soluzione di @chiedo
Tuttavia, usiamo la sintassi ES2015 e ho pensato che fosse un po 'più pulito scriverlo in questo modo.
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
il motivo per cui il mio test falliva, perché nel mio test stavo usando not.toBeDefined()
. La soluzione di @Chiedo lo fa funzionare di nuovo
Capito con l'aiuto di questo: https://groups.google.com/forum/#!topic/jestjs/9EPhuNWVYTg
Imposta un file con i seguenti contenuti:
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 });
Quindi aggiungi la seguente riga a package.json sotto le tue configurazioni Jest
"setupTestFrameworkScriptFile":"PATH_TO_YOUR_FILE",
"setupFiles": [...]
funziona pure. Con l'opzione array, consente di separare i mock in file separati. Ad esempio:"setupFiles": ["<rootDir>/__mocks__/localStorageMock.js"]
getItem
differisce leggermente da ciò che verrebbe restituito da un browser se nessun dato viene impostato su una chiave specifica. chiamare getItem("foo")
quando non è impostato, ad esempio, tornerà null
in un browser, ma undefined
con questo finto - questo stava causando il fallimento di uno dei miei test. La soluzione semplice per me era tornare store[key] || null
alla getItem
funzione
localStorage['test'] = '123'; localStorage.getItem('test')
Se si utilizza create -eagire-app, esiste una soluzione più semplice e chiara spiegata nella documentazione .
Crea src/setupTests.js
e inseriscilo:
const localStorageMock = {
getItem: jest.fn(),
setItem: jest.fn(),
clear: jest.fn()
};
global.localStorage = localStorageMock;
Contributo di Tom Mertz in un commento qui sotto:
È quindi possibile verificare che le funzioni di localStorageMock vengano utilizzate facendo qualcosa di simile
expect(localStorage.getItem).toBeCalledWith('token')
// or
expect(localStorage.getItem.mock.calls.length).toBe(1)
all'interno dei tuoi test se volevi assicurarti che fosse chiamato. Dai un'occhiata a https://facebook.github.io/jest/docs/en/mock-functions.html
localStorage
che usi nel tuo codice. (se usi create-react-app
e tutti gli script automatici che fornisce naturalmente)
expect(localStorage.getItem).toBeCalledWith('token')
o expect(localStorage.getItem.mock.calls.length).toBe(1)
all'interno dei test se si desidera assicurarsi che sia stato chiamato. Dai un'occhiata a facebook.github.io/jest/docs/en/mock-functions.html
localStorage
? Non vorresti resettare le spie dopo ogni test per impedire "spillover" in altri test?
Attualmente (ottobre '19) localStorage non può essere deriso o spiato per scherzo come faresti di solito, e come indicato nei documenti di create-reagire-app. Ciò è dovuto alle modifiche apportate a jsdom. Puoi leggerlo nei tracker dei problemi jest e jsdom .
Per ovviare al problema, puoi invece spiare il prototipo:
// 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');
o prendi semplicemente un pacchetto simulato come questo:
https://www.npmjs.com/package/jest-localstorage-mock
gestisce non solo la funzionalità di archiviazione ma consente anche di verificare se l'archivio è stato effettivamente chiamato.
Un'alternativa migliore che gestisce i undefined
valori (non ha toString()
) e restituisce null
se il valore non esiste. react
Ho provato questo con v15 redux
eredux-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
Se stai cercando un finto e non uno stub, ecco la soluzione che uso:
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
Esporto gli elementi di archiviazione per una facile inizializzazione. IE, posso facilmente impostarlo su un oggetto
Nelle versioni più recenti di Jest + JSDom non è possibile impostare questo, ma il deposito locale è già disponibile e puoi spiarlo in questo modo:
const setItemSpy = jest.spyOn(Object.getPrototypeOf(window.localStorage), 'setItem');
Ho trovato questa soluzione da 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
});
Puoi inserire questo codice nei tuoi setupTest e dovrebbe funzionare bene.
L'ho provato in un progetto con typesctipt.
Sfortunatamente, le soluzioni che ho trovato qui non hanno funzionato per me.
Quindi stavo guardando i problemi di Jest GitHub e ho trovato questo thread
Le soluzioni più votate erano queste:
const spy = jest.spyOn(Storage.prototype, 'setItem');
// or
Storage.prototype.getItem = jest.fn(() => 'bla');
window
né Storage
definito. Forse è la versione precedente di Jest che sto usando.
Come suggerito da @ ck4, la documentazione ha una chiara spiegazione per l'uso localStorage
in jest. Tuttavia, le funzioni simulate non riuscivano a eseguire nessuno dei localStorage
metodi.
Di seguito è riportato l'esempio dettagliato del mio componente di reazione che utilizza metodi astratti per scrivere e leggere dati,
//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 };
Errore:
TypeError: _setupLocalStorage2.default.setItem is not a function
Fix:
Aggiungere di seguito la funzione finto per scherzo (percorso: .jest/mocks/setUpStore.js
)
let mockStorage = {};
module.exports = window.localStorage = {
setItem: (key, val) => Object.assign(mockStorage, {[key]: val}),
getItem: (key) => mockStorage[key],
clear: () => mockStorage = {}
};
Lo snippet è referenziato da qui
Ho trovato alcune altre risposte qui per risolverlo per un progetto con Typescript. Ho creato un LocalStorageMock in questo modo:
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]
}
}
Quindi ho creato una classe LocalStorageWrapper che utilizzo per tutto l'accesso all'archiviazione locale nell'app invece di accedere direttamente alla variabile di archiviazione locale globale. Ha reso facile impostare il finto nell'involucro per i test.
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);
});
});
Crea un finto e aggiungilo global
all'oggetto
Devi deridere l'archiviazione locale con questi frammenti
// 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
});
E nella jest config:
"setupFiles":["localStorage.js"]
Sentiti libero di chiedere qualsiasi cosa .
La seguente soluzione è compatibile per i test con TypeScript, ESLint, TSLint e Prettier più severi { "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 per come aggiornare global.localStorage
Per fare lo stesso nel dattiloscritto, procedi come segue:
Imposta un file con i seguenti contenuti:
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 });
Quindi aggiungi la seguente riga a package.json sotto le tue configurazioni Jest
"setupTestFrameworkScriptFile":"PATH_TO_YOUR_FILE",
Oppure si importa questo file nel test case in cui si desidera deridere il deposito locale.
value + ''
nel setter per gestire correttamente i valori null e indefiniti