Edited at

Testium + ES6(babel)でE2Eテストを書き始める

More than 3 years have passed since last update.

Selenium/Appium Advent Calendar 2015 11日目です。

薄っすい話より薄くて申し訳ない。

繰り返すブラウザテストは自動化しましょう。

さっそくJavaScriptのTestiumで書き始めます。


前提

現状、こんな感じのテストケースがあって、職人の手で真心込めて一つづつテストしていたとする。

画面
操作
期待する結果

Qiita検索画面
検索フォームに"title:Git"と入力して検索する
検索結果に、タイトルに"Git"を含んだ記事が並ぶ

...

これをそのまま自動化していきます。職人は解雇しましょう。


導入

$ mkdir -p e2e/test && cd e2e

$ npm init -y
$ npm install -D mocha babel@5 testium power-assert phantomjs

例によってbabel6は上手く動かせなかったので5指定だよ。


最初のテスト


test/test.js

import injectBrowser from 'testium/mocha';

import assert from 'power-assert';

describe('Qiita検索画面', function () {
before(injectBrowser());

context('検索フォームに"title:Git"と入力して検索する', function () {
it('検索結果に、タイトルに"Git"を含んだ記事が並ぶ', function () {
this.browser.navigateTo('http://qiita.com/search');
this.browser.setValue('#q', 'title:Git');
this.browser.getElement('button[type=submit]').click();

this.browser.getElements('.searchResult h1').forEach(result => {
assert(/git/i.test(result.get('text')));
});
});
});
});


実行

$ $(npm bin)/mocha --compilers js:babel/register

Qiita検索画面
検索フォームに"title:Git"と入力して検索する
✓ 検索結果に、タイトルに"Git"を含んだ記事が並ぶ (5274ms)

1 passing (8s)


Page Object化

さっそくPage Object Patternを採用しましょう。


test/page-object/qiita_search_page.js

export default class QiitaSearchPage {

constructor(browser) {
this.browser = browser;
this.browser.navigateTo('http://qiita.com/search');
if (this.browser.getPageTitle() !== '検索 - Qiita') {
throw new Error('Invalid page');
}
}

search(keyword) {
this.browser.setValue('#q', keyword);
this.browser.getElement('button[type=submit]').click();
}

getSearchResults () {
return this.browser.getElements('.searchResult h1');
}
}



test/test2.js

import injectBrowser from 'testium/mocha';

import assert from 'power-assert';
import QiitaSearchPage from './page-object/qiita_search_page.js';

describe('Qiita検索画面', function () {
before(injectBrowser());
let page;

beforeEach(function () {
page = new QiitaSearchPage(this.browser);
});

context('検索フォームに"title:Git"と入力して検索する', function () {
it('検索結果に、タイトルに"Git"を含んだ記事が並ぶ', function () {
page.search('title:Git');
page.getSearchResults().forEach(result => {
assert(/git/i.test(result.get('text')));
});
});
});
});



Testiumへの不満点

element指定するときXPathが使えないこと。

TestiumはCSS Selectorしか対応していないので、例えばtextで指定ができない。(よね?)


最後に

Seleniumを導入するなら、各言語にバインディングが揃っているので、得意な言語で書き始めれば良いと思う。

JavaScriptならTestiumを推すけど、他ライブラリはサンプルコードを見たくらい。

Testiumは同期的にテスト書けるというのが特徴だけど、じゃあ非同期で書くってどういうことなのかというと、yieldやasyncやwaitみたいなのをちょくちょく挟む事になる。

WebdriverIO

describe('my feature', function() {

it('should do something', function *() {

yield browser
.url('https://duckduckgo.com/');
.setValue('#search_form_input_homepage', 'WebdriverIO')
.click('#search_button_homepage');

var title = yield browser.getTitle();
console.log(title); // outputs: "Title is: WebdriverIO (Software) at DuckDuckGo"
});
});

情弱なのでテスト側で非同期を意識する必要がある場面を知らない。

明日の Selenium/Appium Advent Calendar 2015 はokitanさんです。