- Gherkin syntaxを使いたい
- AWS Lambdaで使いたい
- 知ってる言語ベースだと更に助かる
上記の理由から、nodeで動くcucumber-jsを使ってみました。
参考にした記事
http://qiita.com/p-baleine@github/items/5e6cd1ed12e31bf7edc2
https://github.com/cucumber/cucumber-js/blob/master/docs/nodejs_example.md
##ライブラリインストール
$ npm install -S express multiline
$ npm install --save-dev cucumber@latest selenium-webdriver@3.0.1 chromedriver@2.25.1
とりあえずこんな感じに。
{
"name": "cucumnerjs-example",
"version": "1.0.0",
"description": "example",
"main": "index.js",
"scripts": {
"test": "./node_modules/.bin/cucumber.js",
"start": "node index.js"
},
"author": "hideokamoto",
"license": "MIT",
"dependencies": {
"express": "^4.14.0",
"multiline": "^1.0.2"
},
"devDependencies": {
"chromedriver": "^2.25.1",
"cucumber": "^2.0.0-rc.6",
"selenium-webdriver": "^3.0.1"
}
}
##テスト用アプリの作成
テストするにはテスト対象を作らないとです。
ということで参考記事よろしくnodeで動くwebページを1つ用意します。
const express = require('express')
const multiline = require('multiline')
const app = express()
app.get('/', (req, res) => {
res.send(multiline( () => {/*
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<p>Cucumber-js example</p>
</body>
</html>
*/}))
})
module.exports = app
const app = require('./src/index')
app.listen(3000, () => {
console.log('port 3000')
})
アプリはnpm start
で起動します。
$ npm start
> cucumnerjs-example@1.0.0 start /develop/node/cucumberjs
> node index.js
port 3000
テスト時に使うので、そのままにしておきましょう。
##cucumberjsでのテスト準備
cucumberjs自体はfeature
ディレクトリさえあれば実行可能です。
$ mkdir features
$ npm test
> cucumnerjs-example@1.0.0 test /develop/node/cucumberjs
> cucumber.js
0 scenarios
0 steps
0m00.000s
もっとも、テストファイルが存在しないのでただ実行しただけですが。
###Gherkinでテストを書く
とりあえずテストを書いておきましょう。
Feature: Example feature
As a user of Cucumber.js
I want to have example application
So that I can concentrate on building awesome applications
Scenario: I am on the TopPage
Given I am on the TopPage
Then I should see "Cucumber-js example"
Feature
の下3行はテスト概要などです。
Scenario
以下が実際に実行するテスト内容となります。
今回は
- Given I am on the TopPage
- Then I should see "Cucumber-js example"
の2つをテストするということですね。
この状態でテストを実行すると、以下のように「対応するコードがない」というエラーが出てきます。
Feature: Example feature
As a user of Cucumber.js
I want to have documentation on Cucumber
So that I can concentrate on building awesome applications
Scenario: I am on the TopPage
? Given I am on the TopPage
? Then I should see "Cucumber-js example"
Warnings:
1) Scenario: I am on the TopPage - features/documentation.feature:6
Step: Given I am on the TopPage - features/documentation.feature:7
Message:
Undefined. Implement with the following snippet:
Given('I am on the TopPage', function (callback) {
// Write code here that turns the phrase above into concrete actions
callback(null, 'pending');
});
2) Scenario: I am on the TopPage - features/documentation.feature:6
Step: Then I should see "Cucumber-js example" - features/documentation.feature:8
Message:
Undefined. Implement with the following snippet:
Then('I should see {arg1:stringInDoubleQuotes}', function (arg1, callback) {
// Write code here that turns the phrase above into concrete actions
callback(null, 'pending');
});
1 scenario (1 undefined)
2 steps (2 undefined)
0m00.000s
npm ERR! Test failed. See above for more details.
「こういう風にコード書いてくれ」という指示も出してくれるので、このあたりを参考にコードを書いておきましょう。
###ドライバーの設定
先にテストを実行するためのwebドライバを設定します。
require('chromedriver')
var seleniumWebdriver = require('selenium-webdriver');
var {defineSupportCode} = require('cucumber');
function CustomWorld() {
this.driver = new seleniumWebdriver.Builder()
.forBrowser('chrome')
.build();
}
defineSupportCode(function({setWorldConstructor}) {
setWorldConstructor(CustomWorld)
})
###step_definitionsの設定
続いてGherkinに対応するstep_definitionsを記述します。
var seleniumWebdriver = require('selenium-webdriver');
var {defineSupportCode} = require('cucumber');
defineSupportCode(function({Given, Then}) {
Given('I am on the TopPage', function () {
return this.driver.get('http://localhost:3000');
});
Then('I should see {stringInDoubleQuotes}', function (text) {
const xpath = "//*[contains(text(),'" + text + "')]"
const condition = seleniumWebdriver.until.elementLocated({xpath: xpath})
return this.driver.wait(condition, 10000)
});
});
###hookの設定
features/support/hooks.jsへ、scenarioの前後に実行したいコードを書くことができます。
var {defineSupportCode} = require('cucumber');
defineSupportCode(function({After}) {
After(function() {
return this.driver.quit();
});
});
##テストを実行
お待たせしました。いよいよテスト実行の瞬間です。
事前にnpm start
でlocalhost:3000
にアクセスできることを確認しておきましょう。
$ npm test
> cucumnerjs-example@1.0.0 test /develop/node/cucumberjs
> cucumber.js
Feature: Example feature
As a user of Cucumber.js
I want to have documentation on Cucumber
So that I can concentrate on building awesome applications
Scenario: I am on the TopPage
✔ Given I am on the TopPage
✔ Then I should see "Cucumber-js example"
1 scenario (1 passed)
2 steps (2 passed)
0m01.406s
成功しました。
###テストを失敗させる
せっかくなので、テスト失敗のケースも見ます。
src/index.js
内のコンテンツを書き換えて、npm start
を再実行します。
const express = require('express')
const multiline = require('multiline')
const app = express()
app.get('/', (req, res) => {
res.send(multiline( () => {/*
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<p>Fail test pattern</p>
</body>
</html>
*/}))
})
module.exports = app
テストを実行してみましょう。
$ npm test
> cucumnerjs-example@1.0.0 test /develop/node/cucumberjs
> cucumber.js
Feature: Example feature
As a user of Cucumber.js
I want to have documentation on Cucumber
So that I can concentrate on building awesome applications
Scenario: I am on the TopPage
✔ Given I am on the TopPage
✖ Then I should see "Cucumber-js example"
Failures:
1) Scenario: I am on the TopPage - features/example.feature:6
Step: Then I should see "Cucumber-js example" - features/example.feature:8
Step Definition: features/step_definitions/browser_steps.js:8
Message:
Error: function timed out after 5000 milliseconds
at Timeout.<anonymous> (/develop/node/cucumberjs/node_modules/cucumber/lib/user_code_runner.js:91:22)
at ontimeout (timers.js:365:14)
at tryOnTimeout (timers.js:237:5)
at Timer.listOnTimeout (timers.js:207:5)
1 scenario (1 failed)
2 steps (1 failed, 1 passed)
0m06.392s
npm ERR! Test failed. See above for more details.
失敗しました。
##使ってみて
step_definitionsを自前で書かないといけないのがちょっとツラいなという感じがあります。
BehatであればMinkExtensionを入れるだけでそこそこ使える感じになっていたという印象がありますので。
・・・なんてことを脳内でボヤいていたら、ありました。
https://www.npmjs.com/package/cucumber-mink
次回はこれを使ってみようと思います。