カスタムglobalオブジェクトを定義してそれを使うコンポーネントのテスト
例えばこんな感じでhogeProperty
をglobalで定義した
index.html
<script>
window.hogeProperty = {
hogeProp: "hoge",
hogeFn(arg1 = "", arg2 = "") {
console.log(`${arg1}_${arg2}`)
}
};
</script>
globalオブジェクトを使うコンポーネント
useGlobalProperty.tsx
/**
* hogeボタンをクリックすると`hogeProperty`の`hogeFn`を実行するコンポーネント
*/
export default function UseGlobalProperty() {
// globalオブジェクト呼ぶとtsエラー出るので制御
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const { hogeProp, hogeFn } = hogeProperty;
function clickHandler() {
hogeFn(hogeProp, 'bar');
}
return (
<>
<button onClick={clickHandler} type='button'>
{hogeProp}ボタン
</button>
</>
);
}
globalオブジェクトを使うコンポーネントのテストコード
useGlobalProperty.spec.tsx
import { render, screen, fireEvent } from '@testing-library/react';
import UseGlobalProperty from './useGlobalProperty';
describe('UseGlobalProperty', () => {
test('hogeボタンクリック時、hogeFnが実行される', () => {
// NOTE: テスト中のglobalプロパティを定義する
this.global.hogeProperty = {
hogeProp: 'hoge', // ←使わないので書かなくても良い
hogeFn(arg1 = '', arg2 = '') {
console.log(`${arg1}_${arg2}`); // ←使わないので関数の中身は書かなくても良い
},
};
// NOTE: globalオブジェクト呼ぶとtsエラー出るので制御
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const { hogeProperty } = global;
const { hogeProp } = hogeProperty;
// NOTE: hogeFnが呼ばれたかをテストする為にspyOnする
const hogeFnSpy = jest.spyOn(hogeProperty, 'hogeFn');
render(<UseGlobalProperty />);
fireEvent.click(screen.getByText(`hogeボタン`));
// 1回だけ呼ばれたかテスト
expect(hogeFnSpy).toHaveBeenCalledTimes(1);
// 引数が正しいかテスト
expect(hogeFnSpy).toHaveBeenCalledWith('hoge', 'bar');
});
});
document.cookieのテスト
document.cookieに値をセットするコンポーネント
useDocumentCookie.tsx
/**
* setCookieボタンクリックするとcookieに値を設定するコンポーネント
*/
export default function UseDocumentCookie() {
function setCookie(): void {
// eslint-disable-next-line no-restricted-globals
const { hostname } = location;
document.cookie = `hogeKey=anyValue; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/; domain=${hostname}`;
}
return (
<>
<div>
<button onClick={setCookie} type='button'>
setCookieボタン
</button>
</div>
</>
);
}
document.cookieに値をセットするコンポーネントのテストコード
useDocumentCookie.spec.tsx
import { render, screen, fireEvent } from '@testing-library/react';
import UseDocumentCookie from './useDocumentCookie';
describe('UseDocumentCookie', () => {
test('setCookieボタンクリック時、cookieが設定される', () => {
// NOTE: これがないとテスト実行でクッキー書き換えられない
Object.defineProperty(this.global.document, 'cookie', {
writable: true,
});
render(<UseDocumentCookie />);
fireEvent.click(screen.getByText('setCookieボタン'));
const { cookie } = document;
// cookieの値が期待通り設定されたかテスト
expect(cookie).toEqual(
`hogeKey=anyValue; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/; domain=${hostname}`
);
// NOTE: このテストでcookieの値変更されて他のテストにも影響するので戻しておく
Object.defineProperty(document, 'cookie', {
value: undefined,
});
// NOTE: 一応戻す
Object.defineProperty(this.global.document, 'cookie', {
writable: false,
});
});
});
テスト時のglobalオブジェクトの定義はCustomEnvironmentにまとめる
globalプロパティの定義はCustomEnvironmentにまとめた方が可読性とか良さげ
またjest.config.js
のtestEnvironment
がnode
、 特定のテストだけjsdom
環境にする必要がある時とかはCustomEnvironmentを作成する。
custom-js-dom-environment.ts
// eslint-disable-next-line import/no-extraneous-dependencies,import/no-import-module-exports
import JSDOMEnvironment from 'jest-environment-jsdom';
class CustomJSDOMEnvironment extends JSDOMEnvironment {
async setup(): Promise<void> {
await super.setup();
this.global.hogeProperty = {
hogeProp: 'hoge',
hogeFn(arg1 = '', arg2 = '') {
// eslint-disable-next-line no-console
console.log(`${arg1}_${arg2}`);
},
};
Object.defineProperty(this.global.document, 'cookie', {
writable: true,
});
}
async teardown(): Promise<void> {
Object.defineProperty(this.global.document, 'cookie', {
writable: false,
});
await super.teardown();
}
}
module.exports = CustomJSDOMEnvironment;
CustomEnvironmentを使うテストコード
useGlobalProperty.spec.tsx
/**
* @jest-environment ./src/test/custom-js-dom-environment.ts
*/
// ↑ファイルの先頭に記述。custom-js-dom-environment.tsがあるパスを書く
import { render, screen, fireEvent } from '@testing-library/react';
import UseGlobalProperty from './useGlobalProperty';
describe('UseGlobalProperty', () => {
test('hogeボタンクリック時、hogeFnが実行される', () => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const { hogeProperty } = global;
const { hogeProp } = hogeProperty;
const hogeFnSpy = jest.spyOn(hogeProperty, 'hogeFn');
render(<UseGlobalProperty />);
fireEvent.click(screen.getByText(`hogeボタン`));
expect(hogeFnSpy).toHaveBeenCalledTimes(1);
expect(hogeFnSpy).toHaveBeenCalledWith('hoge', 'bar');
});
});
useDocumentCookie.spec.tsx
/**
* @jest-environment ./src/test/custom-js-dom-environment.ts
*/
import { render, screen, fireEvent } from '@testing-library/react';
import UseDocumentCookie from './useDocumentCookie';
describe('UseDocumentCookie', () => {
afterEach(() => {
// 他のテストも考えるとafterEachに書くのがベター
Object.defineProperty(document, 'cookie', {
value: undefined,
});
});
test('setCookieボタンクリック時、cookieが設定される', () => {
render(<UseDocumentCookie />);
fireEvent.click(screen.getByText('setCookieボタン'));
const { cookie } = document;
expect(cookie).toEqual(
`hogeKey=anyValue; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/; domain=${hostname}`
);
});
});
全てのコード、バージョン情報等はこちら
https://github.com/yamatoto/jest-sample
https://github.com/yamatoto/jest-sample/tree/master/src/views/useGlobalProperty