[筆記] 用Chrome Extension代替Selenium作網頁自動化測試

Selenium自動化測試有諸多不穩定因素,使用起來需要看大量API文檔,下載對應語言的驅動包裹。遂想直接用Chrome Extension取而代之。

如何用Chrome Extension驅動網頁UI測試呢?首先我們從第一個Extension說起。

一個Extension我們放在一個文件夾裏,第一個Extension有三個文件:icon.png, background.js, manifest.json

從網上有很多這樣的代碼,就是當特定瀏覽網頁時,在地址欄右側顯示出extension的圖標icon.png。

// background.js
function match(url){
  var host = "null";
  if(typeof url == "undefined" || null == url)
  url = window.location.href;
  var regex = /.*\:\/\/([^\/]*).*/;
  var match = url.match(regex);
  if(typeof match != "undefined" && null != match)
  host = match[1];
  return host;
}

function entry(tabId, changeInfo, tab) {
  // 在URL是localhost時顯示extension圖標
  if(match(tab.url).toLowerCase()=="localhost"){
    chrome.pageAction.show(tabId);
  }
};

chrome.tabs.onUpdated.addListener(entry);


// manifest.json
{
     "manifest_version": 2,
     "name": "Chrome Extension: Test",
     "version": "0.0.1",
     "background": { "scripts": ["background.js"] },
     "permissions": ["tabs"],
     "page_action": {
          "default_icon": {
               "19": "icon.png"
          },
          "default_title": "test extension"
     }
}
接着打開Chrome,在地址欄輸入chrome://extensions/,勾選Extension標題右側“開發者模式”(developer mode)就可以看見按鈕去選文件夾添加自己的extension了。

載入extension後,在新tab中輸入測試頁面,如http://localhost/index.html,那麼地址欄的右側便會出現icon.png的圖標。

那個圖標暫時就當個裝飾,標明我們想要測試的頁面被handle到。


下面來說一說怎麼得到當前訪問的頁面的信息。這就要用到extension的content script特性了。在extension開發文件夾裏增加一個js文件content.js:

// content.js
var links = document.getElementsByTagName('a');
var list = [];
var n,i,t;
n = links.length;
for(i=0;i<n;i++) {
  t = links[i].href;
  if (!t) continue;
  if (t.toLowerCase().indexOf('javascript:') >= 0) continue;
  list.push(t);
  t = null;
}
console.log(list);

然後在manifest.json裏添加content script的設置:

// manifest.json

... ...
     "background": { "scripts": ["background.js"] },
     // 添加content script的支持
     "content_scripts":[
        {"matches":["http://localhost/*"],"js":["content.js"]}                  
     ],
     "permissions": ["tabs"],
... ...
把自己的extension在chrome://extensions/裏重新加載(Reload)一下,再刷新一下測試頁面;這時進入控制檯,如果頁面裏有超鏈接,那麼控制檯會把它們鏈接到的地址全部打印出來。當然,控制檯輸出結果是一種形式,輸出到文件也可以,我們可以把最開始那個圖標用起來,點擊它看結果。

實現點擊圖標看結果需要知道background和content script如何通信。我們先談一談如何將content script裏得到的list讓background得到,並在圖標點擊後顯示出來。

content script中想把list交給background,需要通過消息機制實現通信。修改content.js和background.js:

// content.js
... ...
console.log(list);

chrome.runtime.sendMessage({
  type: 'localtest-links',
  links: list
});


// background.js
... ...
chrome.tabs.onUpdated.addListener(entry);

var pageData = {};
chrome.runtime.onMessage.addListener(function(message, sender, response){
  if (message.type !== 'localtest-links') return;
  pageData.links = message.links;
});
點擊圖標顯示內容其實就是配置一個popup的頁面,需要添加兩個文件:popup.html和popup.js,並修改manifest.json。

<!-- popup.html -->
<html>
<body>
  <div id="result">(No Result)</div>
  <script type="text/javascript" src="popup.js"></script>
