Answers:
是的,现有框架非常有用。
最近,我将所有测试放在一个“测试”页面上,该页面已嵌入到应用程序中,但除非进行物理键入,否则无法访问。
例如,我会将所有测试放在一个页面下 chrome-extension://asdasdasdasdad/unittests.html
这些测试可以访问localStorage
等。为了访问内容脚本,从理论上讲,您可以通过测试页面中的嵌入式IFRAME进行测试,但是这些是更多的集成级别测试,单元测试需要您从实际页面中抽象出来,以便您不要依赖它们,同样可以访问localStorage。
如果您想直接测试页面,则可以编排扩展名以打开新标签页(chrome.tab.create({“ url”:“ someurl”})。对于每个新标签页,您的内容脚本都应运行,并且您可以使用您的测试框架,以检查您的代码是否已完成应做的工作。
在几个Chrome扩展工作,我想出了sinon-chrome
项目,允许使用运行单元测试mocha
,nodejs
和phantomjs
。
基本上,它将创建所有chrome.*
API的sinon模拟,您可以在其中放置任何预定义的json响应。
接下来,您使用节点的vm.runInNewContext
后台页面和phantomjs
渲染弹出/选项页面加载脚本。
最后,您断言使用所需参数调用了chrome api。
让我们举个例子:
假设我们有一个简单的chrome扩展名,该扩展名显示了按钮标记中打开的选项卡的数量。
背景页面:
chrome.tabs.query({}, function(tabs) {
chrome.browserAction.setBadgeText({text: String(tabs.length)});
});
要测试它,我们需要:
chrome.tabs.query
返回预定义的响应,例如两个选项卡。chrome.*
api注入某些环境该代码段如下:
const vm = require('vm');
const fs = require('fs');
const chrome = require('sinon-chrome');
// 1. mock `chrome.tabs.query` to return predefined response
chrome.tabs.query.yields([
{id: 1, title: 'Tab 1'},
{id: 2, title: 'Tab 2'}
]);
// 2. inject our mocked chrome.* api into some environment
const context = {
chrome: chrome
};
// 3. run our extension code in this environment
const code = fs.readFileSync('src/background.js');
vm.runInNewContext(code, context);
// 4. assert that button badge equals to '2'
sinon.assert.calledOnce(chrome.browserAction.setBadgeText);
sinon.assert.calledWithMatch(chrome.browserAction.setBadgeText, {
text: "2"
});
现在,我们可以将其包装到mocha的describe..it
函数中并从终端运行:
$ mocha
background page
✓ should display opened tabs count in button badge
1 passing (98ms)
您可以在此处找到完整的示例。
另外,sinon-chrome允许触发具有预定义响应的任何chrome事件,例如
chrome.tab.onCreated.trigger({url: 'http://google.com'});
虽然效果sinon.js
不错,但您也可以只使用普通的Jasmine并模拟所需的Chrome回调。例:
chrome = {
runtime: {
onMessage : {
addListener : function() {}
}
}
}
describe("JSGuardian", function() {
describe("BlockCache", function() {
beforeEach(function() {
this.blockCache = new BlockCache();
});
it("should recognize added urls", function() {
this.blockCache.add("http://some.url");
expect(this.blockCache.allow("http://some.url")).toBe(false);
});
} // ... etc
只需修改默认值SpecRunner.html
即可运行您的代码。
关于Chrome中已经存在的工具:
在chrome开发人员工具中,有用于本地存储的资源部分。
开发人员工具>资源>本地存储
在那里查看本地存储的变化。
您可以使用console.profile来测试性能并观察运行时调用堆栈。
如果您将内容脚本和本地存储一起使用而没有后台页面/脚本,也没有消息传递,则只能从该站点访问本地存储。因此,要测试这些页面,您必须在这些选项卡中插入测试脚本。
我发现我可以使用Selenium Web驱动程序来启动具有预安装扩展名的全新浏览器实例,并使用pyautogui进行点击-因为Selenium无法驱动扩展名的“视图”。单击后,您可以制作屏幕截图并将其与“预期”屏幕截图进行比较,以实现95%的相似度(因为在不同的浏览器上,标记移动到几个像素是可以接受的)。
为了确认之前的几个答案,Jasmine似乎可以与Chrome扩展程序很好地配合使用。我正在使用3.4.0版。
您可以使用Jasmine间谍轻松地为各种API创建测试双打。无需从头开始构建自己的。例如:
describe("Test suite", function() {
it("Test case", function() {
// Set up spies and fake data.
spyOn(chrome.browserAction, "setPopup");
spyOn(chrome.identity, "removeCachedAuthToken");
fakeToken = "faketoken-faketoken-faketoken";
fakeWindow = jasmine.createSpyObj("window", ["close"]);
// Call the function under test.
logout(fakeWindow, fakeToken);
// Perform assertions.
expect(chrome.browserAction.setPopup).toHaveBeenCalledWith({popup: ""});
expect(chrome.identity.removeCachedAuthToken).toHaveBeenCalledWith({token: fakeToken});
expect(fakeWindow.close.calls.count()).toEqual(1);
});
});
其他一些详细信息(如果有帮助):
如另一个答案所述,我在运行测试的浏览器扩展中创建了一个HTML页面。HTML页面包括Jasmine库,扩展程序的JavaScript代码以及测试套件。测试将自动运行,并为您格式化结果。无需构建测试运行器或结果格式化程序。只需按照安装说明进行操作,并使用此处记录的HTML创建测试运行器页面,并将测试套件也包括在该页面中。
我认为您无法从另一台主机动态获取Jasmine框架,因此我只是在扩展中包含了Jasmine版本。当然,在构建生产扩展时,我将忽略它以及测试用例。
我还没有研究如何在命令行中执行测试。这对于自动部署工具将很方便。