まちいろエンジニアブログ

南池袋のWebサービス開発会社、株式会社まちいろのエンジニアブログです。

Nightwatch.jsとPhantomJSを使ってヘッドレステストを行う

こんにちわ!まちいろの柏谷です。

Nightwatch.jsというツールでテストを作ることになって調査したので、設定や使い方を残しておきたいと思います。

Nightwatchとは?

Nightwatchは、Node.js製のテストフレームワークです。

Selenium WebDriver APIと連携し、簡単に、様々なブラウザでテストを行うことができます。

ブラウザを利用したUIテストを行うSelenium WebDriver APIのラッパーとして開発されました。

Nightwatch.js | Node.js powered End-to-End testing framework

準備

Nightwatchのインストール

早速、Nightwatchをnpmでインストールします。

$ npm install [-g] nightwatch

PhantomJSをダウンロード

今回は実際のブラウザは利用せず、ヘッドレスでテストを行うという前提があったため、執筆時点で代表的なヘッドレスブラウザのPhantomJSを利用することにしました。

Download | PhantomJS からダウンロードして、./lib以下に配置します。

次のSeleniumもそうなのですが、Nightwatchでchromeieのテストを行うためには、別にドライバーをダウンロードしてくる必要があるため、まとめてbinなりlibなりのサブフォルダを作成して配置するといいでしょう。

Seleniumのダウンロード

NightwatchがSelenium WebDriver APIを利用するので必要となります。

Selenium downloads pageから、selenium-server-standalone-{VERSION}.jarファイルをダウンロードして./lib以下に配置します。

※ 執筆時点で最新バージョンは2.53でした。

Seleniumコマンドラインから手動で起動する場合は以下のコマンドを叩きます。

$ java -jar selenium-server-standalone-{VERSION}.jar

※ nightwatch.jsonでテストの際、自動で起動させる設定が可能です。

設定ファイルの作成

次に、プロジェクトのrootディレクトリにnightwatch.jsonを作成します。

{
  "src_folders" : ["tests"],
  "output_folder" : "reports",

  "selenium" : {
    "start_process" : false,
    "server_path" : "./lib/selenium-server-standalone-2.53.1.jar",
    "log_path" : "",
    "host" : "127.0.0.1",
    "port" : 4444,
  },

  "test_settings" : {
    "default" : {
      "launch_url" : "https://github.com",
      "screenshots" : {
        "enabled" : false,
        "path" : ""
      },
      "desiredCapabilities": {
        "browserName": "phantomjs",
        "phantomjs.binary.path": "lib/phantomjs-2.1.1-macosx/bin/phantomjs",
        "javascriptEnabled": true,
        "acceptSslCerts": true,
        "phantomjs.page.settings.userAgent": "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393"
      }
    }
  }
}

nightwatch.jsonは基本設定、Seleniumの設定、テストの設定の順で構成されています。

よく利用する項目について説明します。

基本設定

項目名 説明
src_folders テストファイルの置かれているフォルダを配列で指定
output_folder JUnit XML reportが保存される場所
custom_commands_path,custom_assertions_path カスタムコマンドやアサーションがある場合はパスを指定
test_workers テストを並行実行させるか。worker"auto"又は数値で指定

seleniumの設定

項目名 説明
start_process 自動的にSeleniumを起動するときにtrueを指定
server_path jarファイルのパス
log_path Seleniumのログが吐き出される場所
host start_prosesstrueにした場合は、指定が必要。Seleniumに割り当てるIPアドレスを指定
port Seleniumに割り当てるポートを指定

テストの設定

テストの設定は下記のように、いくつでも作成することができ、使用する設定はテスト実行時に--envオプションで指定することができます。

"default"は必須。

  "test_settings" : {
    "default" : {
      "launch_url" : "http://localhost",
      "desiredCapabilities": {
      }
    },
    "develop" : {
      "launch_url" : "http://dev.example.com",
      "desiredCapabilities": {
      }
    },
    "production" : {
      "launch_url" : "http://wwww.example.com",
      "desiredCapabilities": {
      }
    }
   }

PhantomJSを利用する場合の設定

PhantomJSを設定する場合は、まずbrowserName"phantomjs"phantomjs.binary.pathにダウンロードしたPhantomJSの実行ファイルのパスを指定します。

また、そのままではユーザーエージェントがないので、設定したい場合はphantomjs.page.settings.userAgentに値を設定します。

"default" : {
      "desiredCapabilities": {
        "browserName": "phantomJS",
        "javascriptEnabled": true,
        "acceptSslCerts": true,
        "phantomjs.binary.path": "lib/phantomjs-2.1.1-macosx/bin/phantomjs",
        "phantomjs.page.settings.userAgent": "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393",
        "phantomjs.cli.args" : []
      }
    }
