CircleCI上からReactをCypressでテストする

# 概要
[Cypress + TypeScript + Reactを導入してみた](https://qiita.com/KbSota/items/efe1b812174578717c98)で作成したCypressテストをGitHubへのpushをトリガーにCircleCI上で動かしてみる。

# 事前準備
- Cypressのテスト(上記時にて作成済み)
- テスト対象のコード(上記時にて作成済み)
- CircleCIとの連携←ここではこれをやる

ちなみに対象のテストは、
`https://google.com`へのリンクをクリックし`Hello World!`が検索できるかをチェックするものです。

### CircleCIとの連携
https://circleci.com/ja/
こちらにアクセスして「ログイン」から「GitHubでログイン」
![スクリーンショット 2022-05-29 20.59.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636746/a751ed15-5dcf-48ed-324e-b9156ab34d4e.png)

連携するRepositoryを選択した。(今回だと「cypress」)
![スクリーンショット 2022-05-29 21.02.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636746/64dc77d5-fd4b-fbef-618e-c1d148c6b6d4.png)

`.circleci/config.yml`がないので一番下を選択。
(自力で`config.yml`作るので２番目で良かった気が。。。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636746/448da587-3fe3-168e-b230-38526b23eb69.png)

これでRepositoryとの連携は完了。
あとは`config.yml`を作成すればCircleCIでCypressが実行できる(はず)。

# config.yml作成
https://docs.cypress.io/guides/continuous-integration/circleci#Basic-Setup
Cypressの公式に親切にconfig.ymlの書き方があったので参考にします。
```yml:.circleci/config.yml
version: 2
jobs:
  build:
    docker:
      - image: cypress/base:14.16.0
        environment:
          TERM: xterm
    working_directory: ~/repo/e2e
    steps:
      - checkout:
          path: ~/repo
      - restore_cache:
          keys:
            - v1-deps-{{ checksum "package.json" }}
      - run:
          name: Install Dependencies
          command: npm install
      - run: ./node_modules/.bin/cypress install --force
      - save_cache:
          key: v1-deps-{{ checksum "package.json" }}
          paths:
            - node_modules
            - ~/.cache
      - run: npm run cy:cli

```
最後のコマンド`npm run cy:cli`の箇所で
`the cypress npm package is installed but the cypress binary is missing.`とのエラーが出たので
https://stackoverflow.com/questions/62319657/how-to-resolve-the-cypress-npm-package-is-installed-but-the-cypress-binary-is
こちらを参考に
`- run: ./node_modules/.bin/cypress install --force`を追加。

これでCircle CIは動くようになったのですが、肝心のReactを起動しないとテスト自体は失敗となる。
つまり、Circle CI上でReactを起動しながら、Cypressを実行する必要があるということ。

以下の二つが必要。(不細工な方法で実装した。)
- cypressフォルダからReactを起動すること
- Reactの起動を待ってからcypressを実行すること

### cypressフォルダからReactを起動
cypressの`package.json`に以下のような記述を追加。
```diff:package.json
"scripts": {
    "cy:gui": "cypress open",
    "cy:cli": "cypress run",
+    "React:start": "cd ../app && npm install && npm start"
  },
```
無理やりディレクトリ移動して、Reactをインストールして、起動するというコマンドを追加しました。。。
不細工ですよね、、

Reactのローカルサーバーは起動中は返答が返ってこないのでbackgroundタスクにしました。
```yml:config.yml
      - run:
          name: start React
          command: npm run React:start
          background: true
```
### Reactの起動を待ってからcypressを実行
このままcypressテストを実行してもReact起動前に実行されて失敗となるので無理やりwaitを入れました。。
(こちらは別のやり方がありそう)
```diff:config.yml
      - run:
          name: start React
          command: npm run React:start
          background: true
+      - run:
+          name: wait for React starts
+          command: sleep 60
      - run:
          name: e2e test
          command: npm run cy:cli

```

### ひとまず
これでひとまず
①GitHubへPush時にCircleCIが起動し
②ローカルのReactを
③cypressでテストする
ことができました。

```yml:config.yml
version: 2
jobs:
  build:
    docker:
      - image: cypress/base:14.16.0
        environment:
          TERM: xterm
    working_directory: ~/repo/e2e
    steps:
      - checkout:
          path: ~/repo
      - restore_cache:
          keys:
            - v1-deps-{{ checksum "package.json" }}
      - run:
          name: Install Dependencies
          command: npm install
      - run: ./node_modules/.bin/cypress install --force
      - save_cache:
          key: v1-deps-{{ checksum "package.json" }}
          paths:
            - node_modules
            - ~/.cache
      - run:  #ReactのInstallと起動
          name: start React
          command: npm run React:start
          background: true
      - run:  #React起動までのwait
          name: wait for React starts
          command: sleep 60
      - run:
          name: e2e test
          command: npm run cy:cli
```
```json:package.json
  "scripts": {
    "cy:gui": "cypress open",
    "cy:cli": "cypress run",
    "React:start": "cd ../app && npm install && npm start"
  },
```

# CypressのDashboard管理
これでCircleCIからe2eテストを実施できるようになったのですが、
CircleCIからはテストの結果が詳しくわかりません。
ローカルのようにscreenshotや動画が残りません。(CI上には残るのですがすぐ消えてしまいます)

## Dashboard
CypressはDashboardを用意してくれていて、
チームでプロジェクトを管理でき、無料プランでも過去500回のテスト結果を記録しておくことができます。

### 登録
https://dashboard.cypress.io/login
こちらからログインして登録することができます。

初回ログインのみ以下のような画面が出て、ユーザ登録が必要です。
![スクリーンショット 2022-06-02 22.45.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636746/ef718304-21ac-90ca-49b9-a5bc01cb848c.png)
スクリーンショット 2022-06-02 22.45.15

### 連携
projectを設定すると以下のような画面で`projectId`と`record key`が表示される。(後で何度でも確認できます)
![スクリーンショット 2022-06-02 22.47.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636746/491b32bf-c5e5-9778-23f8-016f4eab05be.png)
スクリーンショット 2022-06-02 22.47.16

それらを以下のように設定する。
```diff:cypress.json
{
  "baseUrl": "http://localhost:3000",
  "chromeWebSecurity": false,
+  "projectId": "******"
}
```
```diff:package.json
  "scripts": {
    "cy:gui": "cypress open",
-    "cy:cli": "cypress run",
+    "cy:cli": "cypress run --record --key ********************",
    "React:start": "cd ../app && npm install && npm start"
  },
```

これだけでCircleCIからテストを実行するとDashBoardへ反映される。
サイドペインの`Latest runs`から最新結果を確認できます。
また、GitHubのブランチやユーザ情報も自動で連携されているので、組織で利用できるようになっています。
(余談ですがAWSのCodeBuildは環境変数で渡さないといけないので大変でした)


#### Tips
CypressをCI上で実行した場合、動画が途中で終わってしまている場合があります。
https://github.com/cypress-io/cypress/issues/2370

[I've kind of 'made it work' by adding a wait(1000) to the end of the test...](https://github.com/cypress-io/cypress/issues/2370#issuecomment-481089880)
とか言っている人もいましたが、
最も簡単だと思う手法はテストの最後にスナップショットを撮ることです。
```diff:HellWorld.ts
it("is serching hello world", () => {
  cy.visit("/");
  cy.get("[data-cy=correct]").click();
  cy.url().should("contain", "google.com");
  cy.get('[name="q"]').type("Hello,World").type("{enter}");
+  cy.screenshot();
});
```
これで動画は最後まで撮られますし、証跡が増えるのも良いことだと思います。

# まとめ
- Circle CIのようなCI環境でもCypressは利用できる。
- Reactのローカルサーバをテストする場合は`package.json`のスクリプトをいじらないといけない。
- また、Reactを起動するまで、何らかの形でWaitを入れないといけない。
- CI上でテストする場合は、結果が残らないのでDashBoardを利用するのが吉
- ビデオが最後まで残らない場合は`cy.screenshot()`がおすすめ。