開発者ドキュメント

PuppeteerとJestを使用してNode.jsでエンドツーエンドのテストを作成する方法

著者は、 Write for DOnations プログラムの一環として、 Free and Open SourceFundを選択して寄付を受け取りました。

序章

エンドツーエンドテスト(略して e2e )は、アプリケーションのライフサイクル全体を本番環境のようなシナリオでユーザーの観点からテストするプロセスです。 このプロセスには通常、通常のユーザーと同じようにアプリケーションのインターフェイスを自動的にナビゲートするスクリプトを展開し、その過程で特定の機能と動作をテストすることが含まれます。 Node.js 開発では、 Chrome API PuppeteerとJavaScriptテストフレームワークJestを組み合わせて使用して、e2eテストを自動化できます。 、バグを修正して新しい機能を追加するときに、アプリケーションのユーザーインターフェイス(UI)が引き続き機能していることを確認できます。

このチュートリアルでは、サンプルWebページのアカウント作成およびログイン機能が意図したとおりに機能することを検証するe2eテストを作成します。 最初に、基本的なPuppeteerスクリプトを記述してブラウザーを開き、テストWebページに移動します。次に、ブラウザーとページインスタンスをグローバルに使用できるようにするプリセットを構成します。 次に、 GitHubのDigitalOceanCommunityリポジトリからmock-authサンプルアプリケーションのクローンを作成し、アプリケーションをローカルで提供します。 このサンプルアプリケーションは、アカウントを作成してそのアカウントにログインするためのインターフェイスをユーザーに提供します。 最後に、Puppeteerスクリプトを調整して、アカウント作成フォームとログインフォームに入力し、送信ボタンをクリックしてから、Jestで単体テストを記述して、スクリプトが期待どおりに機能することを検証します。

警告:ウェブスクレイピングの倫理と合法性は複雑であり、絶えず進化しています。 また、場所、データの場所、および問題のWebサイトによっても異なります。 このチュートリアルでは、スクレーパーアプリケーションをテストするために特別に設計されたローカルで提供されるサンプルアプリケーションをスクレイプします。 他のドメインをスクレイピングすることは、このチュートリアルの範囲外です。

前提条件

このガイドを開始する前に、次のものが必要です。

ステップ1—テストプログラムを開始する

このステップでは、Node.jsテストプログラム用のディレクトリを作成し、必要な依存関係をインストールします。 このチュートリアルでは、3つの依存関係を使用します。これらの依存関係は、Node.jsのデフォルトのパッケージマネージャーであるnpmを使用してインストールします。 これらの依存関係により、JestとPuppeteerを一緒に使用できるようになります。

まず、このプロジェクトのフォルダーを作成し、そのフォルダーに移動します。 このチュートリアルでは、プロジェクトの名前としてend-to-end-test-tutorialを使用します。

  1. mkdir end-to-end-test-tutorial
  2. cd end-to-end-test-tutorial

以降のすべてのコマンドは、このディレクトリで実行します。

これで、ディレクトリ内のnpmを初期化して、依存関係を追跡できるようになります。 次のコマンドを使用して、プロジェクトのnpmを初期化します。

  1. npm init

このコマンドは、一連のプロンプトを表示します。 すべてのプロンプトでENTERを押すか、パーソナライズされた説明を追加できます。 必ずENTERを押し、entry point:およびtest command:の入力を求められたら、デフォルト値のままにしておきます。 または、-yフラグをnpmに渡すと、すべてのデフォルト値が送信されます。

これらのプロンプトに入力すると、package.jsonファイルが作成され、プロジェクトの依存関係といくつかの追加のメタデータが管理されます。

次に、ファイルを保存するように求められます。 yesと入力し、ENTERを押します。 npmは、この出力をpackage.jsonファイルとして保存します。

これで、依存関係をインストールできます。 このチュートリアルに必要な3つの依存関係は次のとおりです。

npmを使用してこれらの依存関係をインストールします。

  1. npm install --save jest puppeteer jest-puppeteer