項目名 説明
launch_url browser.launchUrlでテストから参照が可能。環境ごとにurlの指定を変えたい時に便利
screenshots screenshotの撮影タイミング(エラー時、テスト失敗時)、ファイルの保存先の指定
username 対象のサイトで認証が必要な際、ユーザー名を指定
access_key 対象のサイトで認証が必要な際、アクセスキーを指定
desiredCapabilities 新しいセッションが生成された時にSelenium WebDriverに渡されるオブジェクト。ブラウザや他の機能を設定できる
skip_testcases_on_fail 一つのテストケースが失敗した際に他のテストをスキップするか
detailed_output falseに設定すると、テストがパスまたは失敗した時にテストケース名のみを表示

テストを書く

BDD形式

Nightwatchは バージョン0.7からBDD形式のインターフェースが追加されました。

Chai Expectアサーションライブラリを利用しています。

this.demoTest = function (browser) {
  browser.url(browser.launchUrl);
  browser.waitForElementVisible('body', 1000);
  browser.click('[href="/login"]');
  browser.setValue('#login_field', 'example@machiiro.jp');
  browser.setValue('#password', 'veryveryFukuzatsunaPassword');
  browser.click('input[data-disable-with="Signing in…"]');
  browser.pause(1000)
  browser.assert.elementPresent('.header-logged-in')
  browser.end();
};

assert/verify形式

伝統的なassert/verify形式でも記述できます。

module.exports = {
  'Demo test Github' : function (browser) {
    browser
      .url(browser.launchUrl)
      .waitForElementVisible('body', 1000)
      .click('[href="/login"]')
      .setValue('#login_field', 'example@machiiro.jp')
      .setValue('#password', 'veryveryFukuzatsunaPassword')
      .click('input[data-disable-with="Signing in…"]')
      .pause(1000)
      .assert.elementPresent('.header-logged-in')
      .end();
  }
};

APIの一覧はhttp://nightwatchjs.org/apiにあります。

テストを実行する

以上までで、ディレクトリの構成は次のようになります。

.
├── lib
│   ├── phantomjs-2.1.1-macosx
│   └── selenium-server-standalone-2.53.1.jar
├── nightwatch.json
├── node_modules
├── package.json
└── tests
    └──test.js

設定のsrc_settingに記載した全てのディレクトリのテストを実行する場合は、対象のテストファイルを指定する引数なしで実行します。

$ nightwatch

一つのテストファイルをだけテストしたい場合は、ファイルを指定してテストを実行することができます。

$ nightwatch ./tests/test.js

成功すると、Success!と表示されます。嬉しいですね!

$ nightwatch ./tests/test.js
Starting selenium server... started - PID:  11111

[Github / Top] Test Suite
================================

Running:  Demo test GitHub
 ✔ Element <body> was visible after 1200 milliseconds.
 ✔ Testing if element <.container h1 strong a> is visible.
 ✔ Checking project title is set to nightwatch

OK. 3 assertions passed. (12.974s)

失敗した場合は、失敗した箇所が×で表示されます。

設定ファイルのscreenshotstrueに指定しておいた場合、自動的に対応するフォルダが生成され、失敗直後のキャプチャが保存されます。

Starting selenium server... started - PID:  11641

[Github / Top] Test Suite
================================

Running:  Demo test GitHub
 ✔ Element <body> was visible after 1083 milliseconds.
 ✖ Testing if element <#login_fieldd> is visible. Element could not be located.  - expected "true" but got: "null"
    at _combinedTickCallback (internal/process/next_tick.js:67:7)

ERROR: Unable to locate element: ".container h2 strong a" using: css selector


FAILED:  1 assertions failed, 1 errors and 1 passed (10.28s)

groupやtagを指定してテストを実行する

grouptagskipオプションを利用することで、お望みのテストを一括で指定したり、除外して実行をすることができます。

例として以下のようにテストが配置されているとします。

└── tests
    ├── github
    │   ├── login_test.js
    │   └── top_test.js
    └── google
        ├── login_test.js
        └── top_test.js

groupsrc_foldersで指定したフォルダのサブディレクトリの名称を指定します。

この例で言うとgithubgooglegroupになります。

グループを指定して実行する場合は次のようにオプションをつけます。

$ nightwatch --group github

また、tagは各テストファイルの中に次のような形で記述することでオプションから指定することが可能になります。

module.exports = {
  'tags': ['top', 'sanity'],
  '[demo] test': function (client) {
     // test code
  }
};

タグを指定して実行する場合。

$ nightwatch --tag login

まとめ

本番デプロイ前後はいつもどきどきですが、テストが通っていると同じ不安でも程度が違いますよね。

皆さんも、よりよいテスト生活を送られるようお祈りしております。