まだ手動でやってない?UIテストを爆速で自動化できるNightwatch.jsが便利すぎ

2016/08/30

Hugo Giraudel

109

Articles in this issue reproduced from SitePoint
Copyright © 2016, All rights reserved. SitePoint Pty Ltd. www.sitepoint.com. Translation copyright © 2016, KADOKAWA ASCII Research Laboratories, Inc. Japanese syndication rights arranged with SitePoint Pty Ltd, Collingwood, Victoria,Australia through Tuttle-Mori Agency, Inc., Tokyo

Webアプリのクオリティアップに役立つのが、フロントエンドのテスト。実装したはずの機能がある条件で動かなかったり、期待どおりに操作できなかったりするとガッカリですね。Nightwatch.jsならテストがだいぶ捗りそうです。

少し前に、Eric Elliottが「JavaScript Testing: Unit vs Functional vs Integration Tests」でJavaScriptのテストについて比較しました。

本記事では、JavaScriptの機能テストについてもう少し掘り下げます。Nightwatch.jsライブラリーを詳しく探りながら、機能テストを実施してみましょう。

解説する前に、機能テストとはなにか、なぜ重要なのか説明します。おおまかに言うと、機能テストとはユーザーの観点から予測されるとおりにアプリケーションが動作しているか確認するためのプロセスです。

ユニットや総合テストのような技術的テストではなく、プラットホームへのログインや商品の購入など特定のシナリオを、ユーザーがシームレスに実行できるかの確認を目標とします。

Nightwatch.jsとは

Nightwatch.jsはNode.js上で動作するエンドツーエンド(E2E)のテストフレームワークのことで、Webブラウザーの自動化促進を目的としたプロジェクトSeleniumに依存します。

ヒューマンフレンドリーな構文を通じて、Nightwatch.jsはブラウザーが自動的に再生する「スクリプト」のシナリオを可能にします(必ずしもヘッドレスブラウザーではありません)。

Nightwatchのインストール

Nightwatch自体はNode.jsモジュールで、Nodeをマシンにインストールする必要があります。もっとも簡単な方法はnvmなどのバージョンマネージャーを使用することです。Nightwatchはnpmで配布されるので、そのほかのモジュールと同じように、-gでグローバルにインストールするか、--save-devで現在のプロジェクト内にインストールします。

npm install --save-dev nightwatch

NightwatchはSelenium WebDriver APIに依存するため、Java上で実行するSelenium WebDriverサーバーを必要とします。つまりJava Development Kit(JDK 7+)もインストールする必要があります。JDKはOracleのWebサイトからダウンロードできます。

ダウンロードしてインストールしたら、java -versionのあるマシン上でJavaを正常に利用できるか確認できます。最後のステップは、SeleniumのダウンロードページからSeleniumスタンドアロンサーバーパッケージをjarとしてダウンロードすることです。パッケージはプロジェクト内のbinフォルダに置いてください。