このコマンドを実行すると、Jest、Puppeteer、互換性のあるバージョンのChromiumブラウザー、およびjest-puppeteerライブラリがインストールされます。

注: Linuxマシンでは、Puppeteerにいくつかの追加の依存関係が必要になる場合があります。 Ubuntu 20.04を使用している場合は、PuppeteerのトラブルシューティングドキュメントのUNIXセクションでChromeヘッドレス内のDebianDependenciesドロップダウンが起動しないことを確認してください。 次のコマンドを使用して、不足している依存関係を見つけることもできます。

  1. ldd ~/end-to-end-test-tutorial/node_modules/puppeteer/.local-chromium/linux-970485/chrome-linux/chrome | grep not

このコマンドでは、プロジェクトのChromeのインストールでlddを使用してプログラムの依存関係を検索し、結果をgrepにパイプして、notという単語を含むすべての依存関係を検索します。 。 これにより、インストールされていない依存関係が表示されます。 chromeモジュールへの個々のパスは異なる場合があることに注意してください。

必要な依存関係がインストールされると、package.jsonファイルのdependenciesの一部としてそれらが含まれます。 これを確認するには、お好みのテキストエディタで開きます。

  1. nano package.json

これにより、次のようなファイルが表示されます。

end-to-end-test-tutorial / package.json
{
  "name": "end-to-end-test-tutorial",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "jest": "^27.5.1",
    "jest-puppeteer": "^6.1.0",
    "puppeteer": "^13.5.0"
  }
}

これにより、依存関係がインストールされたことを確認できます。

テストプログラムを開始し、依存関係を設定したら、次にそれを構成し、最初のPuppeteerスクリプトを追加して、すべてが正しく設定されていることを確認します。

ステップ2—テストプログラムの構成

Webサイトを手動でテストする方法は、ブラウザーを使用してWebページを閲覧し、ボタンをクリックし、ページをスクロールして、各インタラクションで正しいページとテキストがレンダリングされていることを確認することです。 これらは、自動化されたエンドツーエンドテストの作成に関連する手順と同じです。ブラウザはプログラムでWebページを開き、インターフェイスをナビゲートします。テストライブラリは、ブラウザがWebページから期待される動作または出力を取得したことを表明します。 このステップでは、Node.jsアプリケーションでこれらの手順を実行するようにJestとPuppeteerを構成し、www.google.comにアクセスするPuppeteerスクリプトを使用して構成をテストします。

まず、テストアプリケーションに構造を与えるために、いくつかのフォルダーを作成します。

  1. mkdir actions
  2. mkdir logs
  3. mkdir specs
  4. mkdir utils

actionsフォルダーには、ローカルWebページをクロールするPuppeteerスクリプトが保持され、specsにはテスト自体が保持され、utilsには模擬クレデンシャル生成などのヘルパーファイルが保持されます。 このチュートリアルでは使用されていませんが、テストの結果を保持するためにlogsフォルダーを作成することをお勧めします。

これらのディレクトリを作成したら、お好みのエディタでjest.config.jsファイルを作成して開きます。

  1. nano jest.config.js

次の構成をファイルに追加します。

end-to-end-test-tutorial / jest.config.js
module.exports = {
  preset: 'jest-puppeteer',
  roots: [ 'specs' ],
};

これはJest構成ファイルであり、インストールしたjest-puppeteerライブラリのpreset構成を使用するようにJestに指示するように設定されています。 また、このチュートリアルの後半で作成するテストスクリプトの場所としてspecsフォルダーを指定します。

ファイルを保存して終了します。 次に、ルートディレクトリから、jest-puppeteer.config.jsファイルを作成して開きます。

  1. nano jest-puppeteer.config.js

次の構成をファイルに追加します。

end-to-end-test-tutorial / jest-puppeteer.config.js
module.exports = {
  launch: {
    headless: false,
      args: [ "--window-size=1366,768" ],
  },
  browser: 'chromium',
}

