acvetkov / sinon-chrome

Testing chrome extensions with Node.js
ISC License
435 stars 46 forks source link

Example in Readme.md to test messaging #13

Closed tvpavan closed 8 years ago

tvpavan commented 8 years ago

It would be good, if we have an example to test message passing. Most of the plugins have a postMessage and onMessage callbacks. eg. chromeobject.postMessage("hello") chromeobject.onMessage.AddListener(function(data){ console.log(data) }) A call to postMessage or message needs to trigger callback registered via onMessage.AddListener.

acvetkov commented 8 years ago

@tvpavan, hi!

Yes, it's good idea, but you can test message passing as usual chrome events.

For example

var spy = sinon.spy();
chrome.runtime.onMessage.addListener(spy);

// trigger event manually instead of postMessage

chrome.runtime.onMessage.trigger(1, 2, 3);
console.log(spy.withArgs(1, 2, 3).callCount); // 1

Another example

function handler(data) {
   console.log(data);
}

var obj = {a: 1, b: 2};

chrome.runtime.onMessageExternal.addListener(handler);

// trigger event manually

chrome.runtime.onMessageExternal.trigger(obj);
// function handler will be called with obj argument
tvpavan commented 8 years ago

Thansk @acvetkov . I will go with chrome.runtime.onMessage.trigger(1, 2, 3) method. Was wondering if a specail stub / spy can do a "on"+methodName.captializeFirstLetter().trigger so that main app code needn't be changed for testing.

acvetkov commented 8 years ago

main app code needn't be changed for testing.

@tvpavan, can you write example for this case? I don't understand for what reason your app code need to be changed.

tvpavan commented 8 years ago

To test our background.js i am simulating an user click as chrome.browserAction.onClicked.trigger() from test script. Code of background.js uses postMessage and has AddListener calls on tab ports to communicate with our injected content script on tabs. I can change the code of background.js as if(testmode) { chrome.tabs.connect(id).onMessage.trigger({data:"hello"}); } else { chrome.tabs.connect(id).postMessage({data:"hello"}); } this works. But I thought if we can simulate/stub these calls , i can avoid the if(testmode) code change.

acvetkov commented 8 years ago

@tvpavan, I think, it's not TDD way. You should test your background page apart from content-script.

In background you should make sure that port object send correct message to content-script. In content script you should make sure that it works correct with correct input params.

For example

// background.js

chrome.browserAction.onClicked.addListener(clickHandler);

function clickHandler() {
   chrome.tabs.connect('1').postMessage({data:"hello"});
}

Let's test it

// background.test.js

var fakePort = {
   postMessage: sinon.spy()
};

before(function () {
   chrome.tabs.connect.returns(fakePort);
});

it('should send correct message to content script', function () {
   // simulate click 
   chrome.browserAction.onClicked.trigger();
   assert.calledOnce(fakePort.postMessage.withArgs({data:"hello"}));
});

Content script

// content-script.js
var port = chrome.runtime.connect({name: 'content'});
var port.onMessage.addListener(function () {
   // do something
});

test

// content-script.test.js
var ChromeEvent = require('sinon-chrome/out/events');
var fakePort = {
   onMessage: new ChromeEvent()
};

before(function () {
   chrome.runtime.connect.returns(fakePort);
});

it('should works', function () {
   // run you content script
   fakePort.onMessage.trigger({});
   // test reaction
});