概要
業務で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
作成されたファイル
{
"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"
}
}
{
"compilerOptions": {
"target": "es2016",
"lib": ["dom", "es6"],
"module": "commonjs",
"types": ["cypress"],
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}
{}
テスト作成
e2e/cypress/integration以下にテストを作成。
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に記述しておきます。
{
"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
と表示された後、以下のような画面が立ち上がる。
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
へのリンクを作成しました。
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>
);
function GoogleLink() {
return (
<>
<a href="https://google.com">Google</a>
</>
);
}
export default GoogleLink;
Reactアプリテスト
Cypressの方も少し修正します。
- {}
+ { "baseUrl": "http://localhost:3000/", "chromeWebSecurity": false }
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
今回の例のようにcy.contains()
を利用して要素を取得するのは「Best」ではないです。
というのも、似たような文言が羅列されているページではcontains
つまりページ上の文字では判別がつかないことが多いからです。
Reactを以下のように修正してみました。
function DummyGoogleLink() {
return (
<>
<a href="">Dummy Google</a>
</>
);
}
export default DummyGoogleLink;
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属性を追加してみます。
function GoogleLink() {
return (
<>
- <a href="https://google.com">Google</a>
+ <a data-cy="correct" href="https://google.com">Google</a>
</>
);
}
export default GoogleLink;
function DummyGoogleLink() {
return (
<>
- <a href="">Dummy Google</a>
+ <a data-cy="dummy" href="">Dummy Google</a>
</>
);
}
export default DummyGoogleLink;
t("is serching hello world", () => {
cy.visit("/");
- cy.contains("Google").click();
+ cy.get("[data-cy=correct]").click();
cy.url().should("contain", "google.com");
});
こちらでテストすると想定通り、Googleへリンクし成功します。
まとめ
- CyoressはNode.js環境で速やかに構築・実行ができるE2Eテストツール。
- デプロイ後でもローカルでもテストが可能。
- 要素取得の際にはあらかじめ付与したdata属性を用いてテストを記述するのがBest Practice。