これらの構成は、Webページをテストするためにブラウザーを開く方法を定義します。 headlessは、ブラウザがインターフェイスの有無にかかわらず実行されるかどうかを決定します。 この場合、デスクトップ環境でウィンドウを開くようにPuppeteerを構成しています。 argsは、関連するPuppeteer引数をブラウザインスタンスに渡すために使用されます。 この場合、これを使用して、開いているブラウザのウィンドウサイズを指定します。 最後に、browserは使用するブラウザを指定します。 このチュートリアルでは、これはChromiumですが、 puppeteer-firefox がインストールされている場合は、Firefoxである可能性があります。

ファイルを保存して終了します。

specsフォルダーをすべてのテストを保持するフォルダーとして設定し、そのフォルダーに基本的なテストファイルを作成します。

specsフォルダーに移動し、users.test.jsファイルを作成します。 users.test.jsファイルを開き、次のコードを追加して、アプリケーションの機能をテストします。

end-to-end-test-tutorial / spec / users.test.js
jest.setTimeout(60000)

describe('Basic authentication e2e tests', () => {
  beforeAll( async () => {
  // Set a definite size for the page viewport so view is consistent across browsers
    await page.setViewport( {
      width: 1366,
      height: 768,
      deviceScaleFactor: 1
    } );	

    await page.goto('https://www.google.com');

    await page.waitFor(5000);
    } );

  it( 'Should be truthy', async () => {
    expect( true ).toBeTruthy();
  })	
});

このコードでは、最初にsetTimeout()メソッドを使用してJestのデフォルトのタイムアウトを60秒に設定します。 Jestのデフォルトのタイムアウトは5秒で、テストに合格または不合格になる必要があります。そうでない場合、テストはエラーを返します。 ブラウザの操作は実行に5秒以上かかることが多いため、時間の経過に対応するために60秒に設定します。

次に、describeブロックは、describeキーワードを使用して、関連するテストを相互にグループ化します。 その中で、beforeAllスクリプトを使用すると、このブロック内のすべてのテストの前に特定のコードを実行できます。 これは、このテストブロックに対してローカルであるが、含まれるすべてのテストに対してグローバルである変数のようなコードを保持します。 ここでは、ブラウザで開いたページのビューポートをjest-puppeteer.config.jsで指定したブラウザのサイズに設定するために使用しています。 次に、pageオブジェクトを使用してwww.google.com に移動し、5秒間待機します。これにより、ページが読み込まれた後、ブラウザが閉じる前にページが表示されます。 pageオブジェクトは、すべてのテストスイートでグローバルに使用できます。

次に、作成したスクリプトが機能することを検証するための模擬テストを作成しました。 ブール値trueが真の値であるかどうかをチェックします。これは、すべてが正しく機能している場合は常に当てはまります。

ファイルを保存して終了します。

ここで、テストを実行して、期待どおりに機能するかどうかを確認する方法が必要です。 次のコードブロックに示すように、package.jsonファイルを開き、scriptsセクションを変更します。

end-to-end-test-tutorial / package.json
{
  "name": "Doe's-e2e-test",
  "version": "1.0.0",
  "description": "An end to end test",
  "main": "index.js",
  "scripts": {
    "e2e": "jest"
  },
  "keywords": [],
  "author": "John Doe",
  "license": "MIT"
}

これにより、キーワードe2ejestコマンドを呼び出してテストを実行します。 ファイルが保存されたら、次のコマンドを使用して、ターミナルでe2eテストを実行します。

  1. npm run e2e

このコマンドを実行すると、新しいブラウザウィンドウが開き、Googleに移動して、コンソールに次の出力を出力します。

