アプリケーションコードが_location.href = "some-url"
_を呼び出しています。ナビゲーションリダイレクトが発生したことを確認するテストを記述したいと思います。
Jsdomでjestを使用して、jest mock関数を使用してlocation.hrefセッターをオーバーライドしてそれを実行しようとしましたが、機能しています。
しかし、今はテストのクリーンアップでlocation.hrefプロパティを復元できないようで、 'location.href'を中継する残りのテストは失敗します。
_it('test navigation happened', () => {
const originalLocationHref = Object.getOwnPropertyDescriptor(window.location, 'href'); // returns undefined
spyFn = jest.fn();
Object.defineProperty(window.location, 'href', {
set: spyFn,
enumerable: true,
configurable: true
});
someAppCodeThatShouldRedirectToSomeUrl();
expect(spyFn).toBeCalledWith('http://some-url'); // this is working
// Cleanup code, not working, because originalLocationHref is undefined
Object.defineProperty(window.location, 'href', originalLocationHref);
});
_
何が欠けていますか? Object.getOwnPropertyDescriptor(window.location, 'href');
がundefined
である理由
ナビゲーションイベントをインターセプトしてテストするより良い方法はありますか?
ありがとう
新しい場所の文字列をlocation.hrefに割り当てる代わりに、 location.assign() メソッドを使用してください。次に、問題なくモックしてテストできます。
it('test navigation happened', () => {
window.location.assign = jest.fn();
// here you call location.assign('http://some-url');
redirectToSomeUrl();
expect(window.location.assign).toBeCalledWith('http://some-url');
// location.href hasn't changed because location.assign was mocked
});
QuotesBroがすでに説明したように 彼の答え なので、むしろ location.assign() を使用する必要があります。
しかし、Jest v25(新しいバージョンのJSDOMを使用)以降、次のエラーが発生します。
TypeError: Cannot assign to read only property 'assign' of object '[object Location]'
ちなみにこれはJest/JSDOMのバグではありません。これは通常のブラウザの動作であり、JSDOMは実際のブラウザのように動作しようとします。
回避策は、ロケーションオブジェクトを削除して独自のロケーションオブジェクトを作成し、テストを実行した後、それを元のロケーションオブジェクトにリセットする必要があります。
describe('My awesome unit test', () => {
// we need to save the original object for later to not affect tests from other files
const realLocation = window.location
beforeAll(() => {
delete window.location
window.location = { assign: jest.fn() }
// or even like this if you are also using other location properties (or if TypeScript complains):
// window.location = { ...realLocation, assign: jest.fn() }
})
afterAll(() => {
window.location = realLocation
})
it('should call location.assign', () => {
// ...your test code
expect(window.location.assign).toHaveBeenCalled()
// or even better:
// expect(window.location.assign).toHaveBeenCalledWith('/my_link')
})
})