とんかつ時々あんどーなつ

〜たとえ低空でも飛行していられるように〜

Angular アプリケーションの E2E テストのフレームワークを Cypress に変更するまで

はじめに

この記事は Classi Advent Calendar 2020 の 10 日目の記事です。 昨日はそーだいさんが書いてくれました。

soudai.hatenablog.com

今回は Angular アプリケーションの E2E テストフレームワークを Cypress に変更する方法について紹介します。

Angular CLI でアプリケーションを作成すると標準で Protractor が E2E フレームワークとしてインストールされています。 $ ng e2e コマンドを打つだけで実行できるように環境設定がされているので、テストを書き始める敷居はとても低いと感じます。

一方で 公式ドキュメント を見ると AngularJS にも対応しているためか少し古いように感じます。(個人の感想です)

またロードマップに「E2Eテスト戦略のアップデート」があったり E2E テストに関するアンケート調査をしていることから、コアチームも現状の E2E テスト環境に課題感を持っているのではないでしょうか?

そこで今回は一度 Protractor を忘れて Cypress に置き換えてみよう、という話です。 Cypress について説明された記事はたぶんいっぱいあるので今回は割愛します。

Angular アプリケーションで使うには

今回はいかに「楽に」導入できるかを調べました。

Plugins | Cypress Documentation

f:id:kasaharu:20201203220050p:plain

とりあえず Cypress の plugins を見ると Angular で使えそうなものを 2 つほど発見(Cypress Angular Schematic, Nx)。 Cypress の環境だけを作るなら Cypress Angular Schematic の方が導入が楽そうに見えたので今回はそちらを試してみました。

Cypress Angular Schematic

導入

というわけで、本当に導入はすごく簡単で $ ng add コマンドを叩くだけでした。(こんなパッケージがあったのか…)

$ yarn ng add @briebug/cypress-schematic

コマンドを実行するとデフォルトの E2E テストとして存在する Protractor を削除するか聞かれるので、特に積み上げてきたテストがなければ削除を選んでいいと思います。

変更内容は以下のような感じ。

DELETE e2e
CREATE cypress.json (132 bytes)
CREATE cypress/tsconfig.json (140 bytes)
CREATE cypress/integration/spec.ts (103 bytes)
CREATE cypress/plugins/cy-ts-preprocessor.js (425 bytes)
CREATE cypress/plugins/index.js (158 bytes)
CREATE cypress/support/commands.ts (1377 bytes)
CREATE cypress/support/index.ts (651 bytes)
UPDATE package.json (1326 bytes)
UPDATE angular.json (4707 bytes)

angular.json の差分を見ると e2e architect の builder が @angular-devkit/build-angular:protractor から @briebug/cypress-schematic:cypress に変更されていることがわかります。 つまり $ yarn e2e で Cypress が起動するように自動で変更されています。かんたん!

実行と設定内容の確認

まずは実行してみる。

$ yarn e2e

e2e architect の options に devServerTarget が指定されているので e2e コマンドを実行すると Angular アプリケーションの serve も一緒に走ります(テスト時に自分で起動する必要がないので便利)。 Cypress のテストの実行モードには run と open の 2 つがあり、デフォルトでは open 相当で動作するため、実行すると下記のような Cypress アプリケーションが起動し Run 1 integration spec を押すとテストを実行できます。

f:id:kasaharu:20201205204005p:plain

この時点では、実行されるテストは cypress/integration/spec.ts のみです。

ここで CI で動かすことも考えて Cypress の実行モードとブラウザの種類を変更します。

先程も説明したようにデフォルトでは open 相当で動作するように設定されているため、run で動くように変更します。これで Cypress アプリケーションが起動しなくなります。 またブラウザはデフォルトで Electron が使用されるためこちらも Headless Chrome に変更します。こうすることですべてコマンドライン上で完結します。

diff --git a/angular.json b/angular.json
index c520c52..2cd5ccd 100644
--- a/angular.json
+++ b/angular.json
@@ -120,8 +120,9 @@
           "builder": "@briebug/cypress-schematic:cypress",
           "options": {
             "devServerTarget": "try-cypress-for-angular:serve",
-            "watch": true,
-            "headless": false
+            "watch": false,
+            "browser": "chrome",
+            "headless": true
           },
           "configurations": {
             "production": {

再度 $ yarn ng e2e を実行すると、テストは一回だけ走り終了することが確認できました。 しかし、デフォルトのテストでは Angular のアプリケーションに沿ったテストケースになっていないので失敗します。

テストの実装

改めてテスト中身を見てみます。 cypress.json を見ると integrationFolder に cypress/integration が指定されているので実行されているテストは cypress/integration/ 配下にあることがわかります。

cypress/integration/ には spec.ts が一つだけあり、コードは下記のようになっています。

it('loads examples', () => {
  cy.visit('/');
  cy.contains('Replace me with something relevant');
});

テストの内容は /(http://localhost:4200) にアクセスをして開いたページの中に Replace me with something relevant という文字列があるかを確認していました。当然 Replace me with something relevant という文字列はないのでテストが失敗しているというわけです。

元の Protractor のテストにあったように app-root .content span を見つけて <APP NAME> app is running! という文字列があることを確認するようにテストを書き換えるとテストは成功します。

diff --git a/cypress/integration/spec.ts b/cypress/integration/spec.ts
index 24e0ad1..a35f5a5 100644
--- a/cypress/integration/spec.ts
+++ b/cypress/integration/spec.ts
@@ -1,4 +1,4 @@
 it('loads examples', () => {
   cy.visit('/');
-  cy.contains('Replace me with something relevant');
+  cy.get('app-root .content span').should('contain', '<APP NAME> app is running!')
 });

これで Protractor から Cypress に置き換えることができました。

まとめ

Angular アプリケーションの E2E テストに Cypress を使いたいなーという思いから始まりましたが、簡単に置き換えられることがわかりました。 導入はできたので、今後は Cypress を使ったテストを書いていきたいと思いました。

今回試したリポジトリはこちら: GitHub - kasaharu/try-cypress-for-angular

というわけで、この記事は以上です。