Protractorの代わりを探して~Cypress~

はじめに

みなさんはE2E(End to End)のテストツールは何を使っていますか?私のチームではAngularを使っているため、Angularにデフォルトで搭載されているProtractorを使っています。Protractorは2013年からAngularチームが開発してきたE2Eツールで、Selenium WebDriver APIのラッパーとして機能しており、テストコードはJasmineやMochaを使ってテストが書けました。

このProtractor……なんとAngular v15でサポートが終了してしまいます…
https://github.com/angular/protractor/issues/5502

要約すると、以下のような内容になります。簡単に言ってしまうと、E2Eのツールは他にも良いものがあるので、そちらを使ってほしいってことですね。

・WebDriver APIがまだ標準でない頃(2013年)非同期処理をサポートしたE2EテストのためにProtractorを開発した
・WebDriverJS(Selenium)やProtractorはPromise Manager(あるいはControl Flow)と呼ばれる機能を実装し、E2Eテストケースの記述にPromiseが登場しないようにした
・Promise Managerなしでも同期処理のような書き方でテストが書けるようになった
・ES2017ベースにProtractorを作り変えるのは非常にコストが掛かるためサポートを終了する
 元々AngularJSアプリの為のE2Eテストツールだったが、AngularJSもEOLなので維持する必要がなくなった

Protractorのサポートが終了してしまうAngular v15。v15のリリースが2022の冬となっているため、早急にProtractorの代替ツールの検討が必要になります。この記事は、Protractorの代わりとなるE2E自動化ツールの候補のうちの1つを掘り下げて、紹介するものとなっています。

E2E自動化ツール

E2E自動化ツールといっても数多くありますので、まずは3つに分けて紹介します。

分類分け

WebDriver API型

ブラウザの自動操作を行う手段として、WebDriver APIを利用するタイプです。WebDriverはユーザーエージェントのイントロスペクションと制御を可能にするリモートコントロールインターフェイスです。Webドキュメント内のDOM要素を検出および操作して、ユーザーエージェントの動作を制御するための一連のインターフェイスが提供されています。このWebDriverを介してブラウザをリモートで操作してユーザーエージェントの自動化を図ります。マルチブラウザに対応しており、Protractorで採用されている方式ですが、WebDriver、Karma、Selenium等々セットアップが大変です。また、Protractorがそうなのですが、内部でSeleniumを使っているものが大半です。

WebDriver

JavaScript注入型

JavaScriptをページに流し込んでブラウザを操作する注入タイプです。ブラウザに組み込まれているため、Seleniumと比べて多くのことができます。これの特徴は、とにかく実行が早く、セットアップが簡単であるという点です。しかし、WebDriver API型と違い、マルチブラウザへの対応はツールによってまちまちです。

有名どころとしては、CypressTestCafeNightmareが挙げられます。

注入型

開発者ツールAPI型

こちらは、調べた限りではPuppeteerしか見つからなかったので、Puppeteerの説明になります。DevToolsプロトコルを介してChromeまたはChromiumを制御するための高レベルAPIを提供するNodeライブラリです。Chrome拡張機能のテストに使われることが多いそうです。セットアップはほぼ不要なのですが、特定のブラウザの開発者ツールを使いますので、マルチブラウザには対応していません。

puppeteer

Cypress

これら自動化ツールの中でCypressについて掘り下げて紹介したいと思います。

前述したサポートを終了するという旨の記事に、Angularチームが自動化テストツールについてのアンケートが載っていました。そのアンケートによると、E2Eテストツールの中でCypressが一番使われていたため、今回取り上げることにしました。

アンケート結果

Cypressとは

ブラウザでのテスト作業を自動化するテストフレームワークで、さきほどJavaScript注入型で紹介したツールの1つです。

CypressはオープンソースのローカルにインストールされたCypress Test Runnerとテストを記録するためのCypress Dashboardで構成されています。Cypress Test Runnerは無料で提供されていますが、Cypress Dashboardは有料で使用することが出来ます。 ブラウザはChrome、FireFox、Edgeに対応している他、ElectronとBraveにも対応しています。 対応ブラウザ

Cypress Test Runner

