[笔记] 用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

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