【Cypress】Next.jsにE2Eテストツールを導入してみた

# はじめに

E2Eテストツールを使用したことがなかったので、Cypressについて調べつつ触ってみた時の手順をざっくりまとめました。

# 概要

- Cypressとは
- 導入方法
    - Next.js
    - Cypress
    - テストコードの例

# Cypressとは

前提として、E2Eテストはシステム全体を通して行うテストのことです。
Webアプリの場合はユーザーと同じようにブラウザを操作し期待する結果になるかをテストします。

Cypressは上記のE2Eテストを実装するためのツールになります。

# 導入方法

最終的になNext.jsとCypressのディレクトリ構成です。

    my-app
    │
    ├── .next/
    ├── .cypress/
    │   └── e2e/
    │       └── sample-spec.cy.ts
    ├── .tsconfig.json
    ├── package.json
    └── package-lock.json

    ※他にもNext.js用のファイル群は存在しますが、説明に必要なものだけを記述してます。


## Next.js

任意の作業用のディレクトリ内で ```npx create-next-app``` を実行するとNext.jsのプロジェクトが作成されます。（アプリ名は「my-app」とします）

事前準備としてNode.jsのインストールが必要ですが、今回は説明を省略します。

    my-app
    │
    ├── .next
    ├── .tsconfig.json
    ├── package.json
    └── package-lock.json

    ※他にもNext.js用のファイル群は存在しますが、説明に必要なものだけを記述してます。

## Cypress

my-app 直下に入り、```npm i cypress``` を実行するとCypressがインストールされ、```npx cypress open``` で Cypressを起動することができます。

<br>

E2Eテストなので左を選択

![スクリーンショット 2024-06-23 151508.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/eaffc99b-ca2f-51ec-7c12-c4f2be032e4b.png)

<br>

使用するブラウザを選択して「Start E2E Testing in ~」をクリック

![スクリーンショット 2024-06-23 151520.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/dbbe634d-3f40-e874-2b1a-f30c4e824607.png)

<br>

するとCypressの管理画面が開きます。

![スクリーンショット 2024-06-23 151544.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/0b453658-2566-42cc-d183-68c65f0b64fd.png)

<br>

セットアップに関してはこれで完了ですが、最後にテストコードの書き方についても少しだけ触れます。

## テストコードの例

管理画面のサイドメニュー「Specs」を選択し、右側の「+ New spec」をクリックすると新しいspecファイル（テストファイル）を作成できます。

![スクリーンショット 2024-06-23 152237.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/7413a3f6-8e29-3086-4e4d-9487db85fb73.png)

右側の「Create new spec」を選択すると

![スクリーンショット 2024-06-23 152348.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/47ea3c4e-d7a3-d9c8-bca8-fc704a4a4abe.png)

名前を付けてspecファイルを作成できます。

<br>

ここで作成したspecファイルは「.cypress/e2e/」の中に配置されます。

    my-app
    │
    ├── .next/
    ├── .cypress/
    │   └── e2e/
    │       └── spec.cy.ts
    ├── .tsconfig.json
    ├── package.json
    └── package-lock.json

![スクリーンショット 2024-06-23 152635.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/7c230e93-330d-20f0-6536-af67e1e22878.png)

<br>

では実際にテストコードを書いていきます。

今回は事前に用意したNext.jsのログイン画面を対象にテストします。

```ts
describe('ログイン画面', () => {

  it('初期表示時', () => {
    cy.visit('http://localhost:3000/login');
    cy.get('[data-cy=login-form-userId]').should('have.value', '');
    cy.get('[data-cy=login-form-password]').should('have.value', '');
  });

});

```

テストコードにある項目については、

- describe：大項目テストタイトル（画面名など）
- it      ：各テスト項目

のような感じです。この辺の切り分けについては色々な方法があると思います。

<br>

例えば以下のテストでは初期表示時の画面に関するテストをしています。

まずはcy.visit()でテストしたい画面のリンクを渡して、テスト対象の画面を指定します。

cy.get()でHTMLの要素を取得し、should()でその要素がどうあるべきかという検証を行います。
cy.get()ではidやclassも指定することができますが、「data-cy」のような専用の属性を使用することが一般的です。

```ts
describe('ログイン画面', () => {

  it('初期表示時', () => {
    cy.visit('http://localhost:3000/login');
    cy.get('[data-cy=login-form-userId]').should('have.value', '');
    cy.get('[data-cy=login-form-password]').should('have.value', '');
  });

```

今回は input要素であるユーザーIDとパスワードの入力欄が、初期表示時点で値を持たないこと（=空文字）を検証します。

<br>

Cypressの管理画面「Specs」メニューからテストファイル名をクリックして実際にテストを実行すると、

![スクリーンショット 2024-06-23 154419.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/1161d523-0f12-7ffa-1efd-0784e1e4f62b.png)


![スクリーンショット 2024-06-23 154344.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/f4a24e8d-af8e-8564-bdcc-92a373ced14e.png)

こんな感じで自動的にテストが実行されました。

<br>

今回は要素の初期値だけを検証しましたが、他にも

- 要素が存在するか
- 要素を入力／選択した時
- フォーカスアウトした時
- ボタンをクリックした時
- メッセージの表示内容
- 正しく画面遷移するか
 
など、実際に画面で操作することができる様々な挙動を検証することが可能です。

<br>

Cypress に関しては下記の記事がわかりやすかったので、ぜひ読んでみてください。

https://qiita.com/n_takechi/items/7fb80a353505065502ef