your_project/
|
|– bin/
|   |– selenium-server-standlone-2.53.1.jar
|
`– package.json

これで設定が完了しました。それでは始めましょう。

Nightwatchの設定

想像している通り、Nightwatchには多くの設定があります。幸いにも、最初からすべてを知る必要はありません。設定は、プロジェクトのルートのnightwatch.jsonファイルかnightwatch.conf.jsファイルのどちらかで実行できます。より柔軟性がありコメント追加機能のある後者がおすすめです。

var SELENIUM_CONFIGURATION = {
  start_process: true,
  server_path: 'bin/selenium-server-standalone-2.53.0.jar',
  host: '127.0.0.1',
  port: 4444
};

var FIREFOX_CONFIGURATION = {
  browserName: 'firefox',
  javascriptEnabled: true,
  acceptSslCerts: true
};

var DEFAULT_CONFIGURATION = {
  launch_url: 'http://localhost',
  selenium_port: 4444,
  selenium_host: 'localhost',
  desiredCapabilities: FIREFOX_CONFIGURATION
};

var ENVIRONMENTS = {
  default: DEFAULT_CONFIGURATION
};

module.exports = {
  src_folders: ['tests'],
  selenium: SELENIUM_CONFIGURATION,
  test_settings: ENVIRONMENTS
};

備考:JSONファイルでは許可されていませんが、個人的には、設定ファイルは小さなオブジェクトに分割されているとより読みやすくなると思います。

今回のケースでは、Seleniumの特定の構成とテスト設定を使用し、testsフォルダ内で実行することをNightwatchに伝えます。それでは、各チャンクを見ていきます。

var SELENIUM_CONFIGURATION = {
  start_process: true,
  server_path: 'bin/selenium-server-standalone-2.53.0.jar',
  host: '127.0.0.1',
  port: 4444
};

この構成オブジェクトでは、Nightwatchのデフォルト値である127.0.0.1:4444上で実行するとSeleniumに伝えています。また、binフォルダに保存したSeleniumサーバーを利用して自動的に起動することを確認します。

注意:より高度な使用についてはSeleniumオプションの全リストを確認してください。

実際のテストのセットアップへ進みます。

var DEFAULT_CONFIGURATION = {
  launch_url: 'http://localhost',
  selenium_port: 4444,
  selenium_host: 'localhost',
  desiredCapabilities: FIREFOX_CONFIGURATION
};

var ENVIRONMENTS = {
  default: DEFAULT_CONFIGURATION
};

Nightwatchからのtest_settingsオプションは、各環境の名前になっているキーを持つオブジェクトを要求します。このオブジェクトは、別の構成オブジェクトにマッピングされます。今回のケースでは、(まだ)カスタム環境を設定していないのでdefaultを使用します。stagingまたはproductionテスト環境はあとで設定できます。

環境設定では、どのURLを開き(例えばステージングでは異なる場合があります)、テストの実行にはどのブラウザーを使うかをNightwatchに伝えます。

注意:より高度な使用についてはテストオプションの全リストを確認してください。

var FIREFOX_CONFIGURATION = {
  browserName: 'firefox',
  javascriptEnabled: true,
  acceptSslCerts: true
};

ここでは、JavaScriptを有効にし、SSL証明書を受け入れるFirefoxを使用します。さらに踏み込んで、(versionで)特定のブラウザーバージョンまたは(platformで)OSを指定できます。

注意:より高度な使用については機能オプションの全リストを確認してください。

これで適切な設定ができました。最初のテストを記述していきましょう!

Nightwatchテストの記述

今回のテストでは、メールフィールド、パスワードフィールド、送信ボタンを含む/loginでのログインページを含みます。フォームを送信するとき、ユーザーは「ニュースフィード」というページにリダイレクトされます。

先ほどの構成で、テストはtestsフォルダにあると指定しました。これからこのtestsフォルダだけでなく、login.jsファイルも作成します。

your_project/
|
|– bin/
|   |– selenium-server-standlone-2.53.1.jar
|
|– tests/
|   |– login.js
|
|- nightwatch.conf.js
`– package.json

このファイルはシナリオを説明するオブジェクトをエクスポートします。各キー(複数ある場合)は、実行するステップを含む関数にマッピングされたテストの名前です。

module.exports = {
  'Login test': function (client) {
    // Steps to execute
  }
};

テスト関数は、シナリオの記述に必要なAPIを提供するオブジェクトを選択します。まずログインURLにナビゲートします。次にフィールドに入力しボタンを押します。最後に「News feed」のテキストを見つけられるか確認します。

module.exports = {
  'Login test': function (client) {
    client
      .url('http://foobar.qux/login')
      .setValue('input[name="email"]', 'foo@bar.com')
      .setValue('input[name="password]', 'p455w0rdZ')
      .click('button[type="submit"]')
      .assert.containsText('main', 'News feed')
      .end();
  }
};

注意:Seleniumのセッションを適切にシャットダウンするため、命令リストの終了には必ず.end()を使用します。

これはとても簡単でした! それでは、動作確認のテストを実行します。

./node_modules/.bin/nightwatch

次のような結果になるはずです。

Implementing JavaScript functional testing with Nightwatch.js

注意:Firefox 47のリリースでFirefoxDriverベースのエクステンションは動作しなくなりました。これはFirefox 47.1およびSelenium2.53.1で修正されました。別のブラウザーでテストを実行するにはプロジェクトのWikiを参照してください。

