Open1

Cypressの初期設定

mu0363mu0363

CypressをTypescriptで初期設定するときの備忘録。


依存ライブラリをインストール

npm install -D cypress @testing-library/cypress env-cmd start-server-and-test

env-cmd

.env.local, .env.develop.loocal, .env.test.localを環境ごとに使い分けるためのライブラリ

start-server-and-test

e2eテスト実行には一度ビルドしてから立ち上げたサーバーとは別にテスト用のサーバーを立ち上げなければいけないのを簡単にしてくてるライブラリ

package.json

package.json
  "scripts": {
    "db:reset": "source scripts/reset-db.sh",
    "build:test": "npm run db:reset && export NODE_ENV=\"test\" && next build",
    "start:test": "export NODE_ENV=\"test\" && next start",
    "cypress:open": "env-cmd -f .env.test.local cypress open",
    "cypress:start": "start-server-and-test 'npm run start:test' 3000 'npm run cypress:open'",
    "cypress:build": "npm run build:test && npm run cypress:start"
  },

tsconfig.json

tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["es5", "dom"],
    "types": ["cypress", "node"]
  },
  "include": ["**/*.ts"]
}

e2e.ts

cypress/support/e2e.ts
import "@testing-library/cypress/add-commands";

cypress:buildを実行するとビルドが走り、ビルド終了後Cypressのブラウザが立ち上がる。


ダイナミックルートのテスト

ダイナミックルートのテストには以下の3種類がある

  1. ビルド時にすでに存在している静的ページ
  2. 動的ページでビルド時に存在しているページ(存在してないページへのエラーページ含む)
  3. これから追加する動的ページ

1. ビルド時にすでに存在している静的ページへのテスト

cypress/e2e/routes/routes.cy.ts
describe("routes.cy.ts", () => {
   it("displays correct heading when navigating to shows route", () => {
    cy.visit("/");
    cy.findByRole("button", { name: /shows/i }).click();
    cy.findByRole("heading", { name: /upcoming shows/i }).should("exist");
  });

  it("display correct heading when navigating to bands route", () => {
    cy.visit("/");
    cy.findByRole("button", { name: /bands/i }).click();
    cy.findByRole("heading", { name: /Our Illustrious Performers/i }).should(
      "exist"
    );
  });
});

export {};

一度ビルドした後はcypress:startでテストを再実行できる。

2. 動的ページでビルド時に存在しているページ(エラーページ含む)

cypress/e2e/routes/routes.cy.ts
describe("routes.cy.ts", () => {
// ...省略

// リセット後、最初に存在するバンドページのタイトルをテスト
  it("displays correct band name for band route that existed at build time", () => {
    cy.task("db:reset").visit("bands/1");
    cy.findByRole("heading", { name: /Shamrock Pete/i }).should("exist");
  });

// リセット後、存在しないバンドページのエラー文をテスト
  it("displays error message for band not in db", () => {
    cy.task("db:reset").visit("/bands/12345");
    cy.findByRole("heading", { name: /Error: band not found/i }).should(
      "exist"
    );
  });
});

3. 動的ページを追加した場合

まずバンドを追加する関数をcypress.config.tsへ追加しcy.task()で使用できるようにする

cypress.config.ts
export default defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      on("task", {
        "db:reset": () => resetDB().then(() => null),
        // 追加
         addBand: (newBand) => addBand(newBand).then(() => null),
      });
    },
  },
});
cypress/e2e/routes/routes.cy.ts
describe("routes.cy.ts", () => {
// ...省略

// リセット後、新しくバンドを追加後ページが生成されているかテスト
  it("displays name for band that was not present at build time", () => {
    const bandId = generateRandomId();
    const newBand = generateNewBand(bandId);
    cy.task("db:reset").task("addBand", newBand).visit(`bands/${bandId}`);
    cy.findByRole("heading", { name: /Avalanche of Cheese/i }).should("exist");
  });  });
});

デプロイ時のCIでJestとCypressを実行する

JestとCypressを実行する前に、まずはCypressをCI内で実行できるスクリプトを追加する。
ローカルでのテストではcypress:openで実際のブラウザを立ち上げてテストしていたが、
CI内では起動させずにcypress runコマンドを用いる

package.json
"scripts": {
// ...省略
 "cypress:run": "start-server-and-test 'npm run start:test' 3000 'env-cmd -f .env.test.local cypress run'"
},

実行するとCypressがmp4の映像ファイルをcypressディレクトリー内に自動生成するので.gitignoreに追記する

.gitignore
# cypress
cypress/videos

jestを実行

npm test

現状だとエラーがでる。なぜならプロジェクトディレクトリ全体のテストファイルを見てJestがテストを実行しようとし、Cypressのテストファイルも含めてテストを試みたので、Jestに『cyなんかないよ』と怒られる。なのでJestのテストするディレクトリを限定させる。

jest.config.js
// ...省略
const customJestConfig = {
  setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
  // /__tests__/.*/.*を追加
  testRegex: "/__tests__/.*/.*\\.test\\.[jt]sx?$",
/// ...省略
};