Jestテストで「localStorageが定義されていません」と表示されるのは理にかなっていますが、私のオプションは何ですか?レンガの壁を打つ。
@ 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;
これの助けを借りてそれを理解しました: 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 });
次に、Jest configsの下のpackage.jsonに次の行を追加します
"setupTestFrameworkScriptFile":"PATH_TO_YOUR_FILE",
Create-react-appを使用する場合は、 documentation で説明されているよりシンプルで簡単なソリューションがあります。
src/setupTests.js
を作成して、これを入れます:
const localStorageMock = {
getItem: jest.fn(),
setItem: jest.fn(),
clear: jest.fn()
};
global.localStorage = localStorageMock;
以下のコメントでのTom Mertzの貢献:
次に、次のようなことを行うことで、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
または、次のような模擬パッケージを使用します。
https://www.npmjs.com/package/jest-localstorage-mock
ストレージ機能だけでなく、ストアが実際に呼び出されたかどうかをテストすることもできます。
現在(Jan '19)localStorageは、通常のように、またcreate-react-app docsで概説されているように、jestによってモックやスパイを行うことはできません。これは、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();
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
@ ck4が示唆したように、 documentation にはjestでlocalStorage
を使用するための明確な説明があります。ただし、モック関数はlocalStorage
メソッドのいずれかを実行できませんでした。
以下は、データの書き込みと読み取りに抽象メソッドを使用する私のreactコンポーネントの詳細な例です。
//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
修正:
jestの下にモック関数を追加(パス:.jest/mocks/setUpStore.js
)
let mockStorage = {};
module.exports = window.localStorage = {
setItem: (key, val) => Object.assign(mockStorage, {[key]: val}),
getItem: (key) => mockStorage[key],
clear: () => mockStorage = {}
};
スニペットは here から参照されます
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クラスを作成しました。テストのラッパーにモックを簡単に設定できるようにしました。
スタブではなくモックを探している場合、私が使用するソリューションは次のとおりです。
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
初期化を簡単にするために、ストレージアイテムをエクスポートします。 I.E.オブジェクトに簡単に設定できます
Jest + JSDomの新しいバージョンでは、これを設定することはできませんが、localstorageはすでに利用可能であり、次のようにスパイすることができます。
const setItemSpy = jest.spyOn(Object.getPrototypeOf(window.localStorage), 'setItem');
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
オブジェクトに追加します
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
});
このコードをsetupTestsに挿入すると、正常に機能するはずです。
Typesctiptを使用したプロジェクトでテストしました。
Storageオブジェクトのプロトタイプをスパイする必要があります。
const spy = jest.spyOn(Storage.prototype, 'getItem');
そしてその後、次のように主張します:
expect(spy).toHaveBeenCalledWith(somevalue);
次のソリューションは、より厳密なTypeScript、ESLint、TSLint、および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/10129 global.localStorageの更新方法