Protractorを使ったE2Eテストの準備


# はじめに

E2EテストとはEnd to End（エンドツーエンド）の略らしいです。最初から最後までということのようです。
ブラウザを使ったテストの自動化のために今回はProtractorを使うことにしました。
ちょうど仕事で担当になった運用サイトがAngular製アプリケーションだったこともあります。
ProtractorはAngular製のサイトに向いているとのことです。ただAngular製ではないサイトでも利用可能です。

Protractorはwebdriver-managerというものを使ってSeleniumを利用します。
準備するものはnodejsです。

前回書いた次の記事でnodejsを用意していただければ動作します。
[windows10でnode.jsのバージョンを切り替えて使う( nvm-windows )](https://qiita.com/satoysan/items/d88eda88b496f44823e1)

今回はwindows10の環境で進めます。

## Protractorの準備

適当なディレクトリを用意します。仮にprotractor_sampleというディレクトリにします。
コマンドプロンプトを開いて、protractor_sampleディレクトリに移動し、npmコマンドでpackage.jsonを作ります。

```
> npm init -y
``` 

そのまま、protractorをローカルディレクトリのnode_modulesにインストールします。グローバルでインストールしたい場合は-gを入れてください。

```
> npm install protractor
```

次に、PCにインストールされているブラウザに合わせてwebdriverを最新にします。

```
> "./node_modules/.bin/webdriver-manager" update
```

Seleniumを起動します。起動したらもう一つコマンドプロンプトを開いてください。

```
> "./node_modules/.bin/webdriver-manager" start
```

以上でprotractor自体のインストールは終わりです。

## Protractorの設定ファイルを用意

protractor_sampleディレクトリ直下にconf.jsを作り、次のように書きます。

```javascript:conf.js

exports.config = {

    // Testing FrameWorkにjasmine2を利用
    framework: 'jasmine2',

    // seleniumの待ち受けURLを指定
    seleniumAddress: 'http://localhost:4444/wd/hub',

    // 動作させるspec(テストケース)ファイルを指定
    specs: ['specs/case1.js'],

    // テストさせるブラウザを指定
    multiCapabilities: [
        { browserName: 'chrome' },
        // { browserName: 'firefox' },
    ],

    onPrepare: function(){
        browser.waitForAngularEnabled(true);
    }
};
```

これで最低限の設定ができたので、テストを書きます。specsというディレクトリを作りそこにcase1.jsを書きます。
（ファイル名もディレクトリ名も自由に決めて構いません。conf.jsに定義いただければ。）

```javascript:case1.js
//ウィンドウサイズ
const width = 1024;
const height = 768;

//テストしたい最初のページURL
const url = "http://www.way2automation.com/angularjs-protractor/registeration/#/login";

//各所のinput達
//loginページ
const ele_username  = element(by.xpath('//*[@id="username"]'));
const ele_password  = element(by.xpath('//*[@id="password"]'));
const ele_name      = element(by.xpath('//*[@id="formly_1_input_username_0"]'));
const ele_login     = element(by.xpath('/html/body/div[3]/div/div/div/form/div[3]/button'));
const ele_error_msg = element(by.xpath('/html/body/div[3]/div/div/div/div[2]'));

//login後ページ
const ele_logout    = element(by.xpath('/html/body/div[3]/div/div/div/p[2]/a'));
const ele_login_msg = element(by.xpath('/html/body/div[3]/div/div/div/p[1]'));

browser.driver.manage().window().setSize(width, height);

describe('case01-ログイン', function() {

    beforeEach(function() {
        //なにかあらかじめ実行したい時ここに書く
    });

    it('spec001-ログイン', async function() {
        browser.get(url);
        ele_username.sendKeys("angular");
        ele_password.sendKeys("password");
        ele_name.sendKeys("angular user");
        ele_login.click();
    });

    it('spec002-ログアウト', async function() {
        expect(ele_login_msg.getText()).toEqual("You're logged in!!");
        ele_logout.click();
    });

});

```

beforeEachというのは各itが実行される前に1度呼び出されるものを定義します。
また、confやテストケースのコード内でwaitForAngularEnabledをtrueまたはfalseにすることによってAngularの待機処理を待つか待たないか指定できます。待機処理を正しく待たない場合domのロードに間に合わずelementを取得できないためです。


## テストの実行
```
> "./node_modules/.bin/protractor" conf.js
```

ブラウザが（この場合chromeが）起動しテストが開始されます。

## 実行結果

実行すると次のように問題が無かった場合次のように表示されますね。
この表示はとてもさみしいので、ログがもっとちゃんと出るようにします。

```
[17:11:45] I/launcher - Running 1 instances of WebDriver
[17:11:45] I/hosted - Using the selenium server at http://localhost:4444/wd/hub
Started
..


2 specs, 0 failures
Finished in 4.745 seconds

[17:11:51] I/launcher - 0 instance(s) of WebDriver still running
[17:11:51] I/launcher - chrome #01 passed
```

## 実行結果ログをもっとかっこよくする

npmコマンドでjasmine-spec-reporterを追加する

```
> npm install jasmine-spec-reporter
```

次にconf.jsにレポーター処理を追加。``onPrepare``に処理を追加します。

```javascript:conf.js

exports.config = {

    // Testing FrameWorkにjasmineを利用
    framework: 'jasmine2',

    // seleniumの待ち受けURLを指定
    seleniumAddress: 'http://localhost:4444/wd/hub',

    // 動作させるspecファイルを指定
    specs: ['specs/case1.js'],


    // テストさせるブラウザを指定
    multiCapabilities: [
        { browserName: 'chrome' },
        // { browserName: 'firefox' },
    ],

    onPrepare: function(){
        browser.waitForAngularEnabled(true);

        /**
         * コンソールログを美しくする設定
         */
        let env = jasmine.getEnv();
        env.clearReporters();
        let SpecReporter = require('jasmine-spec-reporter').SpecReporter;

        env.addReporter(new SpecReporter({
            displayStacktrace: 'all',      // display stacktrace for each failed assertion, values: (all|specs|summary|none)
            displaySuccessesSummary: true, // display summary of all successes after execution
            displayFailuresSummary: true,   // display summary of all failures after execution
            displayPendingSummary: true,    // display summary of all pending specs after execution
            displaySuccessfulSpec: true,    // display each successful spec
            displayFailedSpec: true,        // display each failed spec
            displayPendingSpec: true,      // display each pending spec
            displaySpecDuration: true,     // display each spec duration
            displaySuiteNumber: true,      // display each suite number (hierarchical)
            colors: {
                success: 'green',
                failure: 'red',
                pending: 'yellow'
            },
            prefixes: {
                success: '✓ ',
                failure: '✗ ',
                pending: '* '
            },
            customProcessors: []
        }));
    }

};
```

以上で準備ができましたので、テストを再実行します。

```
[17:25:29] I/launcher - Running 1 instances of WebDriver
[17:25:29] I/hosted - Using the selenium server at http://localhost:4444/wd/hub
Jasmine started

  case01-ログイン
    √ spec001-ログイン
    √ spec002-ログアウト

Executed 2 of 2 specs SUCCESS in 4 secs.
[17:25:35] I/launcher - 0 instance(s) of WebDriver still running
[17:25:35] I/launcher - chrome #01 passed
```

これで、テスト項目の何が成功しているのかわかるようになりました。
（ちなみにテストケースの名称に半角の?を入れるとこけるので、気を付けましょう。。）

## 他に。。

スクリーンショットとったり、他のサービスにpostしたりする方法とかもあるのですが、それはまた次回にします。