Output
> jest PASS specs/users.test.js (13.772s) Basic authentication e2e tests √ Should be truthy (3ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 14.221s, estimated 16s Ran all test suites.

これは、PuppeteerとJestの両方が正しく機能していることを示しています。 これで、Webページのテストを作成する準備が整いました。 ただし、最初に、テストするインターフェイスを使用できるようにサンプルWebページを設定します。

ステップ3—サンプルWebインターフェイスの実行

このステップでは、 DigitalOcean Community GitHubリポジトリからサンプルアプリケーションのクローンを作成し、LiveServer開発サーバーを使用してローカルで実行します。 これにより、Node.jsアプリケーションでテストするためのユーザーインターフェイスが提供されます。

注:このチュートリアルでは、このサンプルUIをユーザーの観点からのみ検査します。 ユーザーインターフェイスを構築するために必要な開発は、このチュートリアルの範囲を超えています。 UIログイン認証ページの開発に興味がある場合は、Reactアプリケーションにログイン認証を追加する方法チュートリアルを確認してください。

まず、新しいターミナルを開き、テストアプリケーションの外部で次のgitコマンドを実行します。

  1. git clone https://github.com/do-community/mock-auth.git

これにより、DigitalOceanリポジトリからユーザーインターフェイスのクローンが作成されます。 このコードには、模擬認証インターフェースを作成する HTML CSS 、およびJavaScriptが含まれています。

次に、次のコマンドを使用してLiveServerをグローバルにインストールします。

  1. npm install -g live-server

注: Ubuntu 20.04などの一部のシステムでは、npmパッケージをグローバルにインストールすると、アクセス許可エラーが発生し、インストールが中断される可能性があります。 sudonpm installと一緒に使用しないことはセキュリティのベストプラクティスであるため、代わりにnpmのデフォルトディレクトリを変更することでこれを解決できます。 EACCESエラーが発生した場合は、公式のnpmドキュメントの指示に従ってください。

Live Serverは、ライブリロード機能を備えた軽量の開発サーバーです。 静的なHTMLページを取得し、localhostで利用できるようにします。

次に、mock-authサンプルインターフェイスに移動します。

  1. cd mock-auth

次に、次のコマンドを使用して、ローカル開発サーバーでアプリケーションを起動します。

  1. live-server

デフォルトのブラウザでhttp://127.0.0.1:8080のWebページが開き、次の画像として表示されます。

これは、テストプログラムが対話するUIです。 ログインボタンをクリックすると、ブラウザはユーザー名パスワードのフィールドを含むログインフォームをロードします。 アカウントの作成ボタンを選択すると、アカウントの作成フォームが表示され、フルネームユーザー名パスワードのフィールドが表示されます。 。 次の手順では、これらの各インターフェイスをナビゲートするテストを作成し、アカウントの作成とログインが期待どおりに機能することを確認します。

ステップ4—アカウント作成のテスト

Webサイトでアカウントを作成する場合、最も一般的な動作は、Webサイトが、名前と新しく作成したアカウントに関するいくつかの関連情報が記載されたウェルカムページに移動することです。 このステップでは、サンプルWebアプリケーションのアカウント作成ページがこのように機能することを検証します。 これを行うには、actionsフォルダーにスクリプトを記述してインターフェイスをナビゲートし、そのアクションを使用して機能を検証するテストを記述します。

まず、テストプログラムが含まれているターミナルに戻り、サンプルWebアプリケーションのアカウントの作成ページをクロールするスクリプトを作成します。 このチュートリアルでは、このファイルにcreateAccount.jsという名前を付けます。

  1. nano actions/createAccount.js

このファイルを開いたら、次のコードを追加します。

エンドツーエンドテストチュートリアル/actions/createAccount.js
const chalk = require( 'chalk' );

class createAccount {
  constructor( page ) {
    this.url = "http://127.0.0.1:8080/"
    this.page = page;
    this.signupBtn = '#signup';
    this.signupBody = '#signupBody';
    this.fullnameField = '#fullname';
    this.usernameField = '#username';
    this.passwordField = '#password';
    this.loginPageBtn = '#loginBtn';
    this.signupPageBtn = '#signupBtn';
  }
}

module.exports = ( page ) => new createAccount( page );

このスニペットは、最初にchalkモジュールをインポートします。このモジュールは、後でターミナルでエラーメッセージをフォーマットするために使用されます。 これは必須ではありませんが、エラー報告が読みやすくなります。 次に、createAccountというクラスを作成します。 コンストラクターはpageパラメーターを受け取り、サンプルWebアプリケーションのホームページURLを設定し、プログラムがDOM[X229Xで対話するHTML要素へのID参照としてオブジェクトのプロパティを設定します。 ]。 最後に、コードは関数をエクスポートして、createAccountクラスの新しいインスタンスを作成します。

次に、signupメソッドをcreateAccountクラスに追加します。これは、ページでさまざまなアクションを実行するのに役立ちます。 次の強調表示されたコードをファイルに追加します。

エンドツーエンドテストチュートリアル/actions/createAccount.js
...
    this.signupPageBtn = '#signupBtn';
  }

  async signup( fullname, username, password ) {
    try {
      await this.page.goto( this.url );
      await this.page.waitFor( this.signupBtn );
      await this.page.click( this.signupBtn );
      // Wait for the signupBody on the signup page to load
      await this.page.waitFor( this.signupBody );

      // Type the login credentials into the input fields
      await this.page.type( this.fullnameField, fullname );
      await this.page.waitFor( 1000 );
      await this.page.type( this.usernameField, username );
      await this.page.waitFor( 1000 );
      await this.page.type( this.passwordField, password );
      await this.page.waitFor( 1000 );
            
      // Click then create account button
      await this.page.click( this.signupPageBtn );

      // Wait for homepage to load
      await this.page.waitFor( '#firstname' );
      await this.page.waitFor( 2000 );

      const firstname = await this.page.$eval( '#homeBody #firstname', el =>  el.textContent );
            
      return firstname;
    } catch ( err ) {
      console.log( chalk.red( 'ERROR => ', err ) );
    }
  }
}

