如何测试Chrome扩展程序/Firefox WebExtension代码?

3
由于 Firefox 强制要求我这样做,我正在重写我的扩展程序以使用 WebExtension API,即 Chrome 的 Extension API。我想要进行自动化测试。到目前为止,我尝试过以下方式:
我有一个 package.json 文件,因此 npm 将安装依赖项:
{
  "name": "extension-api-tests",
  "version": "0.0.1",
  "scripts": {
    "test": "karma start"
  },
  "devDependencies": {
    "karma": "^1.3.0",
    "karma-firefox-launcher": "^1.0.0",
    "karma-mocha": "^1.3.0",
    "karma-sinon-chrome": "^0.2.0",
    "mocha": "^3.1.2",
    "sinon-chrome": "^2.1.2"
  }
}

我有一个 karma.conf.js 来设置测试运行器:
module.exports = function(config) {
  config.set({
    frameworks: ['mocha', 'sinon-chrome'],
    files: ['test.js'],
    reporters: ['dots'],
    autoWatch: false,
    browsers: ['Firefox'],
    singleRun: true,
    concurrency: Infinity,
  });
};

我有基础测试:
describe('my frustration', () => {
  it('works when it uses no APIs', done => {
    done();
  });

  it('should respond to messages!', done => {
    console.log('message test starting');
    chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
      console.log('received message');
      sendResponse(true);
    });
    chrome.runtime.sendMessage({}, result => {
      console.log('received response to message');
      done();
    });
  });

  it('should open a tab!', done => {
    console.log('tab test starting');
    chrome.tabs.create({
      'active': true,
      'url': 'http://www.example.com/',
    }, tab => {
      console.log('created a tab:', tab);
      done();
    });
  });
});

当然,这只是一个简化的测试案例。当我运行npm test时,我会得到以下结果(略有缩写):
> extension-api-tests@0.0.1 test .../ext-test
> karma start

25 07 2017 11:57:10.395:INFO [karma]: Karma v1.7.0 server started at http://0.0.0.0:9876/
25 07 2017 11:57:10.397:INFO [launcher]: Launching browser Firefox with unlimited concurrency
25 07 2017 11:57:10.404:INFO [launcher]: Starting browser Firefox
25 07 2017 11:57:14.687:INFO [Firefox 54.0.0 (Ubuntu 0.0.0)]: Connected on socket iIjNRRQfzWj68_GNAAAA with id 42440302
.
LOG: 'message test starting'
Firefox 54.0.0 (Ubuntu 0.0.0) my frustration should respond to messages! FAILED
        Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
LOG: 'tab test starting'
Firefox 54.0.0 (Ubuntu 0.0.0) my frustration should open a tab! FAILED
        Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
Firefox 54.0.0 (Ubuntu 0.0.0): Executed 3 of 3 (2 FAILED) (3.998 secs / 4.001 secs)
npm ERR! Test failed.  See above for more details.

我的测试尝试使用扩展API都失败了。它并没有说(例如)chrome.runtime未定义(但如果我从karma.conf.js中删除'sinon-chrome',它就会这样说),所以我相信我已经设置好了sinon。但是API永远不起作用,永远不起作用。我想要测试的代码完全围绕着通过这些API传递数据(特别是作为消息,跨越chrome/content边界)。

我猜sinon提供了一个假的API,它不完全像真实的API那样运作,以便进行测试。 - arantius
实际上,sinon文档中的示例与您使用的简单调用完全不同。我不了解sinon,因此无法确定这是否是唯一支持的方法。 - wOxxOm
尝试将 sinon 标签添加到问题中,以便它能够被 sinon 专家看到。 - wOxxOm
在创建简化测试用例时不知何故错过了,但我绝对尝试过,就像(最初)在选项卡示例中一样;已编辑为sendMessage。 - arantius
1
你(已删除)的回答帮助解释了你的具体问题是什么。 - serv-inc
显示剩余3条评论
2个回答

2
除了原始问题中的所有设置外,还要意识到Sinon仅提供API表面的存根/模拟,而不是假API实现。
为了使测试“起作用”,必须声明模拟的行为;请参见例如 https://sinonjs.org/releases/latest/mocks/ https://sinonjs.org/releases/latest/stubs/。原始问题中的这种类型的测试“不可能”,因为您主要将测试您还需要在测试中编写的虚假实现。
一旦设置好sinon-chrome,您就可以更像编写测试
chrome.tabs.executeScript.callsArg(2);
// ... call code under test ...    
assert(chrome.tabs.executeScript.calledOnce);

(这不是我真正想要编写的测试类型。)

你在使用真实的浏览器/网页扩展API方面有成功吗? - serv-inc
1
不,我调整了我的测试策略。 - arantius

0
根据https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/runtime/sendMessage的说明,sendMessage返回一个Promise对象。根据您的日志记录,在您的成功处理程序中...
chrome.runtime.sendMessage({}, result => {
  console.log('received response to message');
  done();
});

与运行测试的主线程相比,该函数未能及时调用。您应该尝试在主线程中添加一个睡眠时间。

function sleep (time) {
  return new Promise((resolve) => setTimeout(resolve, time));
}

像这样

chrome.runtime.sendMessage({}, result => {
  console.log('received response to message');
});

sleep(500).then(() => {
  done();
});

只要sendMessage在500毫秒内返回,这应该可以工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接