• トップ
  • ブログ一覧
  • CypressでE2Eテストどやってみた!
  • CypressでE2Eテストどやってみた!

    ヨウ(エンジニア)ヨウ(エンジニア)
    2025.09.05

    IT技術

    はじめに

    最近テストの重要性を感じて、特にE2Eテストを導入したいなーって思ってました。
    そこで、Cypressを使って実際にプロジェクト作りながら学んでみることにしました!

    プロジェクト概要

    • Docker Composeで構築
    • フロントエンドはRemix、バックエンドはGoで実装
    • PostgreSQLを使用
    • Nginxをリバースプロキシとして設定
    • Cypressを使ってE2Eテストを実装
    • GitHub ActionsでCI/CDを設定

    やりたいこと

    • APIテスト
    • E2Eテスト
    • ビジュアルテスト
    • GitHub Actionsで自動テスト

    さっそく始めよう!

    今回はシンプルなブログアプリを作ってみます。
    APIのエンドポイントはこんな感じ:

    ヘルスチェック: GET /api/health

    ユーザーログイン: POST /api/user/signin

    ユーザー登録: POST /api/user/signup

    記事を取得: GET /api/posts/user

    記事を作成: POST /api/post

    フロントはRemixで、ログインと記事一覧ページを作ってみました。

     

    テストやってみよう!

    今回のメインイベント、Cypressをインストールします!

    npm install cypress --save-dev

    次に、Cypressの初期設定をやります。

    npx cypress open

    これでCypressのGUIが開きます!

    初回起動時にサンプルテストがいくつか生成されて、テストの雛形が用意されます。

    好きなブラウザを選択できます、便利だね。
    それでは、テストを書いていきましょう!

    APIテスト

    まずはAPIのヘルスチェックから。

    1describe("サーバーが動いてるかチェック", () => {
    2  it("ステータス200が返ってくる", ()=> {
    3   cy.request("GET", "http://localhost/api/health")
    4    .then((response)=> {
    5     expect(response.status).to.eq(200);
    6  });
    7 });
    8});
    いい感じ!!!
    次は、ユーザーのログインAPIをテストしてみます。
    1describe("ユーザールート", () => {
    2  it("有効なメールアドレスでサインインに成功するべき", () => {
    3    cy.request({
    4    method: "POST",
    5    url: `http://localhost/api/user/signin`,
    6    body: {
    7    email: "sample@mail.com" // 既存のテストユーザーを使用
    8    }
    9  }).then((response) => {
    10      expect(response.status).to.eq(200);
    11      // クッキーが設定されているかチェック
    12      expect(response.headers).to.have.property("set-cookie");
    13      cy.getCookie("sample-token").should('exist');
    14     });
    15  });
    16});

    続いては、ユーザがログインし、投稿までの流れでテストを書いてみたいです。

    1describe("ユーザがログインして投稿する", () => {
    2  const baseUrl = "http://localhost/api";
    3  const userEmail = "sample@mail.com";
    4  const testPost = {
    5  content: "この投稿はCypressからのテストです"
    6  };
    7  // まず、認証トークンを取得するためにサインイン
    8  before(() => {
    9    cy.request({
    10      method: "POST",
    11      url: `${baseUrl}/user/signin`,
    12      body: {
    13      email: userEmail
    14   }
    15  }).then((response) => {
    16    expect(response.status).to.eq(200);
    17  });
    18});
    19
    20it("新しい投稿を作成するべき", () => {
    21  cy.request({
    22    method: "POST",
    23    url: `${baseUrl}/post`,
    24    body: testPost
    25  }).then((response) => {
    26    expect(response.status).to.eq(201);
    27    expect(response.body).to.have.property("id");
    28    expect(response.body.content).to.eq(testPost.content);
    29  });
    30 });
    31})
    うまく出来ましたね!
    APIのテストはここまでにして、いよいよ本文に入りましょう!

    E2Eテスト

    E2Eテストでは、実際のユーザーの操作をマネして、アプリ全体の動きをチェックしていきます。

    まずは、ログインページにちゃんとアクセスできるかをテストします。

    1describe("ログインE2Eテスト", () => {
    2  it("ログインページにアクセスできる", () => {
    3    cy.visit("http://localhost");
    4    cy.get('input[name="email"]').should("exist");
    5    cy.get('button[type="submit"]').should("exist");
    6  });
    7});

    APIのテストとは違って、実際のブラウザが右側に表示されて、操作を確認しながらテストができます、Cypressの強力なところですね!

    次に、ログインフォームに入力して、ログインが成功してブログ一覧のページに遷移することをテストしたいです。

    1describe("ログインE2Eテスト", () => {
    2  it("ログインして、ブログ一覧に遷移", () => {
    3  cy.visit("http://localhost");
    4  cy.get('input[name="email"]').should("exist");
    5  cy.get('button[type="submit"]').should("exist");
    6  // インプットフィールドにメールアドレスを入力
    7+ cy.get('input[name="email"]').type("sample@mail.com");
    8  // ログインボタンをクリック
    9+ cy.get('button[type="submit"]').click();
    10  // ログイン後のクッキーが存在することを確認
    11+ cy.getCookie("sample-token").should("exist");
    12  // ログイン後のページが正しいことを確認
    13+ cy.location("pathname").should("eq", "/blog");
    14 });
    15});

    面白い!手動でブラウザを操作しているみたいですね!
    次は、ログイン失敗のケースもテストしてみます。
    1it("存在しないメールはログインに失敗する", () => {
    2  cy.visit("http://localhost");
    3  cy.get('input[name="email"]').should("exist");
    4  cy.get('button[type="submit"]').should("exist");
    5  cy.get('input[type="email"]').type("notfound@mail.com");
    6  cy.contains("ログイン失敗").should("not.exist");
    7  cy.get('button[type="submit"]').click();
    8  cy.contains("ログイン失敗").should("be.visible");
    9});
    これで、E2Eテストについてはだいぶイメージできたと思います。

    ビジュアルテスト

    ビジュアルテストでは、アプリの見た目が正しいかをチェックします。Cypressでは、プラグインを使って簡単にビジュアルテストができます。

    今度は`cypress-image-diff-js`を使います。

    テーマの切り替えとモバイルビューでのレイアウトを確認するためのビジュアルテストを書いてみます。

    1describe("ビジュアルテスト", () => {
    2  it("テーマ切り替えのビジュアル確認", () => {
    3    cy.visit("http://localhost");
    4    // スクリーンショット比較のため一貫したビューポートに設定
    5    cy.viewport(1280, 720);
    6    cy.get("div[data-testid='wrapper']").should('be.visible');
    7    // 初期状態のスクリーンショット比較を行う
    8    cy.compareSnapshot({
    9      name: '01-theme-dark-initial',
    10    });
    11    // テーマボタンの存在確認
    12    cy.get('button[theme-value]')
    13      .should("exist")
    14      .should("be.visible").click();
    15    // テーマ切り替え後のスクリーンショット比較を行う
    16    cy.compareSnapshot({
    17      name: '02-theme-light-after',
    18    });
    19  });
    20
    21it("モバイルレイアウトのビジュアル確認", () => {
    22  cy.signin();
    23
    24 // スクリーンショット比較のため一貫したビューポートに設定
    25  cy.viewport(1280, 720);
    26
    27  let userInfo = cy.get("div[data-testid='user-info']");
    28  userInfo.should('be.visible');
    29  // 特定要素のみのスクリーンショット比較を行う
    30  userInfo.compareSnapshot({
    31  name: '03-user-info',
    32  });
    33 // モバイルのビューポート設定
    34  cy.viewport(375, 667);
    35  userInfo = cy.get("div[data-testid='user-info']");
    36  // モバイルビューでの特定要素のスクリーンショット比較を行う
    37  userInfo.compareSnapshot({
    38    name: '04-user-info-sp',
    39  });
    40 });
    41});

    すると、Cypressがスクリーンショットを撮ってくれました。

    例えば、間違ってバックグラウンドの色を変更してしまった場合:
    1- const bg = theme === "dark" ? "bg-gray-900" : "bg-stone-100";
    2+ const bg = theme === "dark" ? "bg-gray-900" : "bg-stone-300"; // ここは値を変更

    もう一回テストを実行すると、差分があることを検知してくれます。

    すごくないですか?これで、見た目の変更が意図しないものになっていないかを簡単にチェックできます。

    GitHub ActionsでCI/CD

    最後に、毎回手動でテスト実行するのって結構忘れちゃうんですよね...😅
    なので、GitHub Actionsで自動テストも設定していきましょう!
    1- name: Cypress テスト実行
    2    uses: cypress-io/github-action@v6
    3    with:
    4      wait-on: http://localhost
    5      wait-on-timeout: 60
    6      working-directory: frontend
    7      start: npm run dev
    8      browser: chrome
    9      headed: false
    10      record: false
    これで、コードをプッシュしたら勝手にテストが走ってくれるんです!これがあると安心感が全然違います。

    まとめ

    今回、Cypressでテストを実装してみて、改めてテストの重要性を実感しました!
    実際にこの記事書いてる最中にもコードをちょくちょく修正してたんですけど、テストがあるおかげで不安にならずに済んだのが最高でした。
    Cypressは非常に強力で、コンポーネントテスト、E2Eテスト、ビジュアルテストまで幅広く対応できて、バグの原因も特定しやすいです。
    ぜひ皆さんも試してみてください!

     

    ライトコードでは、エンジニアを積極採用中!

    ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。

    採用情報へ

    おすすめ記事

    エンジニア大募集中!

    ライトコードでは、エンジニアを積極採用中です。

    特に、WEBエンジニアとモバイルエンジニアは是非ご応募お待ちしております!

    また、フリーランスエンジニア様も大募集中です。

    background