microCMS

Cypressで始めるReactのE2Eテスト-導入から実際にテストを書いてみよう!

エンジニアリング
2020/04/13 かみむら

こんにちはかみむらです。
SPAの登場で状態管理が複雑化するに連れて、よりフロントエンドのテストが重要になってきました。
しかし、なかなか導入できていないところが多いのではないでしょうか。その中でもE2Eテストは工数の兼ね合い、優先的にテストできない工程ですよね。
そこで、今回は導入コストが低いCypressで、フロントエンド(React)のE2Eテストについてご紹介します。

Cypressとは?


Cypressはブラウザでのテスト作業を自動化するテストフレームワークです。オープンソースできています。
これまでのE2EテストはSeleniumが主流でしたが、最近はCypressも勢いを増しています。

また、Cypress DashboardというSaaSもあるので、これらをうまく組み合わせることでチームでのテスト効率をあげることに繋がります。

今回はCypressを使ってフロントエンド(React)のE2Eテストをしてみます。

Cypressのリポジトリ
https://github.com/cypress-io/cypress

Cypressの公式サイト
https://www.cypress.io/

前提

create-react-appで作成したプロジェクトをベースにしていきます。事前にプロジェクトを作成してください。

導入 

導入はとても簡単です。まずは、Cypressのライブラリをインストールします。

$ yarn add -D cypress

そして、package.jsonにCypressを起動するためのスクリプトを追加します。

"scripts": {
  //追加
  "cy:open": "cypress open"
}

下記のコマンドを実行すると、ダッシュボードが開きます。それと同時にCypressのテストファイルがプロジェクト内に展開されます。これで準備ができました。

$ yarn run cy:open


Scaffoldで作成されたフォルダの中に多くのexampleがあります。色々なパターンでのテストがあるので、一度見てみてください。

初めてのブラウザテスト

それでは早速、ブラウザテストを書いてみましょう。
cypress.jsonに、今回テストするアプリケーションのベースURLを指定します。ここではlocalhost:3000を指定します。

{
 "baseUrl": "http://localhost:3000"
}

そして、integrationの中にsample_spec.jsを作成してください。内容は簡単でCypressが正しく動いているかを確認します。

describe('Cypress', () => {
 it('is working', () => {
  expect(true).to.equal(true)
 })
})

そして、テストを実行するためのコマンドを追加します。ここでは--browserオプションで実行するブラウザを指定することもできます。例えば、
chromeとfirefoxに対応する場合は下記のように指定します。

"scripts": {
  "cy:run": "cypress run",
  "cy:run:chrome": "cypress run --browser chrome",
  "cy:run:firefox": "cypress run --browser firefox"
}

Reactアプリケーションを起動して、その後テストを実行します。

$ yarn run start

--specオプションで実行するテストファイルを指定することができます。

$ yarn run cy:run --spec=./cypress/integration/sample_spec.js

テストが通ってることを確認してみましょう。これで初めてのCypressのテストを書くことができました。

カウンターアプリケーションのテスト

今回は、Reactの簡単なカウンターアプリケーションを作成します。ここでのブラウザ動作は単純で、

  1. +ボタンを押すと、countのstateが1プラスされる
  2. -ボタンを押すと、countのstateが1マイナスされる
  3. リセットボタンを押すと、countのstateが0(初期値)に戻る


といった感じです。これをCypressを使って自動ブラウザテストしてみましょう。

カウンターアプリケーションの作成

こちらがカウンターアプリのコードです。非常に簡易的ですが実装してみましょう。

//App.js
import React, {useState} from 'react';

const App = () => {
 const [count, setCount] = useState(0);

 const increment = () => {
  setCount(count + 1);
 };

 const decrement = () => {
  setCount(count - 1);
 };

 const handleReset = () => {
  setCount(0);
 };
 return (
  <div className="container">
   <span className="counter">{count}</span>
   <button className="increment" onClick={increment}>
    +
   </button>
   <button className="decrement" onClick={decrement}>
    -
   </button>

   <button className="reset" onClick={handleReset}>
    数値をリセット
   </button>
  </div>
 );
};

export default App;

Reactのアプリケーションを起動して手動テストをしてみます。正しく動作することを確認してください。

自動ブラウザテストの作成

それではカウンターアプリの自動ブラウザテストをしてみましょう。integrationフォルダcounter_spec.jsを作成します。

describe('カウンターアプリのテスト', function () {
  beforeEach(() => {
    cy.visit('/');
  });
  it('+ボタンを押すとカウンターの値に1プラスされる', () => {
    cy.get('.increment').click().get('.counter').should('have.text', '1')
  });

  it('-ボタンを押すとカウンターの値が1マイナスされる', () => {
    cy.get('.decrement').click().get('.counter').should('have.text', '-1')
  });

  it('+ボタンを押した後、リセットボタンを押すとカウントが0に戻る', () => {
    cy.get('.increment').click().get('.reset').click().get('.counter').should('have.text', '0')
  });
});


cy.visit()は指定したURLを開くコマンドで、先ほどcypress.jsonで指定したlocalhost:3000にアクセスします。
cy.get()DOM elementsを指定します。clickを指定することでDOM elementsにクリックする動作を追加することができます。
shoudを使うことでアサーションを作成することができます。

このテストを実行します。

$ yarn run cy:run --spec=./cypress/integration/counter_spec.js

すべてのテストが無事に通りました。CLI上で確認してください。

また、テストの実行方法がもう一つあります。先ほどのopenコマンドを実行して、ダッシュボードを開きます。

$ yarn run cy:open


そして右上にあるRun all specsをクリックします。

すると、実際にブラウザが開いてテストの実行過程をみることができます。

cypress.jsonの設定

Cypressの設定ファイルのドキュメントがこちらにあります。使っていく中でいくつか変えたい設定があったのでここで紹介します。
https://docs.cypress.io/guides/references/configuration.html#Global

テストフォルダを変えたい場合

実行するテストフォルダを変えることができます。デフォルトではcypressフォルダを起点にしていましたが、私はユニットテストと同じ階層のフォルダにまとめたかったので、下記のようにしました。これで、__tests__フォルダのe2eにCypressのテストをまとめることができます。

{
 "fixturesFolder": "__tests__/e2e/fixtures",
 "integrationFolder": "__tests__/e2e/integration",
 "screenshotsFolder": "__tests__/e2e/screenshots",
 "videosFolder": "__tests__/e2e/videos"
}

動画の出力を無効にしたい

デフォルトではmp4の動画が出力されます。非常に便利ですが、動画を出力したくない場合もあります。そんな時は下記のように設定すると、動画が出力されません。

{
  "video": false
}

最後に

今回はCypressを用いたReactのE2Eテストを紹介しました。実際のプロダクトで、フロントエンドのE2Eテストを導入すべきか迷いますね。ですが、今回Cypressを使ってみてシンプルな構文に非常に好感が持てました。今後私が関わったプロジェクトで導入をしたいと感じました。

参考
https://css-tricks.com/using-cypress-to-write-tests-for-a-react-application/
https://qiita.com/aomoriringo/items/187af32eeac869182648

ABOUT ME

かみむら
フロントエンドエンジニア。テックブロガーでもあります。JAMstackアーキテクチャーやSPA(React、Vue)技術が好きです。