Jestを使用してReactコンポーネントのスナップショットテストを作成する方法
序章
スナップショットテストを使用すると、出力が引き続き期待どおりに動作することを確認できます。 これは、コードを再検討して時間の経過とともに更新を行うと、それらの変更によって何かが破損する可能性が高くなるため、便利です。
厳密なテスト駆動開発(TDD)とは異なり、標準的な方法では、最初に失敗したテストを記述してから、テストに合格するためのコードを記述しますが、スナップショットテストは別のアプローチを取ります。
Reactコンポーネントのスナップショットテストを作成するときは、最初にコードを動作状態にする必要があります。 次に、特定のデータを指定して、期待される出力のスナップショットを生成します。 スナップショットテストは、コンポーネントと一緒にコミットされます。 テストフレームワークであるJestは、スナップショットをテスト用にレンダリングされた出力と比較します。
テストが失敗した場合、それは2つのことを意味する可能性があります。 テスト結果が予期しないものである場合は、コンポーネントの問題に対処する必要がある場合があります。 テスト結果が予想される場合は、新しい出力をサポートするためにスナップショットテストを更新する必要があることを意味する場合があります。
このチュートリアルでは、スナップショットテストと、それらを使用してユーザーインターフェイス(UI)が予期せず変更されないようにする方法について説明します。
前提条件
このチュートリアルを完了するには、次のものが必要です。
- Node.jsはローカルにインストールされます。これは、Node.jsのインストール方法とローカル開発環境の作成に従って実行できます。
- ReactとJestにある程度精通していると有益な場合がありますが、必須ではありません。
このチュートリアルでは、 Visual Studio Code をコードエディターとして使用し、統合端末を実行するのに便利です。 ただし、これを選択したエディターとターミナルに置き換えることができます。
このチュートリアルは、ノードv14.7.0、npm
v6.14.7、react
v16.13.1、およびjest
v24.9.0で検証されました。
ステップ1—テストするReactコンポーネントを作成する
まず、何かをテストするために、 Create ReactAppを使用してReactアプリを作成する必要があります。 このチュートリアルでは、プロジェクトはreact-snapshot-tests
と呼ばれます。
ターミナルを開き、次のコマンドを実行します。
npx [email protected] react-snapshot-tests
次に、新しく作成したアプリディレクトリに移動します。
cd react-snapshot-tests
次に、アプリを起動します。
npm start
この時点で、Reactアプリが実行され、Webブラウザーで表示できるようになります。 次に、テストできるコンポーネントを作成する必要があります。
このチュートリアルでは、作成するコンポーネントが、受け取ったitems
小道具をレンダリングします。
ターミナルで、src
の下にcomponents
サブディレクトリを作成します。
mkdir src/components
次に、Items.js
コンポーネントを作成します。
nano src/components/Items.js
次のコードをItems.js
に追加します。
src / components / Items.js
import React from 'react'; import PropTypes from 'prop-types'; /** * Render a list of items * * @param {Object} props - List of items */ function Items(props) { const { items = [] } = props; // A single item in the list, render a span. if (items.length === 1) { return <span>{items[0]}</span>; } // Multiple items on the list, render a list. if (items.length > 1) { return ( <ul> {items.map(item => <li key={item}>{item}</li>)} </ul> ); } // No items on the list, render an empty message. return <span>No items in list</span>; } Items.propTypes = { items: PropTypes.array, }; Items.defaultProps = { items: [] }; export default Items;
このコードは、量に基づいてitems
プロップをレンダリングします。
- 複数のアイテムがある場合、アイテムは順序付けられていないリスト(
<ul>
)に表示されます。 - アイテムが1つしかない場合は、
<span>
要素で表示されます。 - アイテムがない場合は、エラーメッセージが表示されます。
最後に、App.js
を更新して、コンポーネントをレンダリングします。
nano src/App.js
App.js
の内容を次のように置き換えます。
src / App.js
import React, { Component } from 'react'; import Items from './components/Items'; class App extends Component { render() { const items = [ 'Shark', 'Dolphin', 'Octopus' ]; return ( <Items items={items} /> ); } } export default App;
ブラウザでアプリにアクセスすると、App.js
で設定した値のリストが表示された画面が表示されます。
Output* Shark * Dolphin * Octopus
items
が複数あったため、順不同で表示されます。
次に、スナップショットテストを追加します。
ステップ2—スナップショットテストの作成
開始するには、CreateReactAppによって生成されたApp.test.js
ファイルを削除します。
rm src/App.test.js
このチュートリアルでは必要ありません。
次に、 react-test-renderer をインストールします。これは、DOMを必要とせずにReactコンポーネントをJavaScriptオブジェクトとしてレンダリングできるようにするライブラリです。
npm install [email protected]
最初のテストを追加しましょう。 開始するには、Items.test.js
ファイルを作成します。
nano src/components/Items.test.js
Items
コンポーネントを、小道具として渡されるアイテムなしでレンダリングするテストを作成します。
src / components / Items.test.js
import React from 'react'; import renderer from 'react-test-renderer'; import Items from './Items'; it('renders correctly when there are no items', () => { const tree = renderer.create(<Items />).toJSON(); expect(tree).toMatchSnapshot(); });
次に、テストを実行しましょう。 Create React Appは、テストを設定するためのすべての初期化を処理しました。
npm test
"renders correctly when there are no items"
の合格テストを取得する必要があります。
スナップショットテストを初めて実行するときは、__snapshots__
ディレクトリ内に新しいスナップショットファイルが作成されていることに注意してください。 テストファイルの名前はItems.test.js
であるため、スナップショットファイルの名前はItems.test.js.snap
です。
Items.tests.js.snap
の内容は次のようになります。
src / components / __ snapshots __ / Items.test.js.snap
// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`renders correctly when there are no items 1`] = ` <span> No items in list </span> `;
このスナップショットは、コンポーネントの正確な出力と一致します。
Jestはpretty-formatを使用して、スナップショットファイルを人間が読める形式にします。
これで、1つのアイテムがあり、複数のアイテムがある他の2つのシナリオのテストを作成できます。
Items.tests.js
を開きます:
nano src/components/Items.test.js
次のコード行を追加します。
src / components / Items.test.js
// ... it('renders correctly when there is a single item', () => { const items = ['one']; const tree = renderer.create(<Items items={items} />).toJSON(); expect(tree).toMatchSnapshot(); }); it('renders correctly when there are multiple items', () => { const items = ['one', 'two', 'three']; const tree = renderer.create(<Items items={items} />).toJSON(); expect(tree).toMatchSnapshot(); });
この時点で、3つのテストが作成されています。1つはアイテムなし、1つは単一アイテム、もう1つは複数アイテムです。
テストを再実行します。
npm test
3つのテストすべてに合格するはずです。これで、__snapshots__
ディレクトリに3つのスナップショットが作成されます。
次に、スナップショットテストを更新して、失敗したテストに対処します。
ステップ3—スナップショットテストの更新
スナップショットテストが必要な理由をよりよく理解するために、Items
コンポーネントに変更を加えて、テストを再実行します。 これは、開発中のプロジェクトに変更が加えられたときに何が起こるかをシミュレーションしたものです。
Items.js
を開きます:
nano src/components/Items.js
span
およびli
要素にクラス名を追加します。
src / components / Items.js
... /** * Render a list of items * * @param {Object} props - List of items */ function Items(props) { const { items = [] } = props; // A single item in the list, render a span. if (items.length === 1) { return <span className="item-message">{items[0]}</span>; } // Multiple items on the list, render a list. if (items.length > 1) { return ( <ul> {items.map(item => <li key={item} className="item-message">{item}</li>)} </ul> ); } // No items on the list, render an empty message. return <span className="empty-message">No items in list</span>; } Items.propTypes = { items: PropTypes.array, }; Items.defaultProps = { items: [], }; export default Items;
テストを再実行してみましょう。
npm test
失敗したテスト結果が観察されます。
Jestは、既存のスナップショットを、更新された変更を使用してレンダリングされたコンポーネントと照合し、コンポーネントにいくつかの追加があったために失敗しました。 次に、スナップショットテストに導入された変更の差分が表示されます。
変更が予期されていない場合は、変更がデプロイされる前にエラーをキャッチし、エラーに対処できるようになりました。 変更が予想される場合は、スナップショットテストを更新して、正しく合格させる必要があります。
チュートリアルでは、これは予想される変更であると想定できます。 コンポーネントにクラス名を追加するつもりでした。 次に、スナップショットテストを更新する必要があります。
Jestがインタラクティブモードのときに、提供されているオプションを使用してu
を押すと、スナップショットテストを更新できます。
注:または、Jest をグローバルにインストールしている場合、jest --updateSnapshot
またはjest -u
を実行できます。
これにより、スナップショットが更新され、行った更新と一致するようになり、テストに合格します。
アイテムがない場合の以前のスナップショットテストは次のとおりです。
src / components / __ snapshots __ / Items.test.js.snap
// ... exports[`renders correctly when there are no items 1`] = ` <span> No items in list </span> `; // ...
そして、これがアイテムなしの新しく更新されたスナップショットテストです:
src / components / __ snapshots __ / Items.test.js.snap
// ... exports[`renders correctly when there are no items 1`] = ` <span className="empty-message" > No items in list </span> `; // ...
テストを更新した後、それらは合格します:
これで、テストに再び合格しました。 これが開発中のプロジェクトである場合は、意図した変更が将来の開発のために文書化されていることを知って、コードをデプロイできます。
結論
このチュートリアルでは、Reactコンポーネントのスナップショットテストを作成しました。 また、テストの失敗を経験するようにコンポーネントを変更しました。 最後に、スナップショットを更新してテストを修正しました。
これは、ライブプロジェクトの小さなシミュレーションでした。 テストの合格、失敗、および失敗への対処のこのサイクルは、開発ワークフローの一部になります。
スナップショットテストは、さまざまなテストツールの1つです。 したがって、アクションとレデューサーのテストを作成する必要がある場合があります。
スナップショットテストの基本を探求している間、より良いスナップショットテストを書くことについて学ぶことができることがたくさんあります。 スナップショットテストの詳細については、Jestのドキュメントのスナップショットのベストプラクティスをご覧ください。
Reactの詳細については、Reactトピックページで演習とプログラミングプロジェクトを確認してください。