module.exports = ( page ) => new createAccount( page );

ここでは、signupメソッドを非同期キーワードとして宣言しています。 この関数は、 try … catch ブロックを使用して、WebアプリケーションのURLに移動し、インターフェースをナビゲートします。 pageオブジェクトで使用されるメソッドのいくつかは次のとおりです。

これらの方法では、signup関数は最初にページをベースURLにナビゲートし、次にサインアップボタンがロードされるのを待ちます。 次に、このボタンをクリックして、サインアップフォームの本文が読み込まれるのを待ちます。 フルネーム、ユーザー名、パスワードをそれぞれのフィールドに1秒間隔で入力します。 次に、サインアップボタンをクリックして、ウェルカムページが読み込まれるのを待ちます。 page.$eval()メソッドは、このメソッドから返されるウェルカムページに表示される名前をフェッチするために使用されます。

ファイルを保存して終了します。

次に、アカウントの作成が期待どおりに機能することを検証するためのテストを作成します。 ただし、先に進む前に、新しいアカウントを作成するためのクレデンシャルを決定する必要があります。 このために、新しいモジュールを作成します。

credentials.jsファイルをutilsフォルダーに作成します。

  1. nano utils/credentials.js

次のコードをファイルに追加します。

end-to-end-test-tutorial / utils / credentials.js
module.exports = ( user ) => {
  let username = `${user}-${Math.random()}`
  let password = `${Math.random()}`;
  // Make sure both usernames and passwords are strings
  username = String( username );
  password = String( password );
  const fullname = "John Doe"
  let credential = { fullname, username, password };
  return credential;
}

このコードは、ランダムなユーザー名、パスワード、およびハードコードされたフルネームを生成し、生成された資格情報をJSONオブジェクトとして返します。 ハードコードされた名前を任意の名前に変更できますが、多くの場合、アカウントを作成するときの一意のエンティティはユーザー名です。

保存してcredentials.jsを終了します。

次に、specsフォルダーに移動し、エディターでusers.test.jsファイルを開きます。 ここに示すようにコードを変更します。

end-to-end-test-tutorial / specs / users.test.js
let credentials = require( '../utils/credentials' );

jest.setTimeout(60000);

