Jest - React 第一歩
まずは簡単に props.errors で降りてきた文字列を表示するだけの componentを作る。
import * as React from "react";
interface Props {
errors: string
}
interface State {
}
export default class Error extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
}
public render() {
return <h3>{this.props.errors}</h3>;
}
}
上を題材にJestの初歩を勉強する。以下、Jestに動かしてもらう Unit Test を作る。Unit Test 自体も TypeScript で書いてみることにする。以下、error.test.tsx:
import * as React from "react";
import Errors from "../components/error";
import * as ReactTestRenderer from 'react-test-renderer';
test('test error component', () => {
const errorMessage = "hello world!"
const rendered = ReactTestRenderer.create(
<Errors errors={errorMessage} />
);
const renderedJson = rendered.toJSON();
expect(renderedJson.children[0]).toEqual(errorMessage);
React を import しないと、すでにTSにてエラーとなる。
[ts] 'React' refers to a UMD global, but the current file is a module. Consider adding an import instead.
上では、react-test-renderer モジュールを使用してみた。これと、Jest の expect, toEqual 等の組み合わせ。
Jest を走らせると以下の結果:
PASS src\__tests__\error.test.tsx
√ test error component (16ms)
console.log src\__tests__\error.test.tsx:10
{ type: 'h3', props: {}, children: [ 'hello world!' ] }
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.362s
Ran all test suites.
Waiting for the debugger to disconnect...
Press any key to continue . . .
import * as React from "react";
import Errors from "../components/error";
import * as ReactTestRenderer from 'react-test-renderer';
test('test error component', () => {
const errorMessage = "hello world!"
const rendered = ReactTestRenderer.create(
<Errors errors={errorMessage} />
);
const renderedJson = rendered.toJSON();
expect(renderedJson.children[0]).toEqual(errorMessage);
});
React を import しないと、すでにTSにてエラーとなる。
[ts] 'React' refers to a UMD global, but the current file is a module. Consider adding an import instead.
上では、react-test-renderer モジュールを使用してみた。これと、Jest の expect, toEqual 等の組み合わせ。
Jest を走らせると以下の結果:
PASS src\__tests__\error.test.tsx
√ test error component (16ms)
console.log src\__tests__\error.test.tsx:10
{ type: 'h3', props: {}, children: [ 'hello world!' ] }
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.362s
Ran all test suites.
Waiting for the debugger to disconnect...
Press any key to continue . . .
となり、react-test-renderer' がDOM Tree を返してくれるのが分かる。ふむふむ、これは良い。
次に、enzyme を取り入れてみる。
import * as React from "react";
import {shallow} from "enzyme";
import Errors from "../components/error";
test('test error component', () => {
const errorMessage = "hello world!"
const wrapper = shallow(<Errors errors={errorMessage} />);
const tobe = "<h3>" + errorMessage + "</h3>";
expect(wrapper.text()).toEqual(errorMessage);
});
はい、まずはエラー発生。
Enzyme Internal Error: Enzyme expects an adapter to be configured, but found none. To
configure an adapter, you should call `Enzyme.configure({ adapter: new Adapter() })`
before using any of Enzyme's top level APIs, where `Adapter` is the adapter
corresponding to the library currently being tested. For example:
import Adapter from 'enzyme-adapter-react-15';
どこかのVersion の時点でこれが必要になったそうだ。仰せに従い、インストールする。
npm install enzyme-adapter-react-16 @types/enzyme-adapter-react-16 --save-dev
ソースを以下のように変更して走らせる。
import * as React from "react";
import {shallow} from "enzyme";
import Errors from "../components/error";
import { configure } from 'enzyme';
import * as Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });
test('test error component', () => {
const errorMessage = "hello world!"
const wrapper = shallow(<Errors errors={errorMessage} />);
const tobe = "<h3>" + errorMessage + "</h3>";
expect(wrapper.text()).toEqual(errorMessage);
});
Run。また叱られた。
console.error node_modules\fbjs\lib\warning.js:33
Warning: React depends on requestAnimationFrame. Make sure that you load a polyfill in older browsers. http://fb.me/react-polyfills
requestAnimationFrame が Polyfill されていないと。これは、configure({ adapter: new Adapter() }); が実行されると発生する。この Polyfill には、https://www.npmjs.com/package/raf が良いようだ。
と、ここで落ち着いて一工夫。これらは全てのTestで必要となるであろう。毎回これらを Unit Tests の冒頭に書くのは愚。Jest には startup.cs みたいのが2種類あり、前者は Test Framework が生成される前、後者はそのあとに実行されるそうだ。
Jest の config に (pakage.json, "jest" の部)
"setupFiles": ["<rootDir>/src/setupFile.tsx"],
"setupTestFrameworkScriptFile": "<rootDir>/src/setupTestFrameworkScriptFile.tsx"
これらの中身は、
setupFile.tsx:
const raf = require("raf");
raf.polyfill();
setupTestFrameworkScriptFile.tsx
import { configure } from 'enzyme';
import * as Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });
これにて Polyfill が先に実施されるので、後者の configure() が動作する。気を取り直して、enzyme の検証。上の処置により、Unit Test は簡素になった。
import * as React from "react";
import {shallow} from "enzyme";
import Errors from "../components/error";
test('test error component', () => {
const errorMessage = "hello world!"
const wrapper = shallow(<Errors errors={errorMessage} />);
const tobe = "<h3>" + errorMessage + "</h3>";
expect(wrapper.text()).toEqual(errorMessage);
});
結果
PASS src\__tests__\error.test.tsx
√ test error component (5ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.802s, estimated 3s
Ran all test suites.
Waiting for the debugger to disconnect...
Press any key to continue . . .
ばんざーい。
さて、もう一つ、つっこんで enzyme-matchers を取り入れてみる。React の Assertion に便利そうなもので、3種の Test Framework に対応する。勿論 Jest版をインストールする。
npm add jest-enzyme --save-dev
これも毎回書くのは面倒なので、setupTestFrameworkScriptFile に追加する。
import { configure } from 'enzyme';
import * as Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });
import "jest-enzyme";
これだけ。Unit Test を以下のように書き換える。
import * as React from "react";
import {shallow, mount} from "enzyme";
import Errors from "../components/error";
test('test error component', () => {
const errorMessage = "hello world!"
const wrapper = shallow(<Errors errors={errorMessage} />);
const tobe = "<h3>" + errorMessage + "</h3>";
expect(wrapper.text()).toEqual(errorMessage);
expect(wrapper).toHaveProp("errors");
});
Test自体はきちんと走るが、enzyme-matchers が提供する toHaveProp() で assert error となる。shallow() を mount() で置き換えると、assert error は起きない。ようわからんが、shallow() では props がセットされ無いようだ。難しい議論はこちら: https://github.com/airbnb/enzyme/issues/445
---
mock や stub 等々とりあえず置いておけば、これにてひとまず Unit Test をがりがり書ける環境が整ったと思う。何を走らせてどの様に assert するかは、おいおい個別のプロジェクトで勉強することにしよう。
mock や stub 等々とりあえず置いておけば、これにてひとまず Unit Test をがりがり書ける環境が整ったと思う。何を走らせてどの様に assert するかは、おいおい個別のプロジェクトで勉強することにしよう。
Just が提供する assertions はこちら:
Enzyme の提供する render wrapperはこちら:
enzyme-matchers (jest-enzyme) の提供する assertions はこちら:
ばんざーい
コメント
コメントを投稿