概要
window.location.href
に新しいパスを渡してリダイレクト処理等を行う場合がある。その際にJest等でテストを書きたいがMockの仕方に詰まったのでメモとして残す。
window.locationとは
JavaScriptのグローバル変数であるwindow
の読み取り専用プロパティの1つです。documentの現在位置についてのLocation
オブジェクトを返します。
以下のようにブラウザ上での現在の位置情報やhostname、プロトコルなどが参照できます。
> JSON.stringify(location)
'{
"ancestorOrigins":{},
"href":"https://developer.mozilla.org/ja/docs/Web/API/Window/location",
"origin":"https://developer.mozilla.org",
"protocol":"https:",
"host":"developer.mozilla.org",
"hostname":"developer.mozilla.org",
"port":"",
"pathname":"/ja/docs/Web/API/Window/location",
"search":"",
"hash":""
}'
Object.defineProperty()について
静的メソッドの Object.defineProperty() は、あるオブジェクトに新しいプロパティを直接定義したり、オブジェクトの既存のプロパティを変更したりして、そのオブジェクトを返します。
この Object.defineProperty()
を使用することで、テストを書く際にlocationオブジェクトをモックとして新しく定義することができます。
また、オプションキーに writable
というキーがあり、これをtrue
にすることでテストごとにモックの値を変えることができるようになります。(※ これがfalse
の場合は値が代入変更できず、最初に定義したものが使用されることになります。)
実際にテストを書いてみる
- テスト対象
テスト対象は、hostがexample.com
であればwww.google.com
にリダイレクトする関数とします。
const redirectFromExample = () => {
const { hostname, search } = window.location;
const redirectHostname = hostname === 'example.com' ? 'www.google.com' : hostname;
window.location.href = `//${redirectHostname}${search}`;
};
export { redirectFromExample };
beforeEach
でwritable
なwindow.locationオブジェクトを定義して、各テストでlocationオブジェクトをモックします。
const { redirectFromExample } = require('../redirectFromExample');
describe('redirectFromExample', () => {
beforeEach(() => {
Object.defineProperty(window, 'location', {
value: {
href: '',
pathname: '/',
search: '',
hostname: '',
},
writable: true,
});
});
it('redirect to google.com from example', () => {
global.window = Object.create(window);
Object.defineProperty(window, 'location', {
value: {
href: 'https://example.com/',
pathname: '/',
search: '',
hostname: 'example.com',
},
});
redirectFromExample();
expect(window.location.href).toEqual('//www.google.com');
});
it('not redirect to google.com', () => {
global.window = Object.create(window);
Object.defineProperty(window, 'location', {
value: {
href: 'https://www.yahoo.jp/',
pathname: '/',
search: '?hoge=text',
hostname: 'www.yahoo.jp',
},
});
redirectFromExample();
expect(window.location.href).toEqual('//www.yahoo.jp?hoge=text');
});
});
テストを実行するとredirectFromExample()
メソッドで書き換えられたlocationオブジェクトについてテストできていることがわかります。
PASS src/shared/utils/helpers/__tests__/redirectFromExample.test.js
redirectFromExample
✓ redirect to google.com from example
✓ not redirect to google.com
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 0.219s, estimated 1s
Ran all test suites matching /redirectFromExample/i.