describe('Basic authentication e2e tests', () => {
  let credential;
  beforeAll( async () => {
  // Set a definite site for the page viewport so view is consistent across browsers
    await page.setViewport( {
      width: 1366,
      height: 768,
      deviceScaleFactor: 1
    } );
		
    credential = credentials( 'User' );	
		
    await page.goto('https://www.google.com');
		
    await page.waitFor(5000);
  } );
	
  it( 'Should be truthy', async () => {
    expect( true ).toBeTruthy();
  })
} );

ここでは、前に作成したcredentialsモジュールをインポートし、そのブロック内のすべてのテストでグローバルに使用できるcredential変数を作成し、beforeAllを使用して生成された資格情報をその変数に割り当てました。このブロックのすべてのテストの前に実行されるブロック。

これで、次のようにコードを変更することで、実際に検証を行うテストを作成できます。

end-to-end-test-tutorial / specs / users.test.js
let credentials = require( '../utils/credentials' );
let createAccount = require( '../actions/createAccount' );

jest.setTimeout(60000);

describe('Basic authentication e2e tests', () => {
  let credential;
  beforeAll( async () => {
  // Set a definite site for the page viewport so view is consistent across browsers
    await page.setViewport( {
      width: 1366,
      height: 768,
      deviceScaleFactor: 1
    } );

    credential = credentials( 'User' );
    createAccount = await createAccount( page );
  } );

  it( 'Should be able to create an account', async () => {
    const firstname = await createAccount.signup( credential.fullname, credential.username, credential.password );
    page.waitFor( 1000 );
    expect( credential.fullname ).toContain( firstname );
  })

} );

これで、createAccountモジュールがインポートされ、signupメソッドが呼び出され、プログラムがインターフェイスをナビゲートした後、ウェルカムページにfullnameが表示されます。 次に、コードは、このfullnameがテストメソッドが呼び出される前に生成されたfullnameと同じであることを表明します。

スクリプトを保存し、コマンドnpm run e2eを使用して実行します。

  1. npm run e2e

Chromeブラウザが開き、生成されたクレデンシャルを使用してアカウントが自動的に作成されます。 テストが終了すると、次の出力がコンソールに記録されます。

