Skip to content

Testing chrome extensions with Node.js

License

Notifications You must be signed in to change notification settings

chlab/sinon-chrome

Repository files navigation

Build Status Code Climate npm version

What is it?

Mocks for chrome.* extensions api via sinon stubs.

Why this is needed?

To run unit tests for chrome extensions in node or browser

Features

  1. Stubs for all chrome.* methods and properties
  2. Manual events triggering
  3. Plugins to emulate cookies storage, opened tabs, etc

How to install

Npm:

npm install sinon-chrome

Direct download:
sinon-chrome.js

How to use

Make chrome global

Node

before(function() {
   global.chrome = require('sinon-chrome');
});

Browser

<script src="...sinon-chrome.js">

Write tests

You can use all sinon stub api to create chrome methods behavior.

For example

var domainACookies = [
   {
      name: 'a',
      value: 'b',
      domain: 'domainA.com'
   }
];

var domainBCookies = [
   {
      name: 'b',
      value: 'c',
      domain: 'domainB.com'
   }
];

var allCookies = domainACookies.concat(domainBCookies);

before(function () {
   chrome.cookies.getAll.withArgs({domain: 'domainA.com'}).yields(domainACookies);
   chrome.cookies.getAll.withArgs({domain: 'domainB.com'}).yields(domainBCookies);
   chrome.cookies.getAll.withArgs({}).yields(allCookies);
});

it('should return correct cookies for domain A', function () {
   chrome.cookies.getAll({domain: 'domainA.com'}, function (list) {
      assert.deepEqual(list, domainACookies);
   });
});

it('should return correct cookies for domain B', function () {
   chrome.cookies.getAll({domain: 'domainB.com'}, function (list) {
      assert.deepEqual(list, domainBCookies);
   });
});

it('should return correct cookies for all domains', function () {
   chrome.cookies.getAll({}, function (list) {
      assert.deepEqual(list, allCookies);
   });
});

Properties

You can define chrome api property values.

For example

chrome.runtime.id = 'test';
chrome.runtime.lastError = new Error('some error');
chrome.windows.WINDOW_ID_CURRENT = 100;

console.log(chrome.runtime.id); // test
console.log(chrome.runtime.lastError); // Error: some error(…)
console.log(chrome.windows.WINDOW_ID_CURRENT); // 100

chrome.flush();

console.log(chrome.runtime.id); // undefined
console.log(chrome.runtime.lastError); // undefined
console.log(chrome.windows.WINDOW_ID_CURRENT); // undefined

Events

You can can manipulate by chrome events by manual triggering with custom params.

For example

var handler = sinon.spy();
chrome.cookies.onChanged.addListener(handler);

chrome.cookies.onChanged.trigger(1, 2, 3);
handler.withArgs(1, 2, 3).callCount; // 1

chrome.cookies.onChanged.trigger(1, 2, 3);
handler.withArgs(1, 2, 3).callCount; // 2

// remove listener
chrome.cookies.onChanged.removeListener(handler);
chrome.cookies.onChanged.trigger(1, 2, 3);
chrome.cookies.onChanged.trigger(1, 2, 3);
handler.withArgs(1, 2, 3).callCount; // 2

To reset stubs data, you should call chrome.reset.

For example

chrome.tabs.getAll();
chrome.tabs.getAll();

chrome.runtime.id = 'test_id';

console.log(chrome.tabs.getAll.callCount); // 2

chrome.reset();
console.log(chrome.tabs.getAll.callCount); // 0

To reset stubs behavior, you should call chrome.flush or chrome.[namespace].[method].resetBehavior

For example

chrome.runtime.getURL.returns('url');
chrome.tabs.query.yields([1, 2, 3]);
console.log(chrome.runtime.getURL()); // url
chrome.tabs.query({}, function tabsHandler(list) {
   console.log(list); // [1, 2, 3]
});

chrome.flush();
console.log(chrome.runtime.getURL()); // undefined
chrome.tabs.query({}, function tabsHandler(list) {
   // unreachable point. Function tabsHandler will never be called
});

Difference from 0.2 version

We remove all predefined properties and behavior. You must define all stubs behavior by your self.

For example

before(function () {
   chrome.runtime.id = 'my_test_id';
   chrome.runtime.getURL = function (path) {
      return 'chrome-extension://' + chrome.runtime.id + '/' + path;
   };
});

Supported namespaces

  1. chrome.alarms
  2. chrome.bookmarks
  3. chrome.browserAction
  4. chrome.browsingData
  5. chrome.certificateProvider
  6. chrome.commands
  7. chrome.contentSettings
  8. chrome.contextMenus
  9. chrome.cookies
  10. chrome.debugger
  11. chrome.declarativeContent
  12. chrome.desktopCapture
  13. chrome.devtools.inspectedWindow
  14. chrome.devtools.network
  15. chrome.devtools.panels
  16. chrome.downloads
  17. chrome.extension
  18. chrome.extensionTypes
  19. chrome.fontSettings
  20. chrome.gcm
  21. chrome.history
  22. chrome.i18n
  23. chrome.identity
  24. chrome.idle
  25. chrome.instanceID
  26. chrome.management
  27. chrome.notifications
  28. chrome.omnibox
  29. chrome.pageAction
  30. chrome.pageCapture
  31. chrome.permissions
  32. chrome.printerProvider
  33. chrome.privacy
  34. chrome.proxy
  35. chrome.runtime
  36. chrome.sessions
  37. chrome.storage
  38. chrome.system.cpu
  39. chrome.system.display
  40. chrome.system.memory
  41. chrome.system.storage
  42. chrome.tabCapture
  43. chrome.tabs
  44. chrome.topSites
  45. chrome.tts
  46. chrome.ttsEngine
  47. chrome.webNavigation
  48. chrome.webRequest
  49. chrome.windows

Development and pull request.

Fork this repo and install all dependencies. Don't forget check your code style and run tests before send pull request.

code checking

npm run code

run tests

npm test

Any questions?

Feel free to open issue.

Contributors

  1. Vitaly Potapov
  2. Aleksey Tsvetkov

About

Testing chrome extensions with Node.js

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 100.0%