How to test chrome extensions? How to test chrome extensions? google-chrome google-chrome

How to test chrome extensions?


Yes, the existing frameworks are pretty useful..

In the recent past, I have placed all my tests on a "test" page that was embedded in to the application but not reachable unless physically typed.

For instance, I would have all the tests in a page accessible under chrome-extension://asdasdasdasdad/unittests.html

The tests would have access to localStorage etc. For accessing content scripts, in theory you could test that through embedded IFRAMEs in your test page, however these are more integration level testing, unit tests would require you to abstract that away from real pages so that you don't depend on them, likewise with access to localStorage.

If you want to test pages directly, you can orchestrate your extension to open new tabs (chrome.tab.create({"url" : "someurl"}). For each of the new tabs your content script should run and you can use your testing framework to check that your code has done what it should do.

As for frameworks, JsUnit or the more recent Jasmine should work fine.


Working on several chrome extensions I came up with sinon-chrome project that allows to run unit-tests using mocha, nodejs and phantomjs.

Basically, it creates sinon mocks of all chrome.* API where you can put any predefined json responses.

Next, you load your scripts using node's vm.runInNewContext for background page and phantomjs for render popup / options page.

And finally, you assert that chrome api was called with needed arguments.

Let's take an example:
Assume we have simple chrome extension that displays number of opened tabs in button badge.

background page:

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

To test it we need:

  1. mock chrome.tabs.query to return predefined response, e.g. two tabs.
  2. inject our mocked chrome.* api into some environment
  3. run our extension code in this environment
  4. assert that button badge equals to '2'

The code snippet is following:

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 environmentconst context = {  chrome: chrome};// 3. run our extension code in this environmentconst 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"});

Now we can wrap it into mocha's describe..it functions and run from terminal:

$ mochabackground page  ✓ should display opened tabs count in button badge1 passing (98ms)

You can find full example here.

Additionally, sinon-chrome allows to trigger any chrome event with predefined response, e.g.

chrome.tab.onCreated.trigger({url: 'http://google.com'});


While sinon.js seems to work great, you can also just use plain Jasmine and mock the Chrome callbacks you need. Example:

Mock

chrome = {  runtime: {    onMessage : {      addListener : function() {}    }  }}

Test

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

Just modify the default SpecRunner.html to run your code.