</body>
</html>
// popup.js
document.addEventListener('DOMContentLoaded', function () {
  var data = chrome.extension.getBackgroundPage().pageData;
  var dom = document.getElementById('result');
  var html = '';
  var n, i;
  n = data.links.length;
  for(i=0;i<n;i++) {
    html += '<div>' + data.links[i] + '</div>';
  }
  dom.innerHTML = html;
  html = null;
  dom = null;
  data = null;
});

// manifest.json
... ...
          "default_title": "test extension",
          "default_popup": "popup.html"
     }
... ...
這樣訪問localhost的頁面時,所有超鏈接信息都會被收集到,並在點擊extension圖標後顯示在彈出的小窗口中。

上面整套流程基本就可以運行一些簡單的測試了,測試人員可以使用腳本打開chrome,然後讓extension自動執行測試,最後extension圖標可以讓測試人員看到測試結果。

下面就讓我們想一想用extension測試時,把控制面板放入popup.html中;這裏我們添加一個按鈕,點擊這個按鈕後,會觸發被測試頁面中的第一個button的click單擊事件。

先腦補一下事件的觸發:

function trigger(element, eventType) {
  var event = document.createEvent('HTMLEvents');
  event.initEvent(eventType, true, true);
  element.dispatchEvent(event);
  event = null;
}
一個控制按鈕要加到popup.html中,接着就是處理從popup中發送信息告知content script我要觸發button的click事件:

<!-- popup.html -->
... ...
<div id="result">(None)</div>
<button id="fire">Fire</button>
<script src="popup.js"></script>
... ...
// popup.js
... ...
  dom.innerHTML = html;

  dom = document.getElementById('fire');
  dom.addEventListener('click', function () {
    chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
      chrome.tabs.sendMessage(
        tabs[0].id,
        {type: 'localtest-fire'},
        function(response) {});
    });
  });
  html = null;
... ...

// content.js
... ...

chrome.extension.onMessage.addListener(function(message, sender, response) {
  if(message.type!=='localtest-fire') return;
  var buttons = document.getElementsByTagName('button');
  if(buttons.length > 0) {
    // trigger就是剛纔腦補的那部分 :P
    trigger(buttons[0], 'click');
  }
  buttons = null;
});
爲了實驗效果,我們可以在本地服務器上放一個test.html文件:

<html>
<body>
<a href="http://www.baidu.com"">Hello</a><br/>
<a href="javascript:alert('hi');">World</a><br/>
<a href="test.html">self</a><br/>
<button οnclick="javascript:alert('trigger')">From Popup</button>
</body>
</html>
重新加載extension後,當我們訪問http://localhost/test.html時,點擊地址欄右邊extension的圖標,點擊Fire按鈕,這樣就會有alert彈出,上面寫着"trigger"!

但是,自動測試的時候出現alert,測試就暫停了,這個是令人抓狂的,我們得屏蔽掉alert。下面就說一說content script向當前頁面注入代碼,目標是幹掉alert。

我們知道window.alert就是alert,執行它會彈出一個消息框。只要能重載這個函數,讓它把消息輸出到console上就好了。需要修改content.js:

// content.js
... ...
var script = document.createElement('script');
script.type = 'text/javascript';
// 將alert替換,直接將msg輸出到console
script.textContent = 'window.nativeAlert=window.alert;window.alert=function(msg){console.log(msg);};';
// 將代碼注入到當前頁面中
(document.head || document.documentElement).appendChild(script);
// 可以讓代碼運行完後再把script從頁面移除,不過這個就不很重要了
script = null;
重載extension,訪問test.html時,直接單擊“From Popup”按鈕就可以發現消息已經輸出到console了,點擊popup裏的“fire”按鈕效果同樣。

當然,還可以用這種注入的方式把測試腳本加載上運行,然後返回執行結果,這樣就可以做成不錯的網頁UI自動化測試工具了。

對於HTTPS,有時候我們會遇到彈出輸入驗證對話框,那我們就可以啓用extension的webRequest功能,在Header中加入Authentication的信息就可以避開這個對話框的出現。

好了,現在網頁UI自動化測試基本可以跑自己的extension了,寫寫代碼還能把結果輸出成文本,夠用了~就不用對着selium各種神傷了。


J.Y.Liu

2014.09.15

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章