Protractorとは、AngularJSアプリケーションのためのエンド・トゥー・エンド(E2E)テスト・フレームワークです。これはProtractor Tutorialの日本語訳です。
チュートリアル
これはシンプルなチュートリアルです。内容は、Protractorをセットアップし、テストを走らせ始める方法です。(訳注:protractorは分度器のことです)
訳注:本チュートリアルのサンプル・リポジトリを作りました。参考になれば幸いです。
準備
ProtractorはNode.jsのプログラムです。動かすには、Node.jsをインストールしておかなければなりません。ProtractorはNode.jsについてくるnpmを使ってダウンロードすることができます。node --version
と打って、Node.jsのバージョンをチェックして下さい。v0.10.0以降でなければなりません。
デフォルトでは、ProtractorはJasmineテスト・フレームワークをテストするインターフェースのために使います。このチュートリアルでは、Jasmineについてあるていど知っているものとして進めます。
このチュートリアルは、ブラウザを制御するため、ローカルのスタンドアローンなSeleniumサーバを使うテストをセットアップします。スタンドアローンのSeleniumサーバーを動かすためにJava Development Kit (JDK)が必要になるでしょう。コマンドラインからjava -version
コマンドを走らせてJDKが入っているか調べて下さい。
セットアップ
npmを使ってProtractorをグローバルにインストールして下さい:
$ npm install -g protractor
これで2つのコマンドライン・ツールがインストールされます。protractor
とwebdriver-manager
です。protractor --version
と打ってみて、それが確かに動いているか確認して下さい。
webdriver-manager
は、動作中のSeleniumサーバのインスタンスを簡単に取得するためのヘルパー・ツールです。必要なバイナリをダウンロードするために使って下さい:
$ webdriver-manager update
さあ、サーバを起動しましょう:
$ webdriver-manager start
これでSeleniumサーバーが起動し、a bunch of info logs を出力します。Protractorのテストは、ローカルのブラウザを制御するために、このサーバにリクエストを送ります。チュートリアルのあいだは、このサーバを起動したままにしておいて下さい。http://localhost:4444/wd/hub
にアクセスすることで、サーバのステータスについての情報を見ることができます。
訳注:サンプルプロジェクトをセットアップの状態にするにはプロジェクトフォルダの中に入って以下のようにします:
$ git checkout -f setup
サンプルプロジェクトではprotractorをグローバルではなくローカル(プロジェクトフォルダ内)にインストールしました。具体的には、以下のように作りました:
$ npm init
$ npm install protractor --save-dev
webdriver-managerの実行は以下のように行いました。
$ ./node-modules/protractor/bin/webdriver-manager update
$ ./node-modules/protractor/bin/webdriver-manager start
ステップ 0 - テストを書こう
新しいコマンドラインかターミナル・ウィンドウを開き、テストのためのまっさらなフォルダを作って下さい。
Protractorを動かすのに必要なのは、specファイルと設定ファイルの2つのファイルです。
さあ、とあるAngularJSアプリケーションを表示してそのタイトルをチェックするというシンプルなテストから始めましょう。そのアプリケーションは、「Super Calculator」(http://juliemr.github.io/protractor-demo/)です。
以下のspec.jsをコピーして下さい:
describe('AngularJSホームページ', function() {
it('タイトルを持つ', function() {
browser.get('http://juliemr.github.io/protractor-demo/');
expect(browser.getTitle()).toEqual('Super Calculator');
});
});
describe
とit
の文法はJasmineフレームワークのものです。browser
はProtractorによって作られたグローバルで、browser.get
でページを表示すると言ったブラウザレベルのコマンドのために使われます。
さあ、設定ファイルを作りましょう。以下の内容をconf.jsにコピーして下さい:
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['spec.js']
}
この設定ファイルに書かれているのは、Protractorに、どこにあなたのテストファイルがあるか(specs
)と、あなたのSeleniumサーバと対話するにはどうしたらよいか(seleniumAddress
)です。他のすべての設定はデフォルトになっています。Chromeがデフォルトのブラウザです。
では、以下のようにテストを走らせましょう:
$ protractor conf.js
すると、Chromeブラウザのウィンドウが開きCalculatorのページを開き、それからウィンドウが閉じます(これはあっというまです)。テストの出力は1 tests, 1 assertion, 0 failures
となっているはずです。おめでとう、あなたは最初のProtractorテストを走らせたのです。
訳注:サンプルプロジェクトをステップ0の状態にするにはプロジェクトフォルダの中に入って以下のようにします:
$ git checkout -f step-0
サンプルプロジェクトではまずpackage.jsonファイルに以下のコードを追加しました。
"scripts": {
"test": "protractor test.js",
"conf": "protractor conf.js"
},
テストを走らせるには以下のようにしました:
$ npm run conf
ステップ 1 - 要素を調べる
さて、ページ上の要素を調べるためにテストを修正しましょう。spec.jsを以下のように変更します:
describe('AngularJSホームページ', function() {
it('1と2を加える', function() {
browser.get('http://juliemr.github.io/protractor-demo/');
element(by.model('first')).sendKeys(1);
element(by.model('second')).sendKeys(2);
element(by.id('gobutton')).click();
expect(element(by.binding('latest')).getText()).
toEqual('5'); // これはまちがい!
});
});
このテストではglobal?(編集リクエスト求む)のelement
とby
が使われています。これらはProtractorによって作られています。element
関数はWebページからHTML要素を見つけるために使われます。ElementFinderオブジェクトが返り、それは要素を調べて情報を得るのに使うことができます。このテストでは、2つの<input>
に数字を打ち込み、click
によってボタンをクリックし、getText
によって要素の内容を返すためにsendKeys
を使います。
element
はLocatorという1つの引数をとります。これは、その要素をどのように見つけるかを記述します。by
オブジェクトはLocatorをつくります。ここでは、3つのタイプのLocatorを使っています:
-
by.model('first')
は、ng-model="first"
の付いた要素を見つけます。もしあなたがCalculatorページのソースを調べれば、これは<input type=text ng-model="first">
のことだということが見つかることでしょう。 -
by.id('gobutton')
は、idを与えられた要素を見つけます。これは<button id="gobutton">
を見つけます。 -
by.binding('latest')
は、latest
変数に結びつけられた要素を見つけます。これは{{latest}}
を含む要素を見つけます。
LocatorとElementFinderについて、もっと学ぶ.
以下のようにテストを走らせて下さい:
$ protractor conf.js
あなたは、そのページに2つの数字が入力されるのを見るでしょう。そして、結果が表示されるのを待つでしょう。結果は3で、5ではないので、私たちのテストは失敗します。テストを修正して再度テストを走らせてみて下さい。
訳注:サンプルプロジェクトをステップ1の状態にするにはプロジェクトフォルダの中に入って以下のようにします:
$ git checkout -f step-1
サンプルプロジェクトでテストを走らせるには以下のようにして下さい:
$ npm run conf
ステップ 2 - 複数のシナリオを書く
これらの2つのテストをいっしょにして、すこし形を整えましょう。spec.jsを以下のように変えます:
describe('AngularJSホームページ', function() {
var firstNumber = element(by.model('first'));
var secondNumber = element(by.model('second'));
var goButton = element(by.id('gobutton'));
var latestResult = element(by.binding('latest'));
beforeEach(function() {
browser.get('http://juliemr.github.io/protractor-demo/');
});
it('タイトルを持つ', function() {
expect(browser.getTitle()).toEqual('Super Calculator');
});
it('1と2を加える', function() {
firstNumber.sendKeys(1);
secondNumber.sendKeys(2);
goButton.click();
expect(latestResult.getText()).toEqual('3');
});
it('4と6を加える', function() {
// この部分を自分で書いて下さい
expect(latestResult.getText()).toEqual('10');
});
});
ここでは、ページを表示する制御をbeforeEach
関数の中に入れました。それはそれぞれのit
ブロックの前に実行されます。また、一つ目と二つ目の入力のためのElementFinderをいい感じの変数に格納して再利用可能にしました。これらの変数を使って、2番目のテストを自分で書いて下さい。そしてテストを再度走らせ、通ることを確認して下さい。
訳注:サンプルプロジェクトをステップ2の状態にするにはプロジェクトフォルダの中に入って以下のようにします:
$ git checkout -f step-2
ステップ 3 - 設定を変えてみましょう
さて、初歩的なテストをいくつか書いたところで、設定ファイルを見てみることにしましょう。設定ファイルはどのブラウザを使うか、とかどうやってSeleniumサーバに接続するか、といったことを変えることができます。では、ブラウザを変えてみましょう。conf.jsを以下のように変えます:
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['spec.js'],
capabilities: {
browserName: 'firefox'
}
}
再度テストを走らせてみて下さい。テストがChromeの代わりにFirefox上で走るはずです。capabilities
にはテストを実行するブラウザを記述します。すべてのオプションを見るには、設定ファイル・リファレンスを見て下さい。
訳注:サンプルプロジェクトをステップ3の前半の状態にするにはプロジェクトフォルダの中に入って以下のようにします:
$ git checkout -f step-3-1
2つ以上のブラウザでテストを走らせることもできます。conf.jsを以下のように変えて下さい:
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['spec.js'],
multiCapabilities: [{
browserName: 'firefox'
}, {
browserName: 'chrome'
}]
}
もう一度テストを走らせてみて下さい。テストがChromeとFirefox上でsimultaneouslyに実行され、結果がコンソール上に別々に表示されるはずです。
訳注:サンプルプロジェクトをステップ3の後半の状態にするにはプロジェクトフォルダの中に入って以下のようにします:
$ git checkout -f step3-2
ステップ 4 - 要素のリスト
テスト・ファイルに戻りましょう。設定ファイルは、一つのブラウザだけを使うように変えてもらって結構です。
時折、複数の要素のリストを扱いたくなるでしょう。element.all
を使うことでこれができます。これは一つのElementArrayFinderを返します。計算機アプリケーションでは、操作のそれぞれは履歴に記録されます。履歴は、そのサイト上でng-repeat
を使った表として埋め込まれています。いくつか操作しましょう。そして、履歴に入った操作をテストしましょう。spec.jsを以下のように変えます:
describe('AngularJSホームページ', function() {
var firstNumber = element(by.model('first'));
var secondNumber = element(by.model('second'));
var goButton = element(by.id('gobutton'));
var latestResult = element(by.binding('latest'));
var history = element.all(by.repeater('result in memory'));
function add(a, b) {
firstNumber.sendKeys(a);
secondNumber.sendKeys(b);
goButton.click();
}
beforeEach(function() {
browser.get('http://juliemr.github.io/protractor-demo/');
});
it('履歴がある', function() {
add(1, 2);
add(3, 4);
expect(history.count()).toEqual(2);
add(5, 6);
expect(history.count()).toEqual(0); // これはまちがい!
});
});
ここではいくつかのことをしました。最初に、add
というヘルパー関数を作りました。history
変数を追加しました。element.all
をby.repeater
Locatorといっしょに使ってElementArrayFinderオブジェクトを取得しました。このテストでは、履歴が想定された長さを持つかどうかを、count
メソッドを使うことで確かめています。テストを直して2番目の想定が通るようにして下さい。
ElementArrayFinder
は、count
の他にもたくさんのメソッドを持っています。Locatorによって見つかった最後の要素のマッチするElementFinderを取得するためにlast
を使いましょう。テストを以下のように変えます。
it('履歴がある', function() {
add(1, 2);
add(3, 4);
expect(history.last().getText()).toContain('1 + 2');
expect(history.first().getText()).toContain('foo'); // これはまちがい!
});
計算機はいちばん古い結果をいちばん下に表示するため、最後の(1 + 2)の加算は履歴entryの最後になるはずです。toContain
というJasmineのmatcherを使うことで、その要素テキストが「1 + 2」を含んでいることを検証することができます。要素テキスト全体はタイムスタンプと結果も含みます。
テストを直して、最初の履歴がテキスト「3 + 4」を含むことを正しく想定するようにして下さい。
ElementArrayFinderは他にもJavaScriptの配列のメソッドに似たeach
、map
、filter
、reduce
というメソッドを持っています。詳細はAPIドキュメントを読んで下さい.
訳注:サンプルプロジェクトをステップ4の状態にするにはプロジェクトフォルダの中に入って以下のようにします:
$ git checkout -f step-4
この次に読むもの
これであなたはテストを書く準備ができました。さらに学びたい場合は、ドキュメントを読んで下さい。目次。