Nightwatchが毎回バイナリに達するのを避けるため、最後に、package.jsonに小さなnpmスクリプトを作成し、エイリアス化します。

{
  "scripts": {
    "test": "nightwatch"
  }
}

Nightwatchテストの改善

機能テストが多くなると、多くの情報が重複してメンテナンスが難しくなります(テストにもメンテナンスが必要です)。それを防ぐためにページオブジェクトを使用します。

ページオブジェクトは、テストページ(またはページフラグメント)のオブジェクトのラッピングからなる、エンドツーエンドテストの世界では一般的なパターンです。目標は、シナリオを簡素化するために基本的なHTMLと一般的な設定を取り除くことです。

幸いなことに、Nightwatchにはページオブジェクトを処理する簡単な方法があります。page_objects_pathオプションを設定に追加します。tests/pagesのような任意のフォルダを指定できます。

module.exports = {
  src_folders: ['tests'],
  page_objects_path: 'tests/pages',
  selenium: SELENIUM_CONFIGURATION,
  test_settings: ENVIRONMENTS
};

これで、このフォルダ内にlogin.jsファイルを作成できます。ファイル名は、あとでこのファイルに定められているすべての設定を取得するキーとして使用されるので、それを踏まえて名づけてください。

login.jsファイルでは、今後のシナリオを簡単にするために、URLを指定しHTML要素を分かりやすい名前にします。

module.exports = {
  url: function () {
    return this.api.launch_url + '/login';
  },
  elements: {
    emailField: 'input[name="email"]',
    passwordField: 'input[name="password"]',
    submitButton: 'button[type="submit"]'
  }
};

URLをハードコードしないことに注意してください。その代わり、環境設定で定義されたlaunchUrlオプションに依存するようにします。この方法で、ページオブジェクトはコンテキストに依存せずどんな環境でも動作します。

これでページオブジェクトを使用するようにテストを変更するのがとても簡単になりました。クライアントからのpageオブジェクトを介してページを取得します。各ページオブジェクトはページオブジェクトにちなんで名づけられた関数として公開されています(たとえばlogin())。

カスタム名を指していること示すために、CSSセレクターを@マークのプレフィックスがある別名に置き換えます。これで終了です。

module.exports = {
  'Login test': (client) => {
    const page = client.page.login();

    page.navigate()
      .setValue('@emailField', 'foo@bar.com')
      .setValue('@passwordField', 'p455w0rdZ')
      .click('@submitButton')
      .assert.containsText('main', 'News feed');

    client.end();
  }
};

ページではなくクライアント自体のセッションを終了する方法に注意してください。

複数環境での作業

異なる環境での機能テストが実行可能になったことは、たとえば、ローカル環境でユーザーパスが壊れていないか、ステージングと本番とが同じ働きをしているかの確認に便利です。

特定の環境でテストを実行するために、CLIで--envオプションを使用できます。(設定に含まれている)default環境はオプションを省略したときに使用されます。

設定にステージング環境を追加します。

var STAGING_CONFIGURATION = Object.assign({}, DEFAULT_CONFIGURATION, {
  launch_url: 'http://staging.foobar.qux'
});

var ENVIRONMENTS = {
  default: DEFAULT_CONFIGURATION,
  staging: STAGING_CONFIGURATION
};

テストを実行するとlaunch_urlオプションが環境に応じて変わります。

npm test --env staging

まとめると…

Nightwatch.jsはエンドツーエンドの機能テストの記述に使用されるJavaScriptのフレームワークです。Selenium WebDriver APIに依存し、異なるブラウザーを自動的に実行できます。

テストの記述は主に一般的なユーザーシナリオの定義で構成されています。シンプルですが、目的のための完全なAPIがあります。

ユーザーの機能が確実に壊れていないか確かめるために、あなた自身の手で機能テストを書いてください。

(原文:JavaScript Functional Testing with Nightwatch.js

[翻訳:柴田理恵]
[編集:Livit

Copyright © 2016, Hugo Giraudel All Rights Reserved.

Hugo Giraudel

Hugo Giraudel

CSSのゴブリン、Sassハッカー、マージン狂です。Sass GuidelinesSassDocSass CompatibilityBrowserhacksほか多くのSass関連の著者でもあります。

Loading...