acvetkov / sinon-chrome

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

How to override stubbed methods? #30

Open io-monad opened 8 years ago

io-monad commented 8 years ago

Hi, thank you for awesome module!

I have been trying to override a stubbed method provided by sinon-chrome with my implementation to simulate chrome.runtime.lastError set inside the method.

Is there any officially-recommended way to override stubbed methods?


What I have tried

I'll write down here what I have tried for overriding methods just FYI.

NG: Assigning a function

First, I tried simply overwrite the method with a function by assignment as mentioned in README, but it seemed not working at all.

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

// FAIL (getURL() returns undefined)
assert.equal(chrome.runtime.getURL("test"), "chrome-extension://my_test_id/test");

This is because stubbed methods are defined by Object.defineProperty with writable: false.

NG: sinon.stub()

Second, I tried sinon.stub() to stub a stubbed method, which sounds complicated. :P

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

// Error
assert.equal(chrome.runtime.getURL("test"), "chrome-extension://my_test_id/test");

And sinon output error:

TypeError: Attempted to wrap undefined property getURL as function

OK but weird: Replace entire namespace object

Third, I tried replacing entire chrome.runtime namespace object with another one.

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

// PASS
assert.equal(chrome.runtime.getURL("test"), "chrome-extension://my_test_id/test");

Although this one could mange to override a namespace including target method, it looks weird and has too much side-effect which is not related to the test.

I don't think this one is ideal, and there should be another way to override stubbed methods easily IMHO.

acvetkov commented 8 years ago

@io-monad, hi.

Thank you for issue. Unfortunately, sinon-chrome does not support chrome api method overriding now. I am not completely sure that you needs it.

@vitalets what do you think about?

vitalets commented 8 years ago

Is not this work?

chrome.runtime.getURL.restore();
sinon.stub(chrome.runtime, "getURL", function (path) {
   return 'chrome-extension://' + chrome.runtime.id + '/' + path;
});

but anyway it also looks not obvious and needs manual reset / restore.

I suggest to add chrome._stub() method that behave like sinon's one but allows to overwrite stubs.

chrome._stub(chrome.runtime, "getURL", function (path) {
   return 'chrome-extension://' + chrome.runtime.id + '/' + path;
});
tswast commented 8 years ago

Could we update the README? The Difference from 0.2 section makes it sound like we can and should override by assigning the function.

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

@tswast you are right, I'll fix readme

ilyaigpetrov commented 7 years ago

Still an issue with sinon-chrome 2.2.1:

'use strict';

const chrome = require('sinon-chrome/extensions');
const originalSet = chrome.proxy.settings.set;
chrome.proxy.settings.set = function () {
  console.log('I\'m new here!');
}
console.log('STILL THE SAME?', chrome.proxy.settings.set === originalSet); // Prints "true".
ilyaigpetrov commented 7 years ago

Proposed a pull request: #57

acvetkov commented 7 years ago

@ilyaigpetrov hi.

I have no reason to add same functionality for api methods, since sinon-chrome@2 has released. You can override all logic behavior , using sinon stubs api.

For define custom logic, like topic starter wants, you should use callsFake method from sinon stub.

fregante commented 4 months ago

I think this issue can be closed, it's now documented: https://github.com/acvetkov/sinon-chrome#stubs-api

Essentially just call .returns() on the desired method:

chrome.runtime.getManifest.returns({permissions: ['tabs']});