Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
34
35

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Not Angularな環境でProtractorを使ってES2015(ES6), ES7なE2Eテストコードを書いてみた

Last updated at Posted at 2015-10-06

追記

注意
サンプルコードなので省いていますがコードではawaitとしてPromiseのコールバックを隠ぺいしています。
実際にはPromiseresolveではなくrejectを返すこともあるので、実際のコードではtry-catchを使ってちゃんとエラーを捕捉しましょう。

async func() {
  try {
    let t = await funcReturnPromise();
  } catch(err) {
    console.log(err);
  }
}

はじめに

ProtractorはAunglarのためのように使われてますが、Yahoo Mailでの自動テストに書いてあるようにReact+Flux環境でもテスト(機能テスト、スモークテスト、インテグレーションテスト)に使われているということで試してみました。

以下の方針でコード例を記述します。

  • ES2015を使ってモダンにテストコードを書く
  • mocha + power-assertなテスト環境
  • E2EテストはPageObjectパターンを利用

環境

  • Mac OS X Yosemite
  • Node 4.1.1

準備

ディレクトリ構造

$ tree -I node_modules
.
├── package.json
├── protractor.conf.js
└── spec
    ├── test1
    │   ├── BingPageObject.js
    │   └── bing_spec.js
    └── test2
        ├── GooglePageObject.js
        └── google_spec.js

設定ファイル等

今回使うライブラリはpackage.jsonの通りです。

package.json
{
  "name": "example_for_protractor",
  "version": "1.0.0",
  "description": "Example for Protractor",
  "license": "MIT",
  "devDependencies": {
    "babel": "^5.8.23",
    "babel-plugin-espower": "^1.0.0",
    "mocha": "^2.3.3",
    "power-assert": "^1.1.0",
    "protractor": "^2.4.0"
  },
  "scripts": {
    "postinstall": "webdriver-manager update"
  }
}

使ったライブラリでミソなのはpower-assert-js/babel-plugin-espowerです。
これは以下のprotractor.conf.jsで活用します。

protractor.conf.js
// Babel Require Hookを通してpower-assertを使ったES2015コードを変換する
require("babel/register")({
  only: /spec/,
  plugins: ['babel-plugin-espower'],
  extensions: ['.es6', '.js']
});

exports.config = {
  // specの実行前に、protractorが準備できたら一度だけ呼ばれる関数
  onPrepare: function () {
    browser.ignoreSynchronization = true;
  },

  directConnect: true,

  capabilities: {
    'browserName': 'chrome'
  },

  framework: 'mocha',

  suites: {
    test1: './spec/test1/*_spec.js',
    test2: './spec/test2/*_spec.js'
  },

  mochaOpts: {
    ui: 'bdd',
    reporter: "spec",
    slow: 3000,
    enableTimeouts: false
  }
};

ProtractorでES2015なテストコードを扱う場合はprotractor.conf.jsを起点に呼ばれるのでrequire("babel/register")を仕込んでおきます。
またさらにpower-assertも使いたい場合はbabel-plugin-espowerもフックさせると良いです。
こうしておくことで $(npm bin)/protractor protractor.conf.js だけでES2015とpower-assertの変換を掛ける必要がなくなるので書いたコードをすぐ実行できるようになります。

そしてonPrepare内の browser.ignoreSynchronization = true; を書くことでAngularの処理が完了するまで待たない(Not Angular環境でもProtractorが使える)ということになります。

テストコード

例としてとりあえず書いたコードを以下にあげます。
なんだこのテストは、というものもあるかもしれませんがそこは例ということで。

spec/test1/BingPageObject.js
"use strict";
export default class BingPageObject {
    constructor(url) {
        this.url = 'https://www.bing.com/';
    }

    async getPage() {
        await this.navigateTo(this.url);
    }

    async navigateTo(url) {
        await browser.get(url);
    }

    async getTitle() {
        let title = await browser.getTitle();
        return title;
    }

    async typeQuery(query) {
        let textbox = await $('#sb_form_q');
        return await textbox.sendKeys(query);
    }

    async search(query) {
        let submit = await $('#sb_form_go');
        await this.typeQuery(query);
        return submit.click();
    }

    async getQuery() {
        let textbox = await $('#sb_form_q');
        return await textbox.getAttribute('value');
    }

    async getAlgo() {
        let algo = await $$('#b_results > li').filter(async(elem) => {
           let cls = await elem.getAttribute('class');
           return cls === 'b_algo';
        });

        return await algo.map(async(elem) => {
            let title = await elem.$('h2').getText();
            return title;
        });
    }
}
bing_spec.js
"use strict";

import assert from "power-assert";

import BingPageObject from "./BingPageObject"

describe('Bing.com', () => {
    let page;
    let query = '天気';

    before(async() => {
        page = new BingPageObject();
        page.getPage();
        await page.search(query);
    });

    it('検索窓に入力したクエリが表示されている', async() => {
         let text = await page.getQuery();
         assert(text === query);
    });

    it('アルゴが表示されている', async() => {
        let algo = await page.getAlgo();
        assert(algo.length === 10);
    });
});

実行結果

$ $(npm bin)/protractor protractor.conf.js --suite test1
Using ChromeDriver directly...
[launcher] Running 1 instances of WebDriver


  Bing.com
    ✓ 検索窓に入力したクエリが表示されている
    ✓ アルゴが表示されている


  2 passing (3s)

[launcher] 0 instance(s) of WebDriver still running
[launcher] chrome #1 passed

ちょっとテストコードを失敗するようにしてみると

$ $(npm bin)/protractor protractor.conf.js --suite test1
Using ChromeDriver directly...
[launcher] Running 1 instances of WebDriver


  Bing.com
    1) 検索窓に入力したクエリが表示されている
    ✓ アルゴが表示されている


  1 passing (3s)
  1 failing

  1) Bing.com 検索窓に入力したクエリが表示されている:

      AssertionError:   # spec/test1/bing_spec.js:19
  
  assert(text === 'hoge')
         |    |          
         |    false      
         "天気"          
  
  --- [string] 'hoge'
  +++ [string] text
  @@ -1,4 +1,2 @@
  -hoge
  +天気
  
  
      + expected - actual

      -false
      +true
      
[launcher] 0 instance(s) of WebDriver still running
[launcher] chrome #1 failed 1 test(s)
[launcher] overall: 1 failed spec(s)
[launcher] Process exited with error code 1

いい感じにpower-assertも動いているようですね!

まとめ

もともとこの内容は息抜きのつもりでいて、ProtractorとMochaやProtractorとBabelといった内容は見つかったのですが、さらにpower-assertを合わせたり、Angular環境でない場合はどうすればという疑問から試して書き起こしてみました。

余談ですがProtractor以外にも、個人的には(少し試しただけですが)E2Eテストとしてgroupon/testiumも悪くないかと思います。

参考資料

34
35
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
35

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?