LoginSignup
0
1

More than 1 year has passed since last update.

Cypress + TypeScript + Reactを導入してみた

Posted at

概要

業務でCypressを触る機会があったので、
CypressテストをTypeScriptで書いてみて、簡単なReactアプリの上で実行してみます。

Cypressとは

  • E2Eテストのツールでブラウザベース(Chrome,FireFox,Edge)でのテストを実行可能。
  • HTMLエレメントを直感的に指定してコードを書くことが可能なツール。
  • Node.js環境で速やかに構築・実行が可能。

導入

インストール

TypeScript側の方がわかりやすかったのでそちらを参考に進めます

環境

OSはmacOS Monterey 12.2.1

% node -v
v18.0.0

手順

% mkdir e2e
% cd e2e
# 初期化。package.jsonの作成
% npm init -y 
# TypeScript、Cypressのインストール
% npm install cypress typescript
added 166 packages, and audited 167 packages in 29s

27 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

# tsconfig.jsonの作成
% npx tsc --init --types cypress --lib dom,es6
Created a new tsconfig.json with:
  target: es2016
  module: commonjs
  lib: dom,es6
  strict: true
  types: cypress
  esModuleInterop: true
  skipLibCheck: true
  forceConsistentCasingInFileNames: true


You can learn more at https://aka.ms/tsconfig

# cypress.json(cypress設定ファイル)の作成
% echo {} > cypress.json

作成されたファイル

package.json
{
  "name": "e2e",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "cypress": "^9.7.0",
    "typescript": "^4.7.2"
  }
}
tsconfig.json
{
  "compilerOptions": {
    "target": "es2016",
    "lib": ["dom", "es6"],
    "module": "commonjs",
    "types": ["cypress"],
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  }
}
cypress.json
{}

テスト作成

e2e/cypress/integration以下にテストを作成。

e2e/cypress/integration/HelloWorld.ts
it("is serching hello world", () => {
  cy.visit("https://google.com");
  cy.get('[name="q"]').type("Hello, World!").type("{enter}");
});
  • テストはitで始めます。構文はit("説明",()=>{テスト})です。
  • テストでcypressを利用する際はcy.〇〇でコマンドを書きます。
    cy.visit(URL)でURLへアクセス
    cy.get()でHTML要素の取得などです。
  • コマンドのリファレンスはこちら

テスト実行

テストは2通りの方法で実行可能。

  • GUIベースの実行。コマンドはnpm run cypress open
  • CLIベースの実行。コマンドはnpm run cypress run

package.jsonに記述しておきます。

package.json
{
  "name": "e2e",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
-    "test": "echo \"Error: no test specified\" && exit 1"
+    "cy:gui": "cypress open",
+    "cy:cli": "cypress run"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "cypress": "^9.7.0",
    "typescript": "^4.7.2"
  }
}

GUIテスト実行

% npm run cy:gui

初回はIt looks like this is your first time using Cypress: 9.7.0と表示された後、以下のような画面が立ち上がる。
image.png
HelloWorld.tsをクリックするとテストが開始される。
デフォルトではChrome上で開始されるが、--browser ***としてブラウザを指定すると任意のブラウザで実行できる。
https://docs.cypress.io/guides/guides/launching-browsers#Browsers

Reactアプリのテスト

Google検索で「Hello,World!」が検索できることをテストしました。
だが、実際はGoogleやAmazonのWebサイトをテストするのではなく、自分のアプリをテストするのに使うはず。
なので、実際に(かなり初歩的な)アプリを作ってcypressでE2Eテストを実装していくこととします。

Reactアプリ作成

Reactをインストールして、https://google.comへのリンクを作成しました。

index.ts
import React from "react";
import ReactDOM from "react-dom/client";
import GoogleLink from "./GoogleLink";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <div>
      <GoogleLink />
    </div>
  </React.StrictMode>
);
GoogleLinx.tsx
function GoogleLink() {
  return (
    <>
      <a href="https://google.com">Google</a>
    </>
  );
}

export default GoogleLink;

Reactアプリテスト

Cypressの方も少し修正します。

e2e/cypress.json
- {}
+ { "baseUrl": "http://localhost:3000/", "chromeWebSecurity": false }
e2e/cypress/integration/HelloWorld.ts
it("is serching hello world", () => {
-  cy.visit("https://google.com");
+  cy.visit("/");
+  cy.contains("Google").click();
-  cy.get('[name="q"]').type("Hello, World!").type("{enter}");
+  cy.url().should("contain", "google.com");
});

テストとしてはReactアプリ上のリンクをクリックしてgoogle.comを含むURLにリンクできるかのテストを作成しました。
※今回はこのようなテストを作成しますが、cypressは外部リンクにアクセスするようなE2Eテストを推奨していません。
https://docs.cypress.io/guides/references/error-messages#Cypress-detected-a-cross-origin-error-happened-on-page-load

Best Practice

CypressのBest PracticeではHTML要素の取得のしかたが記述されています。
https://docs.cypress.io/guides/references/best-practices#Selecting-Elements
image.png

今回の例のようにcy.contains()を利用して要素を取得するのは「Best」ではないです。
というのも、似たような文言が羅列されているページではcontainsつまりページ上の文字では判別がつかないことが多いからです。

Reactを以下のように修正してみました。

DummyLink.tsx
function DummyGoogleLink() {
  return (
    <>
      <a href="">Dummy Google</a>
    </>
  );
}

export default DummyGoogleLink;
index.ts
import React from "react";
import ReactDOM from "react-dom/client";
import DummyGoogleLink from "./DummyLink";
import GoogleLink from "./GoogleLink";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
+    <div>
+      <DummyGoogleLink />
+    </div>
    <div>
      <GoogleLink />
    </div>
  </React.StrictMode>
);

これで同じテストを実行してみると、
Dummy Googleリンクをcypressがクリックして失敗してしまいます。
「Google」という文言がcontainしているからです。

これを避けるためにBest Practiceである。data属性を追加してみます。

GoogleLinx.tsx
function GoogleLink() {
  return (
    <>
-      <a href="https://google.com">Google</a>
+      <a data-cy="correct" href="https://google.com">Google</a>
    </>
  );
}

export default GoogleLink;
DummyLink.tsx
function DummyGoogleLink() {
  return (
    <>
-      <a href="">Dummy Google</a>
+      <a data-cy="dummy" href="">Dummy Google</a>
    </>
  );
}

export default DummyGoogleLink;
HelloWorld.ts
t("is serching hello world", () => {
  cy.visit("/");
-  cy.contains("Google").click();
+  cy.get("[data-cy=correct]").click();
  cy.url().should("contain", "google.com");
});

こちらでテストすると想定通り、Googleへリンクし成功します。
image.png

まとめ

  • CyoressはNode.js環境で速やかに構築・実行ができるE2Eテストツール。
  • デプロイ後でもローカルでもテストが可能。
  • 要素取得の際にはあらかじめ付与したdata属性を用いてテストを記述するのがBest Practice。
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1