Webdriver.IO 起手式
by alincode

Java(5 years)
SDET
English
NodeJS
freelancer
freelancer / remote
full-time
alincode
5 years
8 months
7 months
8 months


框架介紹
快速開始測試專案
Getting Started
Live Demo
經驗分享
Learning Resources
Q and A
框架介紹
What
End to End
Testing Framework
WebdriverIO
!=
WebdriverJS
Protractor
NightwatchJS
WebdriverIO
Geb
Robot
NodeJS
底層架構
Web
Selenium restful API
Mobile
Appium (base on selenium)

Module is King
npm install wdio-junit-reporter --save-dev// wdio.conf.js
module.exports = {
    // ...
    reporters: ['dot', 'junit'],
    reporterOptions: {
        junit: {
            outputDir: './'
        }
    },
    // ...
};install module
setting config



BDD / TDD framework
Cloud service



Task Runner plugin


Reporter
Dot reporter
Spec reporter

JUnit reporter

Customer reporter

Teamcity reporter

sync and async
exports.config = {
    sync: true
};Async (Promises based)
Sync


Promises based
describe('getTitle', () => {
    it('should return the url of the current webpage', async function () {
        (await this.client.getUrl()).should.be.equal(conf.testPage.start)
    })
})client.url('http://webdriver.io')
      .getUrl().then(function(url) {
          console.log(url);
      });ES2015
Promise
WebdriverIO
- selenium restful api
 - anything is module
 - more familiar api
 - config setting tool
 
Protractor
- selenium-webdriver
 - good for angularJs project
 - but...
 
Protractor
<div class="ng-binding">Hi my name is {{name}}</div>
var greeting = element(by.binding('name'));無縫接軌 angular data bind
angularjs website
it('should have learn link.', function(done) {
    browser.get('http://www.angularjs.org');
    var myElement = element(by.css('.learn-link'))
    expect(myElement.getText()).to.eventually.equal(
      'Learn Angular in your browser for free!');
    done();
});no angularjs website
it('no angularjs website', function(done) {
    browser.driver.get('http://webdriver.io/');
    var myElement = browser.driver.findElement(by.css('h2'));
    expect(myElement.getText()).to.eventually.equal(
      'Selenium 2.0 bindings for NodeJS');
    done();
  });好像可以在 config 調整,but...
What we can do?
自動化測試
爬蟲
自動化截圖
快速開始測試專案
初始化專案
建立設定檔
測試可被執行
create project
mkdir webdriverio-sandbox
cd webdriverio-sandbox
npm init -yinstall package
npm i webdriverio -Dgenerate config tool
./node_modules/webdriverio/bin/wdio
多選,請按空白鍵
vi wdio.conf.js
capabilities: [{
  browserName: 'chrome'
}],
mochaOpts: {
  timeout: 60000
},init folder
mkdir -p ./test/specs/
mkdir -p ./errorShots/vi test/specs/test.js
var assert = require('assert');
describe('mokayo page', function() {
  it('should have the right title', function() {
    browser.url('http://blog.mokayo.com');
    var title = browser.getTitle();
    assert.equal(title, '教你所想學的,用眼樂讀 - blog.mokayo.com');
  });
});執行
./node_modules/webdriverio/bin/wdio wdio.conf.jsnpm run e2e-test
"scripts": {
  "e2e-test": "wdio wdio.conf.js"
}OR
Getting Started
Mode
- 
	
Standalone Mode
 - 
	
The WDIO Testrunner
 
Standalone Mode

The WDIO Testrunner

Config
exports.config = {
    specs: [
        'test/spec/**'
    ],
    capabilities: [{
        browserName: 'chrome'
    }, {
        maxInstances: 5,
        browserName: 'firefox',
        specs: [
            'test/ffOnly/*'
        ]
    },{
        browserName: 'phantomjs',
        exclude: [
            'test/spec/alert.js'
        ]
    }],
    sync: true,
    screenshotPath: 'shots',
    baseUrl: 'http://localhost:8080',
    waitforTimeout: 1000,  // Default timeout for all waitForXXX commands.
};Config
exports.config = {
    // WebdriverCSS: https://github.com/webdriverio/webdrivercss
    // WebdriverRTC: https://github.com/webdriverio/webdriverrtc
    // Browserevent: https://github.com/webdriverio/browserevent
    plugins: {
        webdrivercss: {
            screenshotRoot: 'my-shots',
            failedComparisonsRoot: 'diffs',
            misMatchTolerance: 0.05,
            screenWidth: [320,480,640,1024]
        },
        webdriverrtc: {},
        browserevent: {}
    },
    framework: 'mocha'
    reporters: ['dot', 'allure'],
    // Hooks
    onPrepare: function (config, capabilities) {
    }
  
};Group Test Specs
// wdio.conf.js
exports.config = {
    // define all tests
    specs: ['./test/specs/**/*.spec.js'],      
    // define specific suites
    suites: {
        login: [
            './test/specs/login.success.spec.js',
            './test/specs/login.failure.spec.js'
        ],
        otherFeature: []
    }
}wdio wdio.conf.js --suite loginwdio wdio.conf.js --suite login,otherFeatureBrowser Object
- 
	