Cypressの専用コンポーネントテストランナーで、実際の対話をシミュレートすることで、ブラウザでコンポーネントテストを実行します。

  • テストステータスメニュー
    テストの実行結果の概要とリトライ等のコマンドボタンを表示します。
  • URL プレビュー
    テスト中にアクセスしているページのURLを表示します。
  • ビューポイントサイズ
    プレビューに表示されている画面のサイズを表示します。
  • コマンドログ
    テストスイートを視覚的に表したものです。各テストブロックは適切にネストされており、各テストをクリックすると、テストのブロック内で実行されたコマンドやアサーションが表示されます。
  • アプリケーション プレビュー
    実行中の画面を表示します。

012

Cypress Dashboard

Cypress Dashboardは実行したテスト内容を録画して後から確認することが出来るサービスで、Jenkins、Travis CI、Circle CI、Dockerと連携が可能です。ダッシュボードでは、成功・失敗を確認することができ、失敗したテストのスタックトレース全体を取得します。また、Cypressの機能で実行したテストを録画出来るので、失敗時の挙動を動画で確認することが出来ます。Cypress Dashboardは有料で提供されていますが、500 Test Results(it()関数の呼び出しにつき1 Test Result)までは無料で使うことが出来ます。

Cypressの特徴

Cypressの公式サイトでは、以下の7つをCypressの特徴として挙げていました。

1. Seleniumを使用しない

ほとんどのE2EテストツールはSeleniumベースであるため、すべて同じ問題を抱えています。Seleniumはネットワークを介してリモートコマンドを実行しますが、Cypressはアプリケーションと同じ実行ループで実行されます。

2. WebアプリケーションのE2Eテストの作成に焦点を当てている

Cypressは、一般的な自動化フレームワークではなく、バックエンドサービスの単体テストフレームワークでもありません。それを行う優れたツールはすでに存在します。Cypressは1つのことに特化しています。それは、WebアプリケーションのE2Eテストを作成するときに優れたエクスペリエンスを作成することです。

3. あらゆるフロントエンドフレームワークorWebサイトで動作する

Cypressは、Webブラウザで実行されるすべてのものをテストします。Cypressを取り巻くすべてのアーキテクチャは、最新のJavaScriptフレームワークを特にうまく処理するように構築されています。最新のReact、Angular、Vue、Elmなどのフレームワークを使用した何百ものプロジェクトがあります。Cypressは、古いサーバーでレンダリングされたページやアプリケーションでも同様に機能します。

4. テストコードはJavaScriptでのみ記述

他の言語からJavaScriptにコンパイルすることもできますが、最終的には、テストコードはブラウザー自体の内部で実行されます。言語やドライバーのバインディングはありません。JavaScriptが存在し、これからも存在するでしょう。

5. 他のモジュールを必要としない(オールインワン)

エンドツーエンドのテストを作成するには、さまざまなツールを使用して連携する必要があります。Cypressを入手できます。テストスイートをセットアップするために、10個の個別のツールとライブラリをインストールする必要はありません。すでにおなじみのクラス最高のツールをいくつか採用し、それらすべてをシームレスに連携させました。

6. 開発者やQAエンジニア向け(速くコーディングできる)

Cypressは、アプリケーションを構築するときに使用するときに最高の状態になります。私たちはあなたにできるだけ速くコーディングする力を与えます。

7. 高速実行

Cypressは、テストと開発を同時に行うことができるように構築されています。テストを使用して開発プロセス全体を推進しながら開発を迅速化でき、変更はリアルタイムで反映されます。最終的には、開発が進み、コードが改善され、完全にテストされます。ダッシュボードサービスを利用した場合、並列化と自動負荷分散により、テスト速度がさらに向上します。

Cypressで出来ること・出来ないこと