Output
> jest PASS specs/users.test.js (28.881s) Basic authentication e2e tests √ Should be able to create an account (26273ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 29.087s Ran all test suites.

このスクリプトにより、アカウント作成プロセスが検証されました。

このステップでは、サンプルWebアプリケーションをクロールし、アカウントを自動的に作成するスクリプトを作成しました。 次に、クローラースクリプトの単体テストを作成することにより、プロセスが期待どおりに機能することを確認しました。 次のステップでは、ログイン機能についても同じことを行います。

ステップ5—ログインプロセスのテスト

このステップでは、ログイン機能が正常に機能することを表明します。 この手順は、アカウントの作成手順と似ています。最初にWebクローラースクリプトを作成してログインページをナビゲートし、次に単体テストを記述して、機能が期待どおりに機能していることを確認します。

まず、お好みのエディタでloginAccount.jsファイルを作成して開きます。

  1. nano actions/loginAccount.js

次に、次のコードを追加して、ログインページをトラバースします。

エンドツーエンドテストチュートリアル/アクション/loginAccount.js
const chalk = require( 'chalk' );

class LoginAccount {
  constructor( page ) {
    this.url = "http://127.0.0.1:8080/"
    this.page = page;
    this.loginBtn = '#login';
    this.loginBody = '#loginBody';
    this.usernameField = '#username';
    this.passwordField = '#password';
    this.loginPageBtn = '#loginBtn';
  }

  async login( username, password ) {
    try {
      await this.page.goto( this.url );
      await this.page.waitFor( this.loginBtn );
      await this.page.click( this.loginBtn );
      // Wait for the loginBody on the login page to load
      await this.page.waitFor( this.loginBody );

      // Type the login credentials into the input fields
      await this.page.type( this.usernameField, username );
      await this.page.waitFor( 1000 );
			
      await this.page.type( this.passwordField, password );
      await this.page.waitFor( 1000 );

      await this.page.click( this.loginPageBtn );

      // Wait for homepage to load 
      await this.page.waitFor( '#firstname' );
      await this.page.waitFor( 2000 );
 
      const firstname = await this.page.$eval( '#homeBody #firstname', el =>  el.textContent );

      return firstname;
    } catch ( err ) {
      console.log( chalk.red( 'ERROR => ', err ) );
    }
  }
}

module.exports = ( page ) => new LoginAccount( page );

このコードは、createAccount.jsファイルに似ています。 まず、LoginAccountクラスを作成し、pageオブジェクトをパラメーターとして受け取る関数をエクスポートしました。 コンストラクターには、DOMで対話するためのいくつかのHTML要素へのID参照が含まれています。

LoginAccountクラスには、usernameおよびpasswordをパラメーターとして受け取り、ページでさまざまなアクションを実行するのに役立つ非同期loginメソッドがあります。 コードは最初にサンプルWebアプリケーションのURLに移動し、次にログインページをロードするボタンをクリックします。 ログインページが読み込まれると、loginメソッドに渡されたユーザー名とパスワードをフォームに入力し、ログインボタンをクリックして送信します。 ログインが成功すると、ウェルカムページが読み込まれ、単体テストに渡す名が返されます。

ファイルを保存して終了します。

次に、users.test.jsファイルを再度開き、次のように変更します。

end-to-end-test-tutorial / specs / users.test.js
let credentials = require( '../utils/credentials' );
let createAccount = require( '../actions/createAccount' );
let loginAccount = require( '../actions/loginAccount' );


jest.setTimeout(60000);

describe('Basic authentication e2e tests', () => {
  let credential;
  beforeAll( async () => {
  // Set a definite site for the page viewport so view is consistent across browsers
    await page.setViewport( {
      width: 1366,
      height: 768,
      deviceScaleFactor: 1
    } );
		
    credential = credentials( 'User' );
    createAccount = await createAccount( page );
    loginAccount = await loginAccount( page );
  } );
	
  it( 'Should be able to create an account', async () => {
    const firstname = await createAccount.signup( credential.fullname, 
    credential.username, credential.password );
    page.waitFor( 1000 );
    expect( credential.fullname ).toContain( firstname );
  })

  it( 'Should be able to log in after a successful account creation', async () => {
    const firstname = await loginAccount.login( credential.username, credential.password );
    page.waitFor( 1000 );
    expect( credential.fullname ).toContain( firstname );
  } );

} );

このコードでは、pageのWebクローラー関数と呼ばれるloginAccountモジュールをインポートし、Loginページの名前が合格した場合に合格する新しいテストアサーションを作成しました生成された資格情報に含まれています。

ファイルを保存し、ターミナルからnpm run e2eを実行します。

  1. npm run e2e

Webクローラーはブラウザーを開き、 Login ページに移動して資格情報を入力すると、テストスクリプトが実行され、Webクローラーがウェルカムページに到達したかどうかが確認されます。

以下が端末に記録されます。

Output
> jest PASS specs/users.test.js (48.96s) Basic authentication e2e tests √ Should be able to create an account (21534ms) √ Should be able to log in after a successful account creation (12899ms) Test Suites: 1 passed, 1 total Tests: 2 passed, 2 total Snapshots: 0 total Time: 52.426s Ran all test suites.

これは、ログインが成功するためのテストが期待どおりに合格したことを示しています。 ただし、テストはまだ完了していません。 プログラムは、失敗したログイン試行を処理できる必要があります。

間違ったユーザー名とパスワードの組み合わせを指定すると、無効なユーザー名またはパスワードが入力されましたというメッセージとともにアラートプロンプトがポップアップ表示されます。 アラートボックスメッセージをテストするには、pageオブジェクトでdialogイベントをリッスンできます。 警告ボックスの存在は、ログインが失敗したことを示しています。

これを実装するには、次のようにusers.test.jsスクリプトを変更します。

end-to-end-test-tutorial / specs / users.test.js
let credentials = require( '../utils/credentials' );
let createAccount = require( '../actions/createAccount' );
let loginAccount = require( '../actions/loginAccount' );


jest.setTimeout(60000);

describe('Basic authentication e2e tests', () => {
  let credential;
  beforeAll( async () => {
  // Set a definite site for the page viewport so view is consistent across browsers
    await page.setViewport( {
      width: 1366,
      height: 768,
      deviceScaleFactor: 1
    } );
		
    credential = credentials( 'User' );
    createAccount = await createAccount( page );
    loginAccount = await loginAccount( page );
  } );
	
  it( 'Should be able to create an account', async () => {
    const firstname = await createAccount.signup( credential.fullname, credential.username, credential.password );
    page.waitFor( 1000 );
    expect( credential.fullname ).toContain( firstname );
  })

  it( 'Should be able to log in after a successful account creation', async () => {
    const firstname = await loginAccount.login( credential.username, 
    credential.password );
    page.waitFor( 1000 );
    expect( credential.fullname ).toContain( firstname );
  } );

  it( 'Should not login on wrong credentials', async () => {
    try {
      page.on( 'dialog', dialog => {
        expect( dialog.message() ).toBe( 'Invalid username or password inputted' );
        dialog.accept();
      });

      await page.goto( 'http://127.0.0.1:8080/login.html' );
      await page.type( '#username', 'username' );
      await page.type( '#password', 'password' );
      await page.click( '#loginBtn' );
      await page.waitFor(5000) //Wait for the dialog to accept the prompt before proceeding

    } catch(err){
      console.log("An error occured while trying to login => ", err)
    }
  })

} );

このコードでは、ページの操作を実行する前に、最初にdialogイベントのイベントリスナーを設定する新しいアサーションを追加しました。 dialogイベントをリッスンする前にWebクローラーがボタンをクリックすると、イベントがバブルされる前にdialogがポップアップ表示されます。

次に、コードはlogin.htmlページに移動し、資格情報としてusernamepasswordを入力します。 これらのクレデンシャルは、アカウントの作成時に入力したクレデンシャルと一致しないため、エラーが発生し、アサーションが待機しているダイアログボックスがトリガーされます。 最後に、最後に5秒の遅延を追加したことに注意してください。 これは、jest-puppeteerがページを閉じる前に、dialogイベントがダイアログを受け入れるようにするためです。 実行できるテストがなくなると、ページは閉じられます。

users.test.jsファイルを保存して、テストを実行します。

  1. npm run e2e

次に、すべてのテストに合格することを確認します。

Output
PASS specs/users.test.js (25.736 s) Basic authentication e2e tests ✓ Should be able to create an account (11987 ms) ✓ Should be able to log in after a successful account creation (8196 ms) ✓ Should not login on wrong credentials (5168 ms) Test Suites: 1 passed, 1 total Tests: 3 passed, 3 total Snapshots: 0 total Time: 25.826 s, estimated 27 s Ran all test suites.

これは、サンプルWebアプリケーションが期待どおりに機能していることを示しています。

結論

このチュートリアルでは、PuppeteerとJestを使用して、アカウント作成とログイン機能を備えたサンプルWebアプリケーションの自動テストを作成しました。 PuppeteerとJestが連携するように構成してから、WebアプリケーションUIをナビゲートし、検出したHTML要素の値を返すスクリプトを作成しました。 最後に、これらの値が、テストしていたアクションの期待値と一致するかどうかをテストしました。

エンドツーエンドのテストは、UIをテストするための便利な方法であるだけではありません。 また、これを使用して、Webアプリケーションの他の主要な機能が期待どおりに機能することを確認することもできます。 たとえば、デバイスエミュレーションとネットワークスロットリングを使用して、複数のデバイス間でパフォーマンステストを実行できます。 エンドツーエンドテストの詳細については、PuppeteerおよびJestの公式ドキュメントを確認してください。

モバイルバージョンを終了