スナップショットテスト
スナップショットのテストはUI が予期せず変更されていないかを確かめるのに非常に有用なツールです。
典型的なスナップショットテストでは、UIコンポーネントをレンダリングし、スナップショットを撮り、テストと一緒に保管されているスナップショットファイルと比較します。 2つのスナップショットが一致しない場合テストは失敗します: 予期されない変更があったか、参照するスナップショットが新しいバージョンのUIコンポーネントに更新される必要があるかのどちらかです。
Jestにおけるスナップショットテスト
React コンポーネントをテストする場合 にも、同様のアプローチをとることができます。 アプリケーション全体の構築が必要となるグラフィカルなUIをレンダリングする代わりに、シリアライズ可能なReactツリーの値を素早く生成するテスト用レンダラーを利用できます。 Consider this example test for a Link component:
import renderer from 'react-test-renderer';
import Link from '../Link';
it('renders correctly', () => {
const tree = renderer
.create(<Link page="http://www.facebook.com">Facebook</Link>)
.toJSON();
expect(tree).toMatchSnapshot();
});
The first time this test is run, Jest creates a snapshot file that looks like this:
exports[`renders correctly 1`] = `
<a
className="normal"
href="http://www.facebook.com"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
Facebook
</a>
`;
生成されるスナップショットはコードの変更に追随し、かつコードレビューのプロセスの一部としてレビューされるべきです。 Jest uses pretty-format to make snapshots human-readable during code review. On subsequent test runs, Jest will compare the rendered output with the previous snapshot. それらが一致すれば、テストを通過します。 If they don't match, either the test runner found a bug in your code (in the <Link>
component in this case) that should be fixed, or the implementation has changed and the snapshot needs to be updated.
The snapshot is directly scoped to the data you render – in our example the <Link>
component with page
prop passed to it. This implies that even if any other file has missing props (say, App.js
) in the <Link>
component, it will still pass the test as the test doesn't know the usage of <Link>
component and it's scoped only to the Link.js
. Also, rendering the same component with different props in other snapshot tests will not affect the first one, as the tests don't know about each other.
スナップショットのテストのしくみ、およびそれを作成した理由の詳細については、 release blog postで読むことができます。 いつスナップショットテストを使用するべきかについて、よい感覚を身に付けるには、このブログ記事を読むことをお勧めします。 Jestでスナップショットテストを行うこの eggheadの動画 も観ることをお勧めします。 (訳注: egghead.
スナップショットの更新
バグが混入した後でスナップショットテストが失敗したときは簡単に目星がつきます。 テストが失敗したら、その原因箇所に向かって問題を修正し、スナップショットテストが再びパスすることを確認すればよいのです。 ここで、意図的な仕様変更によりスナップショットテストが失敗するケースについて議論しましょ う。
このような状況はたとえば以下の例のLinkコンポーネントが指すアドレスを意図的に変更した場合に起こります。
// Updated test case with a Link to a different address
it('renders correctly', () => {
const tree = renderer
.create(<Link page="http://www.instagram.com">Instagram</Link>)
.toJSON();
expect(tree).toMatchSnapshot();
});
このケースではJestは以下のような結果を出力します。
異なるアドレスを指すようにコンポーネントを更新したのですから、このコンポーネントのスナップショットに変更があると予想するのが妥当でしょう。 更新されたコンポーネントのスナップショットは今やこのテストで生成されたスナップショットと一致しないので、スナップショットのテストケースは失敗します。
これを解決するには、生成したスナップショットを更新する必要があります。 単純にスナップショットを再生成するように指示するフラグを付けてJestを実行するだけでできます。
jest --updateSnapshot
上記のコマンドを実行することで変更を受け入れることができます。 お好みで一文字の -u
フラグでもスナップショットの再生成を行うことができます。 このフラグは失敗する全てのスナップショットテストのスナップショットを再生成します。 意図しないバグにより追加されたスナップショットテストの失敗があれば、バグが混ざった状態でスナップショットを記録することを避けるためにスナップショットを再生成する前にバグを修正する必要があります。
再生成されるスナップショットを限定したい場合は、 --testNamePattern
フラグを追加して指定することでパターンにマッチするテストのみスナップショットを再生成することができます。
You can try out this functionality by cloning the snapshot example, modifying the Link
component, and running Jest.
インタラクティブ・スナップショットモード
失敗したスナップショットは、ウォッチモードで対話的に更新することもできます。
インタラクティブ・スナップショットモードに入ると、Jest は一度に1つのテストごとに、失敗したスナップショットをステップ実行させてくれます。 ここで、失敗した出力を確認できます。
ここで、スナップショットを更新するか、次にスキップするかを選択できます。
終了したら、Jest はウォッチモードに戻る前に概要を表示します。