Skip to content
Aleksey Tsvetkov edited this page Jan 6, 2016 · 1 revision

Sinon-chrome usage example

Let's create simple chrome extension, that displays opened tabs count. We need create simple background.js script for main logic and popup.js, that displays current tabs count on badge.

Create manifest.json

{
  "name": "Opened Tabs List",
  "description": "A browser action that displays opened tabs list",
  "version": "1.0",
  "permissions": [
    "tabs"
  ],
  "background": { 
    "scripts": ["background.js"]
  },
  "browser_action": {
    "default_popup": "popup.html",
    "default_icon": "icon.png"
  },
  "manifest_version": 2
}

Main logic background.js

/**
 * Retrieves opened tabs list
 * @param {Function} callback
 */
function getOpenedTabs(callback) {
    var params = {
        windowId: chrome.windows.WINDOW_ID_CURRENT
    };
    chrome.tabs.query(params, callback);
}

/**
 * Updates browserAction badge
 * @param {Array} tabs
 */
function updateBadge(tabs) {
    chrome.browserAction.setBadgeText({
        text: String(tabs.length)
    });
}

/**
 * Listen messages from popup
 */
chrome.runtime.onMessage.addListener(function (data, sender, sendResponse) {
    if (data === 'get-tabs') {
        getOpenedTabs(sendResponse);
        return true;
    }
});

/**
 * listen to new tab creation and update badge counter
 */
chrome.tabs.onCreated.addListener(function () {
    getOpenedTabs(updateBadge);
});

/**
 * listen tab onRemoved and update badge counter
 */
chrome.tabs.onRemoved.addListener(function () {
    getOpenedTabs(updateBadge);
});

/**
 * update badge counter on startup
 */
getOpenedTabs(updateBadge);

Create popup page popup.html

<!doctype html>
<html>
  <head>
    <title></title>
    <style>
      body {width: 400px;}
    </style>
  </head>
  <body>
    <ul id="tabs">
    </ul>
    <script src="popup.js"></script>
  </body>
</html>

And popup logic script popup.js

// request background for opened tabs list
chrome.runtime.sendMessage('get-tabs', function(data) {
    var html = [];
    var maxLength = 40;
    data.forEach(function(tab) {
        var title = tab.title.length > maxLength ? tab.title.substring(0, maxLength) + '...' : tab.title;
        html.push('<li><a href="#" data-id="' + tab.id + '">' + title + '</a></li>');
    });
    document.getElementById('tabs').innerHTML = html.join('');
});

// listen click on title to activate tab
document.getElementById('tabs').addEventListener('click', function(e) {
    if (e.target.tagName === 'A') {
        e.preventDefault();
        var tabId = parseInt(e.target.getAttribute('data-id'), 10);
        chrome.tabs.update(tabId, {active: true});
    }
});

Now we have working extension, that watches user tabs. Let's test it with sinon-chrome.

Background specs background.test.js

var fs = require('fs');
var sinon = require('sinon');
var chrome = require('sinon-chrome');
var assert = require('chai').assert;
var jsdom = require('jsdom');

sinon.assert.expose(global.assert, {prefix: ''});

describe('background page', function () {

    var window;

    beforeEach(function (done) {
        jsdom.env({
            // generated background page
            html: '<html></html>',
            // js source
            src: [fs.readFileSync('src/background.js', 'utf-8')],
            created: function (errors, wnd) {
                // attach `chrome` to window
                wnd.chrome = chrome;
                wnd.console = console;
            },
            done: function (errors, wnd) {
                if (errors) {
                    console.log(errors);
                    done(true);
                } else {
                    window = wnd;
                    done();
                }
            }
        });
    });

    afterEach(function () {
        chrome.reset();
        window.close();
    });

    it('should attach listeners on startup', function () {
        assert.calledOnce(chrome.runtime.onMessage.addListener);
        assert.calledOnce(chrome.tabs.onCreated.addListener);
        assert.calledOnce(chrome.tabs.onRemoved.addListener);
    });

    it('should update badge on startup', function () {
        assert.calledOnce(chrome.tabs.query);
        assert.calledOnce(chrome.browserAction.setBadgeText);
        assert.calledWithMatch(chrome.browserAction.setBadgeText, {
            text: '4'
        });
    });

    it('should return tabs by request from popup', function () {
        chrome.tabs.query.reset();
        var sendResponse = sinon.spy();
        chrome.runtime.onMessage.trigger('get-tabs', {}, sendResponse);
        assert.calledOnce(chrome.tabs.query);
        assert.calledOnce(sendResponse);
        assert.calledWith(sendResponse, sinon.match.array);
        assert.calledWith(sendResponse, sinon.match(function (value) {
            return value.length === 4;
        }));
    });
});

And popup.test.js

var fs = require('fs');
var sinon = require('sinon');
var chrome = require('sinon-chrome');
var jsdom = require('jsdom');
var assert = require('chai').assert;

var window;

describe('popup page', function() {

    beforeEach(function(done) {
        jsdom.env({
            // popup
            file: 'src/popup.html',
            // js source
            src: [fs.readFileSync('src/popup.js', 'utf-8')],
            created: function (errors, wnd) {
                if (errors) {
                    console.log(errors);
                    return done(true);
                }
                // attach `chrome` to window
                wnd.chrome = chrome;
                wnd.console = console;

                // fake tabs response
                chrome.runtime.sendMessage.yields([
                    {id: 1, title: 'tab 1'},
                    {id: 2, title: 'tab 2'}
                ]);
            },
            done: function (errors, wnd) {
                if (errors) {
                    console.log(errors);
                    return done(true);
                }
                window = wnd;
                done();
            }
        });
    });

    afterEach(function() {
        chrome.reset();
        window.close();
    });

    it('should request tabs and render response on startup', function() {
        assert.calledOnce(chrome.runtime.sendMessage);
        var html = '<li><a href="#" data-id="1">tab 1</a></li><li><a href="#" data-id="2">tab 2</a></li>';
        assert.equal(window.document.getElementById('tabs').innerHTML, html);
    });

});

Test with pleasure :)

Clone this wiki locally