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にインストールしましょう。 これを使用して、アプリケーションのコンポーネントツリーでコンポーネントセレクターを検索します。

これで、テストの準備が整いました。

簡単なテストを書く

ここで公開されているサンプルBookCollectionAngularアプリケーションをテストします。 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"
  }
}

The test タスクはからテストを実行します index.js GoogleChromeで。 次に、次のコマンドを実行します。

$ 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 と呼ばれるTestCafeオブジェクトです TestContext これにより、クリックや入力などのさまざまなアクションを実行できます。

そして、最後に以下を追加します。

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');
  }
}

The BasePage クラスは、他のページ(ツールバーとメインメニュー)間で共有されるUI要素を扱います。 他のすべてのページの場合、例: the 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の問題ページにアクセスしてください。