如何测试Chrome扩展程序?


154

有什么好方法吗?我正在编写一个扩展程序,它可以作为内容脚本与网站交互,并使用localstorage保存数据。是否可以使用任何工具,框架等来测试此行为?我意识到有一些通用的工具可以测试javascript,但是这些工具足以测试扩展吗?单元测试最重要,但是我也对其他类型的测试(例如集成测试)感兴趣。


8
我刚刚写了一个规范的答案,该答案针对所有浏览器(不仅限于Chrome)的浏览器扩展进行单元测试和集成测试。请参阅“测试浏览器扩展”的答案
罗伯W

Answers:


111

是的,现有框架非常有用。

最近,我将所有测试放在一个“测试”页面上,该页面已嵌入到应用程序中,但除非进行物理键入,否则无法访问。

例如,我会将所有测试放在一个页面下 chrome-extension://asdasdasdasdad/unittests.html

这些测试可以访问localStorage等。为了访问内容脚本,从理论上讲,您可以通过测试页面中的嵌入式IFRAME进行测试,但是这些是更多的集成级别测试,单元测试需要您从实际页面中抽象出来,以便您不要依赖它们,同样可以访问localStorage。

如果您想直接测试页面,则可以编排扩展名以打开新标签页(chrome.tab.create({“ url”:“ someurl”})。对于每个新标签页,您的内容脚本都应运行,并且您可以使用您的测试框架,以检查您的代码是否已完成应做的工作。

至于框架,JsUnit或更新的Jasmine应该可以正常工作。


1
没错,测试真实页面不会进行单元测试。我应该使我的问题更广泛。但这仍然是我要测试的东西,尤其是因为网站html结构可能随时更改。我已经修改了问题。
swampsjohn

1
我仍然会在您的单元测试页中通过IFrames进行测试。内容脚本仍应触发(如果您使脚本能够在iFrame中运行)
Kinlan 2010年

3
代理示例扩展程序进行了一些测试,这些测试仅模拟了必要的Chrome API的 细节:code.google.com/chrome/extensions/samples.html#chrome.proxy ..我们的同事Boris也使用QUnit进行测试他的“模型”层:github.com/borismus/Question-Monitor-for-Stack-Exchange/tree/…–
Paul Irish,

63

在几个Chrome扩展工作,我想出了sinon-chrome项目,允许使用运行单元测试mochanodejsphantomjs

基本上,它将创建所有chrome.*API的sinon模拟,您可以在其中放置任何预定义的json响应。

接下来,您使用节点的vm.runInNewContext后台页面和phantomjs渲染弹出/选项页面加载脚本。

最后,您断言使用所需参数调用了chrome api。

让我们举个例子:
假设我们有一个简单的chrome扩展名,该扩展名显示了按钮标记中打开的选项卡的数量。

背景页面:

chrome.tabs.query({}, function(tabs) {
  chrome.browserAction.setBadgeText({text: String(tabs.length)});
});

要测试它,我们需要:

  1. 模拟chrome.tabs.query返回预定义的响应,例如两个选项卡。
  2. 将模拟的chrome.*api注入某些环境
  3. 在此环境中运行我们的扩展代码
  4. 断言按钮徽章等于“ 2”

该代码段如下:

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'});

该示例的链接似乎已失效-您能否对其进行更新?
Raisen

1
更新了示例链接。另外,sinon-chrome现在也移到了github.com/acvetkov,很快就会有新的例子
vitalets 2015年

3

虽然效果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即可运行您的代码。


2

关于Chrome中已经存在的工具:

  1. 在chrome开发人员工具中,有用于本地存储的资源部分。

    开发人员工具>资源>本地存储

    在那里查看本地存储的变化。

  2. 您可以使用console.profile来测试性能并观察运行时调用堆栈。

  3. 对于fileSystem,您可以使用以下URL来检查文件是否已上传:filesystem:chrome-extension:/// temporary /

如果您将内容脚本和本地存储一起使用而没有后台页面/脚本,也没有消息传递,则只能从该站点访问本地存储。因此,要测试这些页面,您必须在这些选项卡中插入测试脚本。


1
不适用于我,但确实可以帮助我进一步了解JavaScript。+1。
mobibob 2014年

对于fileSystem,您可以使用:filesystem:chrome-extension:// <yourextension-id> / temporary /-Nafis
Ahmad

1

我发现我可以使用Selenium Web驱动程序来启动具有预安装扩展名的全新浏览器实例,并使用pyautogui进行点击-因为Selenium无法驱动扩展名的“视图”。单击后,您可以制作屏幕截图并将其与“预期”屏幕截图进行比较,以实现95%的相似度(因为在不同的浏览器上,标记移动到几个像素是可以接受的)。


0

为了确认之前的几个答案,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版本。当然,在构建生产扩展时,我将忽略它以及测试用例。

我还没有研究如何在命令行中执行测试。这对于自动部署工具将很方便。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.