前回の記事 で作成したボイラープレートにJestを導入する。
各種設定
モジュールの追加
今回は Jest と Enzyme をインストールする。
$ npm install -D jest ts-jest enzyme enzyme-to-json enzyme-adapter-react-16
TypeScript を使用するので以下もインストールする。
$ npm install -D @types/jest @types/enzyme @types/enzyme-adapter-react-16
Jest設定ファイルの作成
Jestの設定ファイルを追加する。
// <プロジェクトルート>/jest.config.js
module.exports = {
// 起点となるディレクトリを指定
"roots": [
"./src"
],
// アセットの変換方法を指定
"transform": {
"^.+\\.tsx?$": "ts-jest"
},
// Jestで実行するテストコードの配置場所とテストコードの正規表現での指定
// __tests__下の hoge.test.tsx または hoge.spec.tsx を対象とする
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
// テスト対象となる拡張子を列挙
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json",
"node"
],
// Enzymeの設定
snapshotSerializers: ['enzyme-to-json/serializer'],
// Enzymeの設定ファイル(自分で作成する)
setupFilesAfterEnv: ['./test/setupEnzyme.ts'],
};
上記で設定した__tests__
ディレクトリを作成しておく。
$ mkdir ./src/__tests__
Enzyme設定ファイルの作成
今回は、Enzymeを使用するので、こちらも設定ファイルを用意する。
// <プロジェクトルート>/test/setupEnzyme.ts
import { configure } from 'enzyme';
import * as EnzymeAdapter from 'enzyme-adapter-react-16';
configure({ adapter: new EnzymeAdapter() });
tsconfig.jsonを作成
TypeScriptの設定ファイルを用意する。
{
"compilerOptions": {
"outDir": "./dist/",
"sourceMap": true,
"strictNullChecks": true,
"strictPropertyInitialization": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"module": "es2015", ← common.jsも設定できるが、静的解析の精度が落ちるのでes2015おすすめらしい
"target": "es5",
"jsx": "react",
"esModuleInterop": true
},
"include": [
"./src/**/*"
]
}
package.jsonにJest実行用設定を追加
package.jsonにJest実行用設定を追加する。
"scripts": {
"start": "webpack-dev-server --open",
"build": "webpack",
"build-prod": "webpack --mode=production",
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook",
"test": "jest" ←ここ追加
},
以上で、実行環境の構築は完了。
動作確認
確認用コンポーネント作成
前回作成したコンポーネントを使用する。
// <プロジェクトルート>/src/components/Button/index.tsx
import * as React from 'react';
export interface IButtonProps {
text: string;
flag?: boolean;
action(): void;
}
const Button = (props: IButtonProps) => {
const { text, flag, action } = props;
return (
<React.Fragment>
{ flag && <p>{text}</p> }
<button onClick={ action }>Button</button>
</React.Fragment>
);
};
export default Button;
テストファイル作成
__tests__
内にコンポーネントと同じディレクトリ構造を作成する。
$ mkdir ./src/__tests__/components/Button
テストコードを作成する。
// <プロジェクトルート>/src/__tests__/components/Button/index.test.tsx
import * as React from 'react';
import {shallow} from 'enzyme';
import Button from '../../../components/Button';
test('小コンポーネントが存在すること', () => {
const wrapper = shallow(<Button text="ボタンです" flag={true} action={() => console.log("test")} />);
expect(wrapper.find("button").length).toBe(1);
expect(wrapper.find("p").length).toBe(1);
expect(wrapper.find("p").text()).toEqual("ボタンです");
expect(wrapper).toMatchSnapshot();
});
test('pコンポーネントが表示されないこと', () => {
const wrapper = shallow(<Button text="ボタンです" flag={false} action={() => console.log("test")} />);
expect(wrapper.find("button").length).toBe(1);
expect(wrapper.find("p").length).toBe(0);
expect(wrapper).toMatchSnapshot();
});
test('イベント発火時にコールバック関数が呼び出されること', () => {
const Spy = jest.fn();
const wrapper= shallow(
<Button text="ボタンです" flag={true} action={Spy} />
);
wrapper.find('button').simulate('click');
expect(Spy).toHaveBeenCalledWith();
expect(wrapper).toMatchSnapshot();
});
実行
コンソールからテストコマンドを実行する。
実行すると、以下のようにテスト結果が出力される。
$ npm run test
> react-ts-webpack@1.0.0 test /Users/kento/Programing/VScodeProjects/ts-react-sass-simple-boiler-v4
> jest
PASS src/__tests__/components/Button/index.test.tsx
✓ 小コンポーネントが存在すること (33ms)
✓ pコンポーネントが表示されないこと (3ms)
✓ イベント発火時にコールバック関数が呼び出されること (6ms)
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 3 passed, 3 total
Time: 2.182s, estimated 5s
Ran all test suites.
テスト実行後、__tests__
ディレクトリ内に、__snapshots__
ディレクトリが作成され、中にスナップショットファイルが作成される。
$ tree ./src/__tests__
./src/__tests__
└── components
└── Button
├── __snapshots__
│ └── index.test.tsx.snap
└── index.test.tsx
index.test.tsx.snap
の中身は以下の通り。
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`pコンポーネントが表示されないこと 1`] = `
<Fragment>
<button
onClick={[Function]}
>
Button
</button>
</Fragment>
`;
exports[`イベント発火時にコールバック関数が呼び出されること 1`] = `
<Fragment>
<p>
ボタンです
</p>
<button
onClick={
[MockFunction] {
"calls": Array [
Array [],
],
"results": Array [
Object {
"type": "return",
"value": undefined,
},
],
}
}
>
Button
</button>
</Fragment>
`;
exports[`小コンポーネントが存在すること 1`] = `
<Fragment>
<p>
ボタンです
</p>
<button
onClick={[Function]}
>
Button
</button>
</Fragment>
`;
以上で、Jestの導入は完了。
作成したボイラープレートは こちら