CircleCIとCypressを導入してReactアプリのコンポーネントテストを自動化してみた！


# はじめに
皆さんこんにちは！
CircleCIカスタマーサクセスマネージャーの小島です。
CircleCIカスタマーサクセスチームでは、お客様がCircleCIを最大限、効率良く、お客様の目標に合わせて活用していただけるよう、日々お手伝いをしております。
今回は、Cypressというフロントエンドのテストツールを実際に使用し、コンポーネントテストをCypressで自動化し、CircleCI上での自動化まで実現できるチュートリアルに挑戦してみました！

# 目次
- 事前準備
- コンポーネントテストとは
- コンポーネントテストとE2Eテストの違い
- コンポーネントテスト実行にCypressを使用してみる
- 実際にコンポーネントテストを書いていこう
- CypressOrbを利用してCircleCIでビルドしてみる
- おわりに

# 事前準備
このチュートリアルを実施するには以下の要件が必要となります。

* Node.jsのインストール
* CircleCIアカウント
* GitHubのアカウントとGitの理解
* JavaScriptとReactの知識
* パイプラインの仕組みの理解
* [デモのReactアプリ](https://github.com/CIRCLECI-GWP/component-testing-with-cypress)のクローン

このチュートリアル内では事前に用意されているデモのReactアプリを使用していきます。



# コンポーネントテストとは
コンポーネントとは、ソフトウェアプログラムの区別できる部分のことです。
フォーム、サイト検索などはWebアプリケーションのコンポーネントの例です。
コンポーネントテストは単体テストやユニットテストとも呼ばれています。
このテストプロセスは、メインアプリケーションから独立した特定のコンポーネントの機能性および要件を検証し、確認することから構成されます。


# コンポーネントテストとE2Eテストの違い
E2Eテストは、アプリケーションの最初から最後までの流れが期待通りに進むかどうかを判断します。
E2Eテストには、サードパーティのAPIやサービスとの統合をテストすることも含まれます。
Cypressでは、ユーザーがアプリケーションとやり取りするのと同じように、ブラウザを使用してE2Eテストを実行します。
アプリケーションの基本的なE2Eテストには、ユーザー登録、確認メール、ログイン、プロフィールの更新、ログアウトが含まれます。
E2Eテストは、コンポーネントテストに比べ、遅く、より脆弱である傾向があります。
コンポーネントテストは、専門的かつ迅速で、信頼性の高いテストです。
E2Eテストは、その範囲の広さから、しばしば複雑なセットアップ段階を必要とし、コンポーネントテストでは、複雑な設定は必要ありません。

CypressのE2Eテストは、開発者、専門のテストエンジニア、または品質保証チームが作成することができます。
通常、コンポーネントの開発者自身がコンポーネントテストを作成します。開発者は、コンポーネントを構築しながら、そのコンポーネントに必要な機能を簡単に検証することができます。
チュートリアルの後半で実際にコンポーネントテストを書いていると、Cypressのエンドツーエンドテストでは初期化コマンドが```cy.visit(url)```であることに気がつくと思います。
コンポーネントテストでは ```cy.mount(<MyComponent />)``` を使用します。
よくテストされたアプリは、エンドツーエンドテストとコンポーネントテストの両方を含み、それぞれのテストセットが最もよく実行するタスクに特化しています。

コンポーネントテストの利点は以下の通りです。
* モジュールの欠陥を検出する
* コンポーネントは、アプリケーション全体の一部としてではなく、それ自体でテストされます。
* 範囲が限定されているため、迅速かつ信頼性の高いテストが可能
* 開発時間を短縮できる
* 容易に特定のシナリオを設定可能
* 外部システム不要

Cypressのコンポーネントテストについて理解したところで、次のセクションでは、アプリケーションに Cypressを設定する方法、テストの記述方法、およびテストの実行方法について触れていきます。

# コンポーネントテスト実行にCypressを使用してみる
Cypress E2Eテストを使用してReactアプリケーションをテストするには、ローカルの開発サーバーでアプリを実行し、別の端末でCypressを実行します。
Cypressは```cy.visit(url)```というコマンドでアプリケーションを訪問し、読み込まれたページでアサーションを実行します。
Cypressの最新バージョンには開発サーバーが組み込まれており、コンポーネントテストを行う際にローカルの開発サーバーが不要になります。
Cypressの組み込みサーバーは、ブラウザにコンポーネントをマウントしてレンダリングする役割を担っています。メインアプリケーションとは別にコンポーネントをマウントし、レンダリングするだけです。
![スクリーンショット 2023-01-28 18.23.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634965/1e8f9e94-cdcd-1747-4e01-301bf951f6e2.png)


この図は、Cypress がこの順序でコンポーネントテストを実行することを示しています。
* ```cy.mount()```コマンドでコンポーネントをマウントする。
* コンポーネントをレンダリングする
* Cypressのコマンドを使用してコンポーネントの属性をテストする

指定されたポイントで障害が発生すると、テストは失敗となります。


# 実際にコンポーネントテストを書いていこう
このセクションでは事前に用意されているReactのアプリケーション内にあるニュースレターの購読コンポーネントのテストを書き、Cypress上でテストを自動実行していきます。

Cypressをインストールするためのコマンド

```
npm install cypress --save-dev
```
このコマンドを利用することによって、ローカル環境にCypressがインストールされます。
実際にインストールされたCypressアプリを開くために、以下のコマンドを実行します。

```
npx cypress open
```

Cypressアプリが開いたら、Component Testingを選択。
![スクリーンショット 2023-01-28 18.36.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634965/05531aa8-427b-a4c5-fe20-5fc236cc1dd0.png)

プロジェクトセットアップのページに進んだら、フロントエンドフレームワークのReactを選択し、次へ。
![スクリーンショット 2023-01-28 18.41.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634965/ec00cc36-2a9d-9253-b6b6-900cdbd29cbf.png)

Dependenciesはすでにインストールされているので、次へ。
![スクリーンショット 2023-01-28 18.41.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634965/05bf71fb-b9d7-cce9-fcf1-a2e42e2fb52a.png)

お好みのブラウザを選択し、次へ、
![スクリーンショット 2023-01-28 18.49.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634965/e4f22616-41dc-b112-ec5b-4b9b7a991d96.png)

新しくテストを書き始めるために、新しい空白のスペックを作成。
スペック名を決め、Create Specボタンを押すと名前がついたスペックが完成。
![スクリーンショット 2023-01-28 18.52.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634965/57275fb4-4347-e1a5-edda-2ed2cad6a0ed.png)

これで、サンプルコードを含む仕様書ができたので、このファイルを実行します。
![スクリーンショット 2023-01-28 18.52.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634965/22f03b1c-3e17-5a68-1454-b04524fea595.png)


これで、ニュースレター購読フォームのテストを作成し始めることができます。
テストはこれらのアクションが起こることを確認する必要があります。

* コンポーネントが正しくインストールされている
* 入力フィールドにプレースホルダが存在する
* 購読後に成功メッセージが返される

先ほど作成した spec ファイルで、生成されたコードを次のように置き換えます。

```

// cypress/component/NewsLetterSubscription.cy.js file

import App from "../.././src/components/App";

describe("NewsLetterSubscription.cy.js", () => {
  describe("NewsLetterSubscription.cy.js", () => {
    it("Check input field for placeholder", () => {
      cy.mount(<App />); // mount the component
      cy.get("input").should(
        "have.attr",
        "placeholder",
        "Subscribe to our newsletter"
      ); // check the placeholder in the input field
    });
    it("test newsletter subscription", () => {
      cy.mount(<App />); // mount the component
      cy.get('[data-test="email-input"]').type("test@gmail.com"); // Type email
      cy.get('[data-test="submit-button"]').click(); // Click on submit button
      cy.get('[data-test="success-message"]')
        .should("exist")
        .contains("Thank you for subscribing to our newsletter"); // Check if success message is displayed
    });
  });
});

```
このテストでは、まず```cy.mount()```コマンドでコンポーネントをマウントします。そして、```cy.get()```関数を使って、入力フィールドにテキストを含むプレースホルダーがあるかどうかをチェックします。
メールアドレスを入力し、購読ボタンをクリックすると、成功メッセージが返されるはずです。
Cypressのブラウザにアクセスして、テストがパスしたことを確認します。
![スクリーンショット 2023-01-28 18.59.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634965/17217ac0-9b91-e6f9-465d-ffd42f65858b.png)

無事にテストが全て通りました！！


# CypressOrbを利用してCircleCIでビルドしてみよう
このセクションではCypressを利用して自動化されたコンポーネントテストを含むReactアプリケーションをCircleCI上でもビルドしていきます。

まずはじめに、.circleciディレクトリをプロジェクトのルートディレクトリに作成。
その中にconfig.ymlファイルを作成します。
config.ymlファイルの中で非公式のCypress Orbも使用するため、CircleCIの設定から非公式のOrbを使用できるよう、許可する必要があります。
以下の設定から非公式Orbの使用許可を行ってください。
Settings -> Security -> Allow uncertified orbs.

config.ymlファイルの中には以下の内容を保存していきます:

```
version: 2.1 # Use 2.1 to make use of orbs and other features
orbs: # An orb is a reusable package of CircleCI configuration that you may share
  # across projects, enabling you to create encapsulated, parameterized commands, jobs, and
  # executors that can be used across multiple projects.
  cypress: cypress-io/cypress@1
workflows: # Workflows are a declarative way to orchestrate jobs and their run order.
  build:
    jobs:
      - cypress/run: # Run the cypress/run job from the cypress orb
          command: npx cypress run --headless --component # Run the cypress run command in headless mode 
```

以上の手順が終了したら、自身のCircleCIアカウントへログインし、Set Up Projectを選択し、プロジェクトの追加を行います。
![スクリーンショット 2023-01-28 19.11.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634965/e665c984-e276-f7f3-b87a-3f45b372dc9a.png)


CircleCIの設定を含むGitHubブランチの名前として、mainを入力します。Set Up Projectをクリックします。

configが存在するブランチを入力します
![スクリーンショット 2023-01-28 19.11.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634965/d85152e8-97b9-ff20-fa33-a09b1ff6da96.png)


CircleCIはパイプラインを開始し、テストを実行します。
数分後、テストが全て通ると、緑色の成功バッジをクリックし、詳細を確認します。

![スクリーンショット 2023-01-28 19.12.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634965/f0b24286-f005-0911-ce08-7fced1984b32.png)
![スクリーンショット 2023-01-28 19.12.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634965/a2ea4ded-eef0-9338-f772-29f6f85cc3d6.png)


# おわりに
今回は実際にCircleCIブログで英語で紹介されているチュートリアルに挑戦し、和訳してみました。
Cypressの導入およびCircleCIとの連携は比較的にスムーズにできた印象ですが、さらにテストの量が多くなると、CircleCIジョブの実行時間が長くなる傾向があります。
ご自身およびチームの開発環境によって、最適なツールを選んでいただければ幸いです！

 
参考記事
[Testing React components with Cypress](https://circleci.com/blog/cypress-react-component-testing/)