ReactのテストとしてJestでSnapshotテストを行うときのメモ。
ボコボコDOMが変化するコンポーネントのテストは非常に面倒なものだが、JestのSnapshotを使えばサクッとできて便利。
// Example.react.js
import React, { Component } from 'react';
export default class Example extends Component {
constructor() {
super();
}
render() {
return (
<div>
<p>text</p>
</div>
)
}
}
この単純なExampleコンポーネントのスナップショットを取るテストコードは以下のようになる。
toMatchSnapshot
するだけ。便利。
// example.react.test.js
'use strict';
import React from 'react';
import Example from '../Example.react';
import renderer from 'react-test-renderer';
describe('Example', () => {
it('レンダリングができること', () => {
const tree = renderer.create(
<Example />
).toJSON();
expect(tree).toMatchSnapshot();
});
});
Jestを実行する。
$ jest __tests__/example.react.test.js
/node_modules/.bin/jest __tests__/example.react.test.js
PASS __tests__/example.react.test.js
Example
✓ レンダリングができること (11ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 1 passed, 1 total
Time: 0.263s, estimated 1s
Ran all test suites matching "__tests__/example.react.test.js".
このとき__tests__/__snapshots__/example.react.test.js.snap
が生成される。
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Example レンダリングができること 1`] = `
<div>
<p>
text
</p>
</div>
`;
このようにレンダリング結果が保存される。次回以降のテストではこのスナップショットと比較され、一致すればPassingする。
試しにExample.react.jsを変更してみる。
import React, { Component } from 'react';
export default class Example extends Component {
constructor() {
super();
}
render() {
return (
<div>
<p>Hello</p>
</div>
)
}
}
text
をHello
に変更したのでレンダリング結果は前回のスナップショットと異なるため、失敗する。
$ jest __tests__/example.react.test.js
FAIL __tests__/example.react.test.js [7/697]
● Example › レンダリングができること
expect(value).toMatchSnapshot()
Received value does not match stored snapshot 1.
- Snapshot
+ Received
<div>
<p>
- text
+ Hello
</p>
</div>
at Object.<anonymous> (__tests__/example.react.test.js:13:18)
at Promise (<anonymous>)
at Promise.resolve.then.el (node_modules/p-map/index.js:42:16)
at <anonymous>
Example
✕ レンダリングができること (14ms)
Snapshot Summary
› 1 snapshot test failed in 1 test suite. Inspect your code changes or re-run with `-u` to update them.
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 1 failed, 1 total
Time: 0.276s, estimated 1s
Ran all test suites matching "__tests__/example.react.test.js".
このようにコンポーネントを変更し、最新のスナップショットを撮り直すにはjest --updateSnapshot
すれば良い。
onClick
のようにイベントが発生した際にDOMが変化する際は、その都度スナップショットを取る。
ボタンをクリックするとカウントアップするやつ。
import React, { Component } from 'react';
export default class Example extends Component {
constructor() {
super();
this._onClick = this._onClick.bind(this);
this.state = {
count: 0
}
}
_onClick() {
this.setState( { count: this.state.count + 1 } );
}
render() {
return (
<div>
<p>{this.state.count}</p>
<button onClick={this._onClick} >Click</button>
</div>
)
}
}
ここでは雑にonClick
を呼ぶ。
Enzymeと併用したほうが幸せになれると思う(jest-serializer-enzymeというものもある)。
'use strict';
import React from 'react';
import Example from '../Example.react';
import renderer from 'react-test-renderer';
describe('Example', () => {
it('レンダリングができること', () => {
const tree = renderer.create(
<Example />
).toJSON();
expect(tree).toMatchSnapshot();
});
it('onClick', () => {
const component = renderer.create(
<Example />
)
// 1回目クリック
component.getInstance()._onClick();
expect(component.toJSON()).toMatchSnapshot();
// 2回目クリック
component.getInstance()._onClick();
expect(component.toJSON()).toMatchSnapshot();
});
});
$ jest __tests__/example.react.test.js
PASS __tests__/example.react.test.js
Example
✓ レンダリングができること (12ms)
✓ onClick (6ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 3 passed, 3 total
Time: 0.266s, estimated 1s
Ran all test suites matching "__tests__/example.react.test.js".
以下のスナップショットが生成される。
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Example onClick 1`] = `
<div>
<p>
1
</p>
<button
onClick={[Function]}
>
Click
</button>
</div>
`;
exports[`Example onClick 2`] = `
<div>
<p>
2
</p>
<button
onClick={[Function]}
>
Click
</button>
</div>
`;
exports[`Example レンダリングができること 1`] = `
<div>
<p>
0
</p>
<button
onClick={[Function]}
>
Click
</button>
</div>
`;