E2EテストフレームワークのCypressとは？

# Cypressって何？

最近流行りのE2Eテストフレームワークになります。

スクレイピングライブラリのSeleniumと違い、完全にテストに特化したものになります。

~~もちろんCyと付いているが、Cygamesのものではない。~~

# こんな画面をテストしてみる

フォーム上に名前を書いたら、一覧に入力した名前が追加されます。

そして名前を押すと、押した名前が画面に表示されます。
<blockquote class="twitter-tweet"><p lang="zxx" dir="ltr"><a href="https://t.co/tlvXMOwSuD">pic.twitter.com/tlvXMOwSuD</a></p>&mdash; サラサラヌラヌラ (@abumai09) <a href="https://twitter.com/abumai09/status/1597586704227241985?ref_src=twsrc%5Etfw">November 29, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<details><summary>コード</summary><div>

```ts: トップページ
import { FormEvent, useState } from 'react';
import { Link } from "react-router-dom";

export const Names = (): JSX.Element => {
const [name, setName] = useState("");

const [names, setNames] = useState([
    'じーさん',
    '孫',
    'ゲベ',
    '校長',
    '最強さん',
    'ちゃむらい'
]);

/**
 * 名前一覧の表示タグの生成
 * 
 * @returns {JSX.Element[]} 
 */
const generateDisplayedName = (): JSX.Element[] => {
    return names.map((name, i) =>
        <div id={`name-${i}`}>
            <Link to={`/name/${name}`}>
                {name}
            </Link>
        </div>
    );
}

/**
 * 入力欄の入力値が変更されたときにnameに入力内容を適用させる
 * 
 * @param event 入力イベント
 */
const handleChangName = (event: React.ChangeEvent<HTMLInputElement>) => {
    setName(event.target.value);
};

/**
 * フォームのサブミット
 * 
 * @param event サブミットイベント
 */
const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    setNames([...names, name]);
}

return (
    <div>
        <h1>名前一覧</h1>
        <form onSubmit={handleSubmit}>
            <input
                type="text"
                value={name}
                name="name"
                onChange={handleChangName}
            />
            <input
                type="submit"
                value="名前の追加"
            />
        </form>
        <div className='names'>
            {generateDisplayedName()}
        </div>
    </div>
);
}
```

```ts: 名前を押すと遷移するページ
import { useParams } from 'react-router-dom';

export const Name = () => {
const { name } = useParams<{ name: string }>();

return (
    <div className='name'>{name}</div>
);
}
```

</div></details>

    

    

# Cypressのセットアップ

## Cypressのインストール

```
npm install -D cypress
```

## Cypressの設定画面を起動

### package.jsonに設定画面を起動するスクリプトの追加

```json
{
  "scripts": {
    "cypress:open": "cypress open"
  }
}
```

## 設定画面を起動

```
npm run cypress:open
```

## 起動中にこんなエラーが出たら

### Missing baseUrl in compilerOptions. tsconfig-paths will be skipped

```json
{
  "compilerOptions": {
    "baseUrl": "src"
  },
}
```

### dri3 extension not supported.

GUIアプリケーションが動かせない環境下で動かすと異常のエラーが発生します。

そのため、GUIを動かせるようにしないといけません。

WSL2であれば、以下の記事を参考にしましょう。
https://zenn.dev/ktny/articles/f8b92e34602fae

## 管理画面起動後

### E2Eテストを選択

![%E3%82%AD%E3%83%A3%E3%83%97%E3%83%81%E3%83%A3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500157/73f62a42-8e0e-bc3a-afd9-c7595b03dd88.png)


### Continueを選択して、設定ファイルを自動生成

![%E3%82%AD%E3%83%A3%E3%83%97%E3%83%81%E3%83%A3 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500157/27825d31-267f-6ad5-0dd2-d1966ddb1325.png)


### 好きなテスト環境を選択
Electronでテストを行う場合は、ブラウザの設定無しで動かすことができます。
![%E3%82%AD%E3%83%A3%E3%83%97%E3%83%81%E3%83%A3 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500157/eb2ecfa5-2edb-a181-4379-d43a5bda5cc1.png)


# E2Eテストをしてみる

```tsx
describe('トップページ', () => {
    beforeEach(() => {
        cy.visit('http://localhost:3000/');
    });

    it('名前一覧に「じーさん」が表示されているか', () => {
        // #name-0のテキスト属性は、「じーさん」であるか？
        cy.get('#name-0').should('have.text', 'じーさん');
    });

    it('フォームに「曽山」と入力して、「曽山」が名前一覧に表示されているか', () => {
        // <input type="text" name="name" /> に「曽山」と入力
        cy.get('[name="name"]').type('曽山');
        // submitボタンを押す
        cy.get('form').submit();
        cy.get('#name-6').should('have.text', '曽山');
    });

    it('「じーさん」のページに遷移する', () => {
        // #name-0に対して、直接クリックしてもaタグをクリックした事にならず、画面遷移はしない。
        cy.get('#name-0').children('a').click();
        // URLの日本語は、エンコードされた文字列じゃないと、trueにならない。
        cy.url().should('include', '/name/%E3%81%98%E3%83%BC%E3%81%95%E3%82%93');
        cy.get('.name').should('have.text', 'じーさん');
    });
});
```

<blockquote class="twitter-tweet"><p lang="zxx" dir="ltr"><a href="https://t.co/eKQ2CYsp03">pic.twitter.com/eKQ2CYsp03</a></p>&mdash; サラサラヌラヌラ (@abumai09) <a href="https://twitter.com/abumai09/status/1597598625097736192?ref_src=twsrc%5Etfw">November 29, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 最後に

Seleniumと違い、設定無しでE2Eテストの動作環境をElectronにできることはとても魅力的と感じました。

また、スクレイピング操作もSeleniumよりも簡単そうに感じました。

~~ま、俺様はSleniumは、にわかなんだけどな…..~~

今回Cypressを試したリポジトリ

https://github.com/kbc18a11/react-cypress-sample