webdriver instance
 - 
	
global object
 
selectors
browser.click('h2.subheading a');- CSS Query Selector (建議使用)
 
- Link Text
 - Partial Link Text
 - Element with certain text
 - Tag Name
 - Name Attribute
 - xPath (不建議使用)
 
Collection of elements
Single element
browser.element('h2');browser.elements('h2');API
- Action
 - Property
 - Protocol
 - State
 - Utility
 - Mobile (略)
 
Action
click
browser.click('#myButton');setValue
var input = browser.element('.input');
input.setValue('test123');
submitForm
browser.submitForm('#loginForm');Property
getTitle
browser.getTitle();getValue
browser.element('.input').getValue();submitForm
browser.submitForm('#loginForm');Protocol
element
browser.element('.h2');elements
browser.elements('li');url
browser.url('http://webdriver.io');State
isEnabled
browser.isEnabled(selector);isExisting
browser.isExisting(selector);isSelected
browser.isSelected(selector);
Utility
waitForExist
browser.element('.notification').waitForExist(5000);saveScreenshot
browser.saveScreenshot('front_page.png');end
client
    .init()
    .url('http://google.com')
    .end();
    // ends session and close browserUtility
pause
browser.pause(5000);debug
browser.addCommand();addCommand
browser.debug();Page Object
霰彈式修改
(Shotgun Surgery)
function Page() {}
Page.prototype.open = function(path) {
  browser.url('/' + path)
}
module.exports = new Page();// login.page.js
var Page = require('./page')
var LoginPage = Object.create(Page, {
    // define elements
    username: { get: function () { return browser.element('#username'); } },
    password: { get: function () { return browser.element('#password'); } },
    form:     { get: function () { return browser.element('#login'); } },
    flash:    { get: function () { return browser.element('#flash'); } },
    // define or overwrite page methods
    open: { value: function() {
        Page.open.call(this, 'login');
    } },
    submit: { value: function() {
        this.form.submitForm();
    } }
});
module.exports = LoginPage// login.spec.js
var expect = require('chai').expect;
var LoginPage = require('../pageobjects/login.page');
describe('login form', function () {
    it('登入失敗', function () {
        LoginPage.open();
        LoginPage.username.setValue('foo');
        LoginPage.password.setValue('bar');
        LoginPage.submit();
        expect(LoginPage.flash.getText()).to.contain('Your username is invalid!');
    });
    it('登入成功', function () {
        LoginPage.open();
        LoginPage.username.setValue('tomsmith');
        LoginPage.password.setValue('SuperSecretPassword!');
        LoginPage.submit();
        expect(LoginPage.flash.getText()).to.contain('login success');
    });
});
Live Demo
- 
	
first test
 - 
	
site map
 
- 
	
auth
 - 
	
add page test case
 
經驗分享
by google testing blog
too slow
not reliable
duplicate
測試範圍如何切割

如何開始寫前端測試
測試計畫
測試規格書
撰寫測試程式
測試計畫
# 正常登入流程
使用者可從首頁點擊登入轉至登入頁,並可輸入帳號密碼,密碼驗證過後,頁面顯示登入成功。
# 正常登入流程
使用者輸入帳號密碼驗證後,發現密碼輸入錯誤,停留在登入頁,顯示登入錯誤原因。
# 正常登出流程
使用者可點擊登出按鈕,畢竟狀態真正為登出。
# 檢查所有從首頁,可正常連連結至分支頁
登入頁、分類頁、個人資訊頁、聯繫客服頁
# etc...測試規格書

不要用 xPath

好讀
易維護
/html/body/section/div/section[2]/article/a[1]$('.icon-search')XPATH
CSS Query Selector
Learning Resources
getter channel

github issue

mokayo

good for java developer

開放Q and A 時間
Trunk-studio 分享會 - Webdriver.IO 起手式
By alincode
Trunk-studio 分享會 - Webdriver.IO 起手式
(16/07/20)
- 3,695