E2ETestCafeを使用したAngularアプリケーションのテスト
TestCafe は、Webアプリケーションをテストするための無料のオープンソースNode.jsツールです。 その主な利点の1つは、セットアップとテストの開始に約1分かかることです(WebDriverを使用しません)。
最も一般的なオペレーティングシステムとブラウザで動作します。 テストはJavaScriptまたはTypeScriptで記述されています。
この記事では、Angularアプリケーションのテストについて具体的に説明します。 次の方法を学習します:
- テスト環境のセットアップ
- Angularセレクターを使用して基本的なテストを作成する
- ページモデルパターンでテストを改善する
- 失敗したテストをデバッグする
テスト用のセットアップ
まず、Node.jsバージョン4.x以降がインストールされていることを確認します。
2つのnpmモジュールが必要です。TestCafe自体と、Angularセレクターを備えたプラグインです。 次のコマンドを実行します。
$ npm i testcafe testcafe-angular-selectors
AngleAugury拡張機能もGoogleChromeにインストールしましょう。 これを使用して、アプリケーションのコンポーネントツリーでコンポーネントセレクターを検索します。
これで、テストの準備が整いました。
簡単なテストを書く
サンプルのBookCollection Angularアプリケーションをテストします。ここで公開されています:https://miherlosev.github.io/e2e_angular
。 最初のテストは単なるログインフォームです。
testcafe-angular-selectors
とAngularAugryには、開発モードで実行されているアプリケーションが必要であることに注意してください。
index.js
ファイルを作成し、次のコードを追加しましょう。
index.js
import { AngularSelector, waitForAngular } from 'testcafe-angular-selectors'; fixture `Book Collection` .page('https://miherlosev.github.io/e2e_angular/') .beforeEach(async t => { await waitForAngular(); }); test('Login', async t => { const loginForm = AngularSelector('bc-login-form'); await t .typeText(loginForm.find('#md-input-1'), 'test') .typeText(loginForm.find('#md-input-3'), 'test') .click(loginForm.find('.mat-button')); });
これが何が起こるかです。 Angularセレクターのインポートから始めます。 これらを使用して、コンポーネントセレクターでページ要素をアドレス指定します。
フィクスチャでは、テストされたページを指定し、beforeEach
テストフックを使用します。 このフックは、各テストを実行する前に特定のアクションを実行する必要がある場合に役立ちます。 この場合、waitForAngular
メソッドを使用すると、Angularコンポーネントツリーが読み込まれるまで待機できます。 その後、テストではコンポーネント名でログインフィールドとパスワードフィールドを見つけ、それらに入力してログインボタンを押します。
テストを実行してみましょう。 次の内容のpackage.json
ファイルを作成します。
package.json
{ "scripts": { "test": "testcafe chrome index.js" } }
test
タスクは、GoogleChromeのindex.js
からテストを実行します。 次に、次のコマンドを実行します。
$ npm test
TestCafeのレポートは、テストに合格したことを示しています。
ページモデルパターンでテストを改善する
ページモデルは、テストされたページの抽象化を作成し、それを使用してページ要素を参照するパターンです。 ページのマークアップが変更された場合にテストをサポートする時間を節約するのに役立ちます。
ログインページのページモデルを作成しましょう。 このページには、ユーザー名とパスワードの入力、およびログインボタンの3つの要素があります。 ページ全体をJavaScriptクラスとして表し、その要素をセレクターとして表します。
page-model.js
ファイルを作成し、次のコードを追加します。
page-model.js
import { AngularSelector } from 'testcafe-angular-selectors'; export class LoginPage { constructor () { const loginForm = AngularSelector('bc-login-form'); this.username = loginForm.find('#md-input-1'); this.password = loginForm.find('#md-input-3'); this.loginBtn = loginForm.find('.mat-button'); } }
AngularSelector
コンストラクターを使用します。 コンポーネントセレクターをスペースで区切ってこのコンストラクターに渡すことができ、ネイティブのTestCafeセレクターを返します。 TestCafeセレクターを使用すると、タグ名、IDなどによる追加のフィルタリングが可能になります。 この例では、find
メソッドを使用して、テキストフィールドとボタンを検索します。
それでは、index.js
をリファクタリングしましょう。 テストからセレクター関連のコードを抽出し、ページモデルに移動しました。 この後、テストコードにはページ要素との相互作用のみが含まれます。
import { waitForAngular } from 'testcafe-angular-selectors'; import { LoginPage } from './page-model.js'; const loginPage = new LoginPage(); fixture `Book Collection` .page('https://miherlosev.github.io/e2e_angular/') .beforeEach(async t => { await waitForAngular(); }); test('Login', async t => { await t .typeText(loginPage.username, 'test') .typeText(loginPage.password, 'test') .click(loginPage.loginBtn); });
同じコマンドでテストを実行し、以前と同じように機能することを確認します。
より複雑なテストを作成する
私たちのテストは、現時点では実際には何もチェックしていません。 アサーションを追加しましょう。特定の本を見つけるようにテストを変更し、検索結果が空でないことを確認します。
ページモデルパターンを続行するので、page-model.js
を更新しましょう。 まず、最初にもう1つimport
を追加します。
import { t } from 'testcafe';
t
は、TestContext
と呼ばれるTestCafeオブジェクトであり、クリックや入力などのさまざまなアクションを実行できます。
そして、最後に以下を追加します。
page-model.js
class BasePage { constructor () { const navigationItem = AngularSelector('bc-nav-item'); this.toolbar = AngularSelector('bc-toolbar'); this.sidenav = { myCollectionNavItem: navigationItem.find('a').withText('My Collection'), browseBooksNavItem: navigationItem.find('a').withText('Browse Books') }; this.openToolbarBtn = this.toolbar.find('button'); } async navigateToBrowseBooksPage () { await t .click(this.openToolbarBtn) .click(this.sidenav.browseBooksNavItem); } } export class FindBookPage extends BasePage { constructor () { super(); this.searchInput = AngularSelector('bc-book-search').find('input'); this.bookPreviews = AngularSelector('bc-book-preview'); } }
BasePage
クラスは、他のページ(ツールバーとメインメニュー)間で共有されるUI要素を処理します。 他のすべてのページの場合、例: FindBookPage
、このクラスを拡張するだけです。
次に、index.js
を次のように変更します。
import { waitForAngular } from 'testcafe-angular-selectors'; import { LoginPage, FindBookPage, } from './page-model'; const loginPage = new LoginPage(); const findBookPage = new FindBookPage(); fixture `Book Collection` .page('https://miherlosev.github.io/e2e_angular/') .beforeEach(async t => { await waitForAngular(); await t .typeText(loginPage.username, 'test') .typeText(loginPage.password, 'test') .click(loginPage.loginBtn); }); test("find a book", async t => { await findBookPage.navigateToBrowseBooksPage(); await t .typeText(findBookPage.searchInput, 'The Hunger Games') .expect(findBookPage.bookPreviews.count).gt(0); });
承認をbeforeEach
テストフックに移動したことに注意してください。 これは、アプリに承認が必要であり、TestCafeが各テストをクリーンな環境で実行して、不安定なテストを回避するためです。 このチュートリアルでは簡単に説明しますが、ユーザーロールと呼ばれるより高度な承認メカニズムもあります。 これにより、認証を分離して、ユーザーアカウントを切り替える必要があるときにいつでも適用できます。
ご覧のとおり、コードにはテストロジックのみが含まれています。 ページ要素の読み込み、アニメーション、XHRの完了、またはその他の定型コードを待つ必要はありません。
次に、npm test
を使用してテストを実行し、結果を確認しましょう。
テストに合格しました。 デフォルトでは、TestCafeはテスト結果をコンソールに表示します。 TeamCity、Slackなどのカスタムレポーターを提供するプラグインもあります。
テストが失敗したときのエラーの特定
失敗したテストがどのように見えるか見てみましょう。 テストが失敗するように、最後のアサーションを変更します。
.expect(findBookPage.bookPreviews.count).eql(0);
次に、テストを実行します。
失敗したテストごとに、TestCafeは失敗したステップを強調表示します。 また、ブラウザ、コールサイト、およびその他の詳細を報告するため、失敗の理由をすばやく見つけることができます。 テストを修正するには、コードを元に戻します。
次のステップ:便利なリンク
このチュートリアルでは、TestCafeとページモデルパターンを使用して簡単なテストを行いました。 その他の例と推奨事項については、公式ドキュメントをご覧ください。
完全なコードは、GitHubのこのチュートリアルから見つけることができます。
TestCafeについてご不明な点がございましたら、フォーラムでお気軽にお問い合わせください。 機能のリクエストとバグについては、GitHubの問題ページにアクセスしてください。