Cypressでは様々なことが出来ます。

  • テスト実行時にスナップショットを取得する
    コマンドログのコマンドにカーソルを合わせるだけで、各ステップで何が起こったかを正確に確認できます。
  • テスト実行中のデバッグが可能
    Chrome DevToolsなどの使い慣れたツールから直接デバッグします。読み取り可能なエラーとスタックトレースにより、デバッグが非常に高速になります。
  • リアルタイムのリロード
    テストに変更を加えるたびに、Cypressは自動的にリロードします。
  • 自動待機
    Cypressは、先に進む前にコマンドとアサーションを自動的に待機します。もう非同期地獄はありません。
  • スパイ、スタブ、時計の作成・制御が可能
    機能、サーバー応答、またはタイマーの動作を確認および制御します。ユニットテストで気に入っているのと同じ機能がすぐに利用できます。
  • ネットワークトラフィック制御
    サーバーを使用せずに、エッジケースを簡単に制御、スタブ、およびテストできます。ネットワークトラフィックは好きなようにスタブできます。
  • 一貫した結果
    私たちのアーキテクチャはSeleniumやWebDriverを使用していません。フレークのない高速で一貫性のある信頼性の高いテストを提供します。
  • 失敗時にスクリーンショットの撮影とテスト全体のビデオの撮影が可能
    失敗時に自動的に撮影されたスクリーンショット、またはヘッドレスで実行した場合のテストスイート全体のビデオを表示します。

特出すべきは、Protractorにはないスナップショットを取得できることですね。各アクションの状態にすぐ戻れますし、失敗したテストケースの原因究明に大いに役立ちます。

また、Seleniumを使用しないことで、できることが増えたのですが、代わりに以下の制約があります。

  • 1つのテストケースで複数のスーパードメインを操作できない
  • 複数タブ・ウィンドウを操作できない

複数タブ・ウィンドウを想定にしたテストケースが多い場合は、採用は難しいでしょう。

Cypressの仕組み

CypressがProxyになり、テストスペックを対象アプリと同じドメインに見せかけることで、DOMやストレージへの直接アクセスが可能となっています。スナップショットが撮れる仕組みもDOMへの直接アクセスが可能なために出来るのではないかと思われます。

アーキテクチャ

Cypressを使う

  1. プロジェクト作成

何はともあれAngularプロジェクトを作りましょう。プロジェクト名はなんでも良いのですが、ここは「demo」にしておきます。

$ ng new demo
  1. Cypressをインストール

作ったプロジェクトにCypressをインストールします。1行目はグローバルインストールなので、1度実行した事があるのなら実行しなくても大丈夫です。

$ npm install -g @briebug/cypress-schematic
$ ng add @briebug/cypress-schematic

Protractorを削除するか聞かれるので、yesを入力してください。

? Would you like to remove Protractor from the project? yes

yesにすると、e2eのフォルダが削除されてcypressのフォルダが作成されます。

011

  1. サーバを起動
$ ng serve
  1. Cypressを起動

このコマンドを実行すると、Cypressが起動します。

$ npx cypress open
  1. テストを実行

INTEGRATION TESTSに作成したテストファイルが表示されますので、実行したいテストをクリックすると、Cypress Test Runnerが起動してテストが実行されます。

013

テストコードを書く

テストケースの1例を書いてみました。ログイン画面で「user」と「password」を入力してログインするコードになっています。describeitといったものはProtractorと同じですが、コマンドは異なります。

describe('ログイン'、 () => {
  it('通常ログイン'、 () => {
    // http://localhost:4200/ にアクセス
    cy.visit('/');
    // id="userInput"に「user」を入力
    cy.get('#userInput').type('user');
    // id="passwordInput"に「password」を入力
    cy.get('#passwordInput').type('password');
    // id="loginButton"の要素をクリック
    cy.get('#loginButton').click();
    cy.location().should((loc) => {
      // http://localhost:4200/client に遷移しているかチェック
      expect(loc.pathname).to.eq('/client')
    })
  });
});

012

APIリファレンスはこちらに載っていますので、そちらを参考にしてください。

おわりに

今回Cypressを紹介しましたが、E2Eテストツールは数多くあります。Protractorと比べてCypressは実行が早く、各アクションの状態に戻せるのは強い利点だと思います。ただ、コードは同じものを使えないので、移行するということを考えるとなると、修正コストと相談にはなりますが、Cypress Dashboardまで利用するつもりでいるのなら、Cypresを採用する価値は大いにあります。それぞれの環境・状況に応じて採用していくと良いでしょう。

ALPHA SYSTEMS INC.

株式会社アルファシステムズは、ITサービス事業を展開しています。このブログで、技術的な取り組みを紹介しています。