SauceLabs selenium testing with selenium-webdriver

selenium 是用來做瀏覽器測試的工具,讓你可以安排一個流程在真實瀏覽器上運行來測試結果是否如預期,已經被大量用在 Web 的測試上,這已經許多年,也有許多教學了。

而在 selenium 的測試上,最方便的是能跨瀏覽器測試,但是最麻煩的是你要安排有很多瀏覽器的機器(或虛擬機器),並把環境部屬好,供 selenuim 運行。

而 saucelab 是一個雲端的測試平台,就是用來解決這個問題,他提供了隨時供你取用的運算資源,讓你隨時可以模擬各種平台不同版本的作業系統與瀏覽器,他是一個付費的服務,但是有免費試用的額度可以玩玩看。

這篇文章紀錄從頭到尾透過 nodejs 在本機建立建立一個 selenuim 的測試環境,最後在透過 saucelab 來測試其他作業系統與瀏覽器。
Continue reading…

[js step] 都是物件

JavaScript 的變數都有物件的型態跟特性,什麼型態都可以當成物件來用。物件是指?可以擁有資料跟方法的變數。

例如這個 obj 物件。

var obj = {};
obj.data = 1;
obj.method = function() { console.log("data = " + this.data); }
obj.method();
//print 1

而其他也是物件的型態有

陣列

var arr = [1, 2, 3];
arr.data = 1;
arr.method = function() { console.log("data = " + this.data); }
arr.method();
//data = 1
console.log(arr);
//[1, 2, 3]
console.log(arr[0]);
//1
console.log((null, arr));
//[1, 2, 3, data: 1, method: function]
 1

函式

var fn = function() { return "hello"; };
fn.data = 1;
fn.method = function() { console.log("data = " + this.data); }
fn.method();
//data = 1
console.log(fn);
//function () { console.log("hello"); }
console.log(fn());
//hello

陣列跟函式都有他原本的功能,但是也帶有物件的特性。就連原生型態數字、布林、字串也都有物件的版本,可以用物件的方式處理。

var n = new Number(100);
n.data = 1;
n.method = function() { console.log("data = " + this.data); }
n.method();
//data = 1
console.log(n);
//Number {data: 1, method: function}
console.log(n+1);
//101

如果沒看到建構 n 的方法,會不會把 n 認作一個物件勒~所以有一些函式可以用來判別變數的型態

n instanceof Number
//true
typeof n
// object
type of 1
// number
n.valueOf();
//100
n.toString();
//"100"

所以複寫 valueOf 跟 toString 可以讓一般物件運作起來像是數字或字串,js 會在執行運算時轉型來決定呼叫哪個函式。

var what = {valueOf: function() { return 100;}};
console.log(what+50);
//150

what = {toString: function() { return "I am what"; }}
console.log("Who are you. "+ what); 
//Who are you. I am whatwha

JavaScript 設計模式

Build Better Applications with Coding and Design Patterns

上個禮拜參加完 JSDC 2013 以後,我就壞掉啦,本來已經很久沒有讀程式寫程式,這裡拜突然就很熱血得衝去天瓏買了 JavaScript 設計模式跟 JavaScript 網頁應用程式設計。奇怪的是歐萊禮這本書是 Pattern 怎麼會是設計模式,那叫 Learning JavaScript Design Patterns 面子往哪襬阿!根本就是卡位…以後讀者在書局看到 同個出版社有 JavaScript 設計模式 跟 學習 JavaScript 設計模式 時情何以堪阿。。

算了…紀錄一下心得好了,由於之前都在網路上斷斷續續的學習 JavaScript 關於 prototype 繼承的資料,一直學得不是很扎實,所以之前都想寫文章來紀錄自己瞭解的程度,沒想到每次都寫的二二六六,證明自己根本沒搞懂,所以也沒什麼本事表達清楚了。

但看完這本書,突然有種任督二脈打通的感覺阿,把 Object、Prototype、__proto__,物件繼承的關係跟模擬 class 的方法,講得清清楚楚,這也佔了本書幾乎一半的篇幅,這本書最重要的其實就是這個部份啦~後面的設計模式根本只是來貼咖的~只是看完了以後有種憂傷,之前花好多時間亂學的,現在都在書上啦。。變成好像很沒價值的知識了~所以還是要把英文學好點,才能多看一點還沒翻完的…

還有各種產生物件的方法跟差異,也是詳細又清楚,之前本來覺得自己加減知道怎麼模擬 class 就還不錯了,他裡面更是解釋各種方法的優點跟缺點,一項項條列出來,又比較不同方法的差異,跟最好最通用的方法。

阿,好像是我太弱了,所以感覺學到新東西都令我開心,所以還蠻喜歡這本書的。。期待 JavaScript 網頁應用程式設計能帶給我更多新知阿。。

 

node.js child_process send function

最近在用 node.js 寫一些系統管理層面的程式,有些複雜的工作需要 fork process 來做,主要的 process 用來跑 Web 跟處理主要流程,所以不打算做太多額外的工作。

var child = require('child_process').fork('./child.js');

在這裡實作的過程中想到一些設計,第一個部份是我的 child 應該設計成一個適合 require 的子模組,由他自己提供輔助函式,也由該模組 fork 自己。

var child = require('./child.js');
child.start();
child.stop();
var process;
exports.start = function() {
  var cp = require('child_process');
  process = cp.fork('./child.js');
  child.send('message', {cmd: 'start'});
}
exports.stop = function() {
  if(process)
    process.kill();
}
process.on('message', function(msg) {
  if(msg.cmd == 'start') {
     // child process start
     // do something
  }
});

由於 fork 出去的 child process 是一個子模組,所以對 parent 來說還是有一些事情想要呼叫 child 來做。依照習慣要寫一些匿名函式當參數,意思就是這個函式希望是在 child process 去跑,而不是單純用來當回呼函式使用,結果實際到這邊發現有些事情跟想像的不太一樣,process.send 當參數如果傳函式到 child process 竟然會接不到~。

仔細想想好像也不完全無道理,由於要 IPC,而 json 對函式的轉換好像本來就不太支援。

範例繼續延續上面的,這範例 msg 將收不到傳過去的函式。

..
child.helper(function(res) {
  // ...
});
..
var process;
exports.start = function() {
  var cp = require(''child_process);
  process = cp.fork('./child.js');
  child.send('message', {cmd: 'start'})
}
exports.stop = function() {
  if(process)
    process.kill();
}
exports.helper = function(handler) {
  process.send({cmd: 'helper', handler: handler});
});
process.on('message', function(msg) {
  if(msg.cmd == 'start') {
     // child process start
     // do something
  }
  else if(msg.cmd == 'helper'){
     console.log(msg);
     // { msg: 'helper' }
  }
});

這裡就讓我想到曾經看過一篇文章…撰寫乾淨的 eval 程式碼的技巧,因此就依樣畫葫蘆…就能動了!

只是要注意透過這種方式傳過去的函式所能存取到的變數已經不是表面上看到的了。而是透過 eval 執行時的 child process 的 context 了。

exports.helper = function(handler) {
  process.send({cmd: 'helper', handler: handler.toString()});
});
process.on('message', function(msg) {
  if(msg.handler) {
    eval('var handler = ' + msg.handler);
  }
  if(msg.cmd == 'start') {
     // child process start
     // do something
  }
  else if(msg.cmd == 'helper' && handler){
     handler([1, 2, 3]);
  }
});

node.js web 開發環境紀錄

webframework : express
npm install express

view engine : ejs
npm install ejs

dev-tool : nodemon  監控檔案變化自動重啟伺服器
npm install nodemon -g

css framework : bootstrap

db : node-sqlite3 :memory:
npm install sqlite3

yaml : js-yaml
npm install js-yaml

db-tool : adminer

flow control : async , step 一開始用 step ,後來看到 async 發現 api 設計的好一點~語意比較清楚

從挑選 package 的過程中真的可以觀察到好的 api 設計。