tedshd's DevNote

Develop & Design Note by Ted

webdriver.io - 前端測試入門筆記...

webdriver.io - 前端測試入門筆記...

前端測試工具很多種

我這裡的需求是要做自動化測試

不知為何就選了這套 webdriver.io

可能就只是單純名字很炫(誤

當然一開始要先要有 Selenium

但為何 Selenium 跟我以前的印象有差別了...

我發現它的 firefox add-on 不能把錄製的動作輸出成 code 了, 是我的錯覺嗎?還是改方式了

但我想說就算了, 直接用寫的也罷

webdriver.io 只是因為是在我看過的關於測試文章中最後有印象的東西所以就去找它了(這是事實...

也還好我的記憶沒錯, 看了介紹和文件覺得 webdriver.io 有符合我的需求且又是用 Node.js 來寫, 所以對我較友善

先記錄一下使用流程

Base tool

  • Java
sudo apt-get update

java -version

sudo apt-get install default-jre

sudo apt-get install default-jdk
  • Node.js

Install

On Local

Get Started

突然發現文件寫得很詳細了...

雖然在做設定那有些選項不同但也影響不大

但想玩進階的方式可參考以下文章

設定 Selenium 參數可參考

基本上以下是我建的順序

1 先建 package.json
{
  "name": "webdriver",
  "description": "automation test",
  "devDependencies": {
  }
}
2 下載 Selenium server

之後有新版請再去確認版本

curl -O http://selenium-release.storage.googleapis.com/2.53/selenium-server-standalone-2.53.0.jar
3 裝 webdriver
npm install webdriverio --save-dev
4 安裝各個 OS 對應的 webdriver

selenium-webdriver

可以不必裝 selenium-webdriver

只要去下載各個 OS 對應要用的 browser 的 webdriver 放在專案資料夾就好了

5 這樣就好了
6 啟動 Selenium server 並開始寫一個簡單的自動化測試的 test case
java -jar selenium-server-standalone-2.53.0.jar

test.js

var webdriverio = require('webdriverio');
var options = {
    desiredCapabilities: {
        browserName: 'firefox'
    }
};
 
webdriverio
    .remote(options)
    .init()
    .url('http://www.google.com')
    .getTitle().then(function(title) {
        console.log('Title was: ' + title);
    })
    .end();
node test.js
// output Title was: Google

這時你就會發現你的 firefox 被打開連到 Google 後就自動關掉

然後 terminal 就會 output Title was: Google

關於測試的的 script 攥寫請參考 API 文件

WebdriverIO - API Docs

我預設使用 mocha

有用 chai 加強攥寫 script

進階應用

基本上 webdriver 分兩種測試方式

  1. Standalone Mode

  2. The WDIO Testrunner

各有優缺點, 就看習慣用哪種方式來跑測試

我較喜歡用 The WDIO 的方式, 因為他是把設定檔抽出來, 較好管理且可用 hook 做其他事情

依我所做的較特別的設定就是把 test case 切很細(因為測試的 scope 需求), 這就需要設定能跑個別的測試

就需要在 config 設定 suites

就可以這樣下 command

./node_modules/.bin/wdio wdio.conf.js --suite test_a
// or
./node_modules/.bin/wdio wdio.conf.js --suite test_b

可參考以下文件

WebdriverIO - Configuration

WebdriverIO - Test Runner

一般都會要把測試結果 output 出來, webdriver 提供自訂 reporter 的功能

就看個人喜好選擇

WebdriverIO - Dot Reporter

但我這需求簡單且需要讓其他人可在測試當下就輕易看到結果, 所以就在 config 設定 hook

讓測試跑完時儲存測試結果並有個頁面讓別人看

config 的 hook

afterTest: function (test) {
    console.log('HOOK - afterTest:', test);
},

test 就是測試結果

hook 也有很多狀態可用

廢棄方法(因為一直試驗失敗...

On remote Server

基本上用 webdriver 做測試是需要有 browser 和 UI

所以需裝 xwindow 或 Xvfb

firefox
sudo apt search firefox

sudo apt-get install firefox firefox-locale-en

如果顯示

Gtk-WARNING **: Locale not supported by C library.
    Using the fallback 'C' locale.

請設定 locale

我是設定 en_US

export LC_ALL=en_US.UTF-8
xvfb
sudo apt-get install xvfb
shell 然後啟動與指派到哪個 port
sudo Xvfb :10 -ac

指定輸出的 DISPLAY

export DISPLAY=:10
firefox

之後再啟動測試

這裡就遇到問題了

出現錯誤訊息...

Error: no display specified

但奇怪的是明明都 export DISPLAY 了還出這 error...

目前都還沒解決這問題...

所以直接採用下面的兩個備案

  1. 裝一台有 GUI 的 Linux 到實體機器上, 非 VM

  2. 使用 SAUCE LABS

個人是建議公司肯出錢就採用 SAUCE LABS 的服務, 隨然有點小貴, 因為涵蓋的 OS 和 browser 很多, 且有 mobile web 的測試(雖然 android 都只有到 4.X 而已

下面說明一下如何設定 SAUCE LABS 與 SAUCE LABS 是如何運作的

SAUCE LABS

SAUCE LABS 提供多個 OS 與 browser 版本的 VM 以供測試且有 native app 的測試

有 14 天的免費試用, 且有 opensource 的 free 方案

在 price 方面須注意的是 Manual 的方案是不含自動化測試的

他有提供 API 去處理測試結果與資訊, 但因為我不會用到所以就沒細看有哪些功能

基本上使用 SAUCE LABS 的流程如下

基本上就是連上 SAUCE LABS 的 host 用 SAUCE LABS 的 VM 測試

下面會說一下設定方式

跟跑 webdriver 一樣設定可分兩種去 run

  1. Standalone Mode

  2. The WDIO Testrunner

1 可參考官方文件

Node.js Test Setup Example - The Sauce Labs Cookbook - Sauce Labs Documentation Wiki

我是採用 2

所以需追加的設定是

capabilities: [{
    'browserName': 'chrome',
    'platform': 'Windows 10',
    'username': <username>,
    'accessKey': <accessKey>
}],

host: <username> + ':' + <accessKey> + '@ondemand.saucelabs.com',
port: 80,
path: '/wd/hub',

<username><accessKey> 都可以經由 SAUCE LABS 後台取得

這樣就可以使用 SAUCE LABS 來跑測試程式了

Note

當你一段時間沒跑, 之後又再跑時有錯

有可能向我遇到JAVA 更新

那這時 Selenium Standalone Server 就要更新 Link

browser driver 也要更新

2016 JSDC 淺談網站自動化測試

Let's Encrypt - Has a certificate problem in Android Chrome

Let's Encrypt - Has a certificate problem in Android Chrome

If you use Let's Encrypt as SSL certificate

Then setting this in Nginx

ssl_certificate /etc/letsencrypt/live/<domain>/cert.pem;

You can find it maybe has problem in Android Chrome

Now you can modify this

ssl_certificate /etc/letsencrypt/live/<domain>/fullchain.pem;

Test your SSL

SSL Server Test

Refer - Let’s encrypt certificate not working for Andriod’s Google Chrome

JavaScript - Why i from RequireJS to webpack

Why i from RequireJS to webpack

RequireJS is a Asynchronous Module Definition(AMD) lib

Its powerful to handle modulize on your page and you can handle all loader on JavaScript, you can focus on JavaScript function and web page.

But if your module is become complex and more module, you can find JavaScript request become more and more.

You can find it is a serious performance problem.

Your network has lot of request of js.

I want to less or one js request on a page

So i choice webpack this tool.

It's powerfull tool handle module bundle.

This is what i want change.

Before

After

If want to use a lib for global like jQuery

Must use npm install & use ProvidePlugin in webpack.config.js

...
plugins: [
    new webpack.ProvidePlugin({
        $: "jquery",
        jQuery: "jquery",
        "window.jQuery": "jquery"
    }),
],
...

How it run

You can use

webpack
# if you want watch change
webpack --watch

more in https://webpack.github.io/docs/cli.html

Use case

If you want bundle all file in directory

var fs = require('fs'),
    entries = fs.readdirSync('./mobile/js/').filter(function(file) {
        return file.match(/.*\.js$/);
    });

entries is a Array show all file.

My webpack

JavaScript - 動作行為抽象化實例

JavaScript - 動作行為抽象化實例

其實標題真的不知道要怎麼定

因為只是要說明一個實例, 但又不想扯到其他太制式的東西(設計模式), 但這範例又可用於其他地方, 所以到最後就用了個似是而非的標題了...

先說一下可能的使用情境

當你在做一個動作時要做一件事 ex: 呼叫 API、紀錄 GA、狀態改變之類的事情

sample code

document.querySelector('a').addEventListener('click', function () {
    // GA or call API or do somethong

});

以紀錄 GA 為例

但是如果是紀錄 GA 點擊事件就會有許多區域要記錄點擊來瞭解使用者點哪個區域較多, 就要在不同區域綁定不同的 GA 但日子一久或程式變大的情況要找哪有綁 GA 就很不好找, 所以這時就需要有個 interface 來統整這事情

document.querySelector('#item').addEventListener('click', function () {
    // GA or call API or do somethong

    interfaceGa(this);
});

document.querySelector('#banner').addEventListener('click', function () {
    // GA or call API or do somethong

    interfaceGa(this);
});

function interfaceGa(argument) {
    var name = argument.getAttribute('data-ga');
    switch(name) {
        case 'product-items':
            ga('send', 'event', 'items', 'click', argument.getAttribute('data-name'));
            break;
        case 'product-banner':
            ga('send', 'event', 'banner', 'click', argument.getAttribute('data-name'));
            break;
    }
}

這樣就很好管理 GA 事件且在頁面上的 DOM 也可以快速知道該 component 是負責什麼 GA 事件, 因為可以快速查到

在其他用法上 interface 重要的是有個能判別的點, 然後再用 switch 去選擇該做的事, 只是該例子是把 switch 要判斷的東西擺在 DOM 的 data attribute

還可加個有趣的用法

function interfaceGa(argument) {
    var name = argument.getAttribute('data-ga'),
        status;
    switch(name) {
        case 'product-items':
            status = true;
            if (status) {
                ga('send', 'event', 'items', 'click', argument.getAttribute('data-name'));
            }
            break;
        case 'product-banner':
            status = true;
            if (status) {
                ga('send', 'event', 'banner', 'click', argument.getAttribute('data-name'));
            }
            break;
    }
}

當你要管理的事情如果臨時要開開關關或是依需求需要開關, 這也會方便管理

所以以上要說的就是在程式變複雜時可以適當地把許多定義出有要做的事情做一層 interface 管理

這似乎是某個設計模式, 但我也臨時找不出這是叫啥設計模式...