AngularJSナシでもできる!Protractor(selenium-webdriver+jasmine)でWebサイトのE2Eテスト入門

WebサイトのE2Eテストとは

E2Eというのは、「End to End(エンドツーエンド)」のことで、「両端で」「端から端まで」という意味の言葉です。

E2Eテストは、Webサイトやアプリケーションの「開始から終了まで」の両端において、設計された通りにフローが実行されているかどうかをテストするためのものです。

たとえば、OGPやリンクが正しく設定されているか、どこかを変更した場合に既に設計通りに動いている部分に影響が及んでいないかなど、いったんブラウザでレンダリングした状態を基に確認していきます。

とはいえ、どこか変更するたびに毎回人力で1つ1つ確認していくのは大変ですね。そこで、Jasmineの使い方で学ぶJavaScriptのテストコード入門で紹介した「テストコード」というものを使って自動化します。

Protractorとは

Protractorは本来AngularJSのE2Eテストのために開発されたE2Eテストフレームワークですが、AngularJSを使っていないWebサイトにも使用することができます。

Protractorなら導入も簡単ですし、WordPressなどのE2Eテストにも使える上、テストコードはJasmineで書けるので現段階でWILDWEST-SERVICEに最も適したE2Eテストフレームワークであると言えます。

下準備(Node.jsのインストール)

お使いの端末に既にNode.jsがインストールされており「npm」コマンドがターミナルやコマンドプロンプト(いわゆる黒い画面)で実行できることが前提条件です。

Node.jsのインストールについては、Node.jsの公式ページをご覧ください。

MacOSXの場合はnodebrewを通してインストールするのがおすすめですが、Node.jsの知識があまりない場合は普通にインストーラーでインストールしてしまっても良いでしょう。

Node.jsがインストールされれば、同時にターミナルやコマンドプロンプトでnpmコマンドを使えるようになっているはずです。

ターミナル、またはコマンドプロンプトを起動し、次のコマンドを入力してみてください。npmのバージョンが表示されれば無事にインストールされています。

npm -v

Protractorのインストール

Node.jsとnpmがインストールされたら、いよいよProtractorをインストールしましょう。

ターミナルおよびコマンドプロンプトで、次のコマンドを入力してください。

npm install -g protractor

これでProtractorのインストールが開始されます。次のコマンドを入力して、Protractorが動作するか確認してみてください。

protractor --version

Protractorのバージョンが表示されていれば大丈夫です。

MacOSXやLinuxでうまくインストールできない場合

MacOSXやLinuxでは、コマンドの先頭にsudoをつけないとうまく動作しない場合もあるようです。

その場合、次のように入力してProtractorをインストールしてみてください。

sudo npm install -g protractor

webdriver-managerのアップデートと起動

Protractorをインストールすると、パッケージ内にselenium-webdriverが含まれています。

Protractorをインストールした際にはwebdriver-managerをアップデートしておいたほうが良いようなので、次のコマンドを入力してください。

webdriver-manager update

あとは設定とテストコードを記述すればProtractorでE2Eテストを実行することができます。

Protractorの設定ファイルを作る(conf.js)

適当にE2Eテスト用のディレクトリ(フォルダー)を作って、そこへconf.jsというJavaScriptのファイルを作成してください。
今回は例としてe2eという名前のディレクトリを作成したと仮定して説明を進めていきます。

conf.jsの中身は次のように記述してください。

capabilities:の中では、キーにあたる「'browserName'」の部分にクォーテーションがついていることと、ブラウザ名の指定は「'Chrome'」ではなく「'chrome'」と、すべて小文字になっている点に注意しましょう。

exports.config = {
  seleniumAddress: '//localhost:4444/wd/hub', // Seleniumサーバー
  capabilities: { // テストに使用するブラウザ設定を記述する部分
    'browserName': 'chrome' // Google Chromeでレンダリングしてテストします(記述方法に注意 よく見て)
  },
  specs: ['spec.js'], // 実行するテストコードが記述されたファイルを指定
  baseUrl: 'https://www.google.co.jp/', // テスト対象のベースURL(相対パスの基準となります)
  framework: 'jasmine2', // 使用するテストフレームワークの指定
  jasmineNodeOpts: { // Jasmine用の設定を記述する部分
    showColors: true // ターミナルの出力結果が色つきになります
  }
}

それぞれの項目について以下で簡単に説明していきますが、conf.jsで設定できる内容についてすべて知りたい場合は、ProtractorのGitHubページ内のreferenceConf.jsをご覧ください。

Seleniumサーバー

先ほどアップデートしたSeleniumサーバーのURLです。

特に設定を変更していなければ、上記の例のままのURLそのままで大丈夫です。

テストに使用するブラウザ設定

どのブラウザを使うのかや、それぞれのブラウザに対するオプション設定などを記述することができます。

標準ではGoogle Chromeで実行されるので、たとえばFirefoxでテストしたい場合には「'firefox'」と書き換えてください。

また、複数のブラウザで同時にテストしたい場合には、次の記述のほうを使用してください。

「capabilities: {」だったのに対して「multiCapabilities: [」となり、使用する括弧が{から[に変わっていますので注意してください。

exports.config = {
  seleniumAddress: '//localhost:4444/wd/hub', // Seleniumサーバー
  multiCapabilities: [ // テストに使用するブラウザ設定を記述する部分({が[に変わっているのに注意 閉じ側も同様)
    {
      'browserName': 'chrome' // Google Chromeでレンダリングしてテストします(記述方法に注意 よく見て)
    },
    {
      'browserName': 'firefox' // Firefoxでレンダリングしてテストします(記述方法に注意 よく見て)
    }
  ],
  specs: ['spec.js'], // 実行するテストコードが記述されたファイルを指定
  baseUrl: 'https://www.google.co.jp/', // テスト対象のベースURL(相対パスの基準となります)
  framework: 'jasmine2', // 使用するテストフレームワークの指定
  jasmineNodeOpts: { // Jasmine用の設定を記述する部分
    showColors: true // ターミナルの出力結果が色つきになります
  }
}

実行するテストコードが記述されたファイルを指定

テストコードは目的に応じて別ファイルに記述します。

実際のE2Eテストコードの書き方について、後ほど説明します。

テスト対象のベースURL

URL指定の際の相対パスの基準となるベースURLです。

テスト対象にしたいサイトのベースURLと同じものを入力してください。(今回は例としてGoogleのトップページとしてあります)

使用するテストフレームワークの指定

jasmineではなくjasmine2を指定してください。ここも「'Jasmine'」のように大文字は使わずすべて小文字で指定します。

jasmineのほかにもmochaやcucumberを指定できますが、そちらを使う場合には別途インストールや設定が必要になります。

Mocha・Cucumberをテストフレームワークに使用したい場合はProtractorの公式サイトをご覧ください。

Jasmine用の設定を記述する部分

基本的にはshowColorsだけで良いと思います。

外部プラグインを使用するなど、他の設定を追加したい場合には、Protractorの公式スライド内42ページ、Using jasmineNodeOptsまたはProtractorのGitHubページ内のreferenceConf.jsをご覧ください。

Jasmineでテストコードを記述する

いよいよテストコードを記述していきます。

conf.jsと同じところにspec.jsというJavaScriptファイルを作成してください。

spec.jsの中身は、テストコード部分において基本的にはJasmineのSpecファイルとなるので、Jasmineの使い方で学ぶJavaScriptのテストコード入門でご紹介した通りです。

しかし、それだけではありません。Protractorを通じてSeleniumに自動でフォーム入力させたりキー入力させるための処理などを同じファイル内に含みますので、Jasmineを使ってJavaScriptの関数などを単体テストする場合よりも、少し複雑になります。

browser.ignoreSynchronization = true; // AngularJSを使っていなくてもProtractorを動作させるために記述が必要

var myTitle,
  currentUrl;

searchWords = 'Jasmine javascript 入門'; // 検索キーワード

browser.get('/') // テスト対象のURLにアクセス
currentUrl = browser.getCurrentUrl(); // 現在のURLを取得(トップページのURL)

$('#lst-ib').sendKeys(searchWords); // 指定した要素に自動で検索キーワードを入力させる
browser.actions().sendKeys(protractor.Key.ENTER).perform(); // Enterキーを自動で押させる

browser.sleep(2000); // 画面が遷移するまで処理を待つ必要があるので2秒だけ停止させる(秒数は適当)

describe('google', function () {

  it('match to myTitle', function () { // 

    <
    title > 要素のテキストに検索キーワードを含むか
    expect(browser.getTitle()).toMatch(searchWords);
  });

  it('change url', function () { // URLがトップページのURLと異なっているか(ページ遷移したか)
    expect(browser.getCurrentUrl()).not.toEqual(currentUrl);
  });

});

browser.sleep(5000); // 最後に5秒だけ停止させる(目で確認するためブラウザが自動で閉じるまで余裕をもたせる)

Protractorで自動操作

まずbrowser.get()でテスト対象のページにアクセスします。

ページにアクセスしたらテストのために必要なブラウザ上の操作を自動で行います。

今回は「Googleのトップページから検索キーワードを入力してEnterキーを押した」という動きを自動化させました。

セレクタをjQueryっぽくCSSスタイルで書くことができる

自動で検索キーワードを入力させている部分で、どのフォームに入力するかを指定するために「$('#lst-ib')」と書いています。

これはjQueryと同じCSSスタイルでのセレクタ指定方式ですね。

待たせる(wait)必要がある場合も

フォーム入力時やリンクのクリック時の挙動など、操作後にページ遷移やAJAX通信による処理が発生し、その処理結果を待ってからテストするような場合、browser.sleep()などで処理が完了するまで待たせる必要があります。

Protractorは本来AngularJSを使ったWebアプリケーションのE2Eテストを行うためのテストフレームワークですので、AngularJSであれば「画面表示完了を待ってテスト」という流れが作れるのですが、AngularJSを使わないものをE2Eテストする際にはbrowser.sleep()で指定秒数待たせたり、browser.wait()で何らかの条件を満たすまでテストコード内の処理をwaitさせます。

ようやっとJasmineでテストコードが書ける

その後のdescribe()以下はJasmineによるテストコードです。

テストが終わったらすぐブラウザが閉じる

ProtractorによるWebサイトのE2Eテストでは、テストが一通り完了した後でブラウザが自動的に閉じます。

表示状態を目でも確認したいような場合、テストコードの最後にbrowser.sleep()で何秒か停止させておくと良いでしょう。

ちなみに、MacOSXでE2Eテストしている場合にはbrowser.pause()でブラウザを閉じないようにできていたのですが、Windows7x64ではbrowser.pause()が効かずに閉じてしまい、ちょっとこのあたりまだよく分かっていません。

テストコードを走らせてみよう!

それでは、いよいよProtractorのE2Eテストコードを走らせてみたいと思います。

まずは、ターミナルまたはコマンドプロンプトでSeleniumサーバーを起動する必要があります。

Seleniumサーバーの起動

webdriver-manager start

ログが流れた後でSeleniumサーバーが起動し、入力を受け付けない状態になりますので、新しいウィンドウかタブでもう1つターミナルまたはコマンドプロンプトを開いてください。

ProtractorのE2Eテストを実行する

これですべての準備は完了です。いよいよProtractorを使ったE2Eテストを実行しましょう。

ターミナルまたはコマンドプロンプトで、cdコマンドを使ってconf.jsが置かれているディレクトリに移動してください。

下の画像のように、まず「cd 」と入力しておいて、目的のディレクトリをドラッグ&ドロップすると便利です。

最後にEnterキーを押すのを忘れずに。

ドラッグ&ドロップのイメージ1

ドラッグ&ドロップのイメージ2

移動できたら、次のコマンドを入力してみましょう。

protractor conf.js

E2Eテストコードを記述したのはspec.jsですが、Protractorの設定を記述したconf.jsをprotractorコマンドで起動します。

conf.jsの中で実行するSpecファイルを指定しているので、spec.jsはconf.jsを通して実行されているわけですね。

E2Eテストの結果はどのように表示されるか

Jasmineをスタンドアローンで実行していた時とは違い、テスト結果はターミナルやコマンドプロンプト上に出力されます。

ちなみに、このテストコードではエラーが出ないように記述しているのですが、「expect(browser.getCurrentUrl()).not.toEqual(currentUrl);」と記述している部分を「expect(browser.getCurrentUrl()).toEqual(currentUrl);」のように、.notを削ることでエラー時にどのように表示されるのかを見ることができます。

おそらく赤い文字でエラーに関する情報が表示されるはずです。

黒い画面の表示例

上の画像で「describe」と「it」で示した部分を手がかりに、どのテストコードでエラーが発生したのかを知ることができます。

expectで示した部分には、E2Eテストコード内のexpect()で指定した実際のブラウザの表示状態などが表示され、toEqual()で示した部分には、E2Eテストコード内のtoEqual()で設定した期待する値が表示されます。

上の画像で言うと、「describe('google')」の中の「it('change url')」において、「 https://www.google.co.jp 」と一致する値を期待したが、実際は「 https://www.google.co.jp/#q=Jasmine+javascript+%E5%85%A5%E9%96%80 」であったというエラー表示になっているわけです。

まとめ

ProtractorはやはりAngularJSを主な対象としたE2Eテストフレームワークなので、汎用性を求めようとすると、どうしても物足りない部分は出てしまいます。

とはいえ、導入までが非常に手軽なので、E2Eテストの入門にはなかなか良いのではないかと思います。

同じくらい手軽でもっと高機能なE2Eテストフレームワークがあれば乗り換えるかもしれませんが、しばらくはProtractorを中心にテスト駆動開発をしていきたいと思います。