Describe the bug
Methods defined with descriptor through get method returning method can not be stubbed.
To Reproduce
Some method-decorators using this approach to define method. Like autobind (#2008, autobind-decorator#47) (not really using it, but this was the only similar issues). Version of bind decorator I made and used (TypeScript):
function bind(t, k, d) {
return {
configurable: true,
get() {
const value = d.get && d.get() || d.value;
const bounded = value.bind(this);
Object.defineProperty(this, k, { value: bounded });
return bounded;
}
}
}
And without decorators, when I need some static local var (static like in c++) in function (there is probably a better approach, but this is one I come up with by my self):
class AutoIdGenerator {
get nextId() {
let b = 1;
Object.defineProperty(this, 'nextId', {
configurable: true,
value() { return b++; },
});
return this.nextId;
}
}
Both examples will work properly with sinon.stub after first getter called.
Expected behavior
Well... Properly stub methods defined through get function...
Context (please complete the following information):
I don't see you trying to demonstrate that this doesn't work. There is nothing special with functions as values, so doing it as in the docs should work fine.
Here's a demo I quickly hacked together now that demonstrates it working fine:
https://runkit.com/fatso83/sinon-issue-2041-stubbing-method-getters
Why should any one in this case want stub to getter function? Have to always pass some function to .get with stub, does not seems right for me. I can't do something like this at least: sinon.stub(o, 'bar').get() or sinon.stub(o, 'bar').get().returns('stubbed bar').
And using stub.get it self in this seems really strange. Why should anyone care to know how things like autobind-decorator works on the inside to test they are own code?
Even if sinon.stub(o, 'bar').get() would work sometime later. This is not approach for methods, but for properties. I think the better approach here will be to define stub's methods to define if original is method or property, like sinon.stub(o, 'bar').method(). Or even better will be to move out property stubing to separate handler like sinon.propStub.
The only workaround I found so far is:
const realStub = sinon.stub();
const propStub = sinon.stub(s, 'handleToolEvent').get(() => realStub);
realStub.restore = () => propStub.restore();
@anon155 the main problem was that I didn't understand what you meant was wrong, since the description utilized some highly creative English syntax 馃槈 I have re-read both the description and the expected outcome, and I'm still not sure.
But by reading the last comment it seems that you somehow want access to the method driving the getter (synthetic property)? I don't know why you would want that, but I can't come up with a way, except if you actually override it using a stub, in which case you do have it.
So AFAIK that isn't possible to do (please prove me wrong! Maybe a property getter is able to?).
The rest seems like you disagree with the API. That's fine. A lot of it is historic baggage and if you come up with some good suggestions in the form of a PR we'll definitely look into it!
If you mean there is a bug lurking here, that I somehow missed, we can reopen the issue.
Yeah, sorry. I'm pretty bad at English ))
The main problem is with decorated methods, especially with @bind decorator. For the user of the decorator, they seems to be normal methods. But internally in most cases they are done with getter (because decorator used on prototype object and not class instance).
Do you think you could describe a scenario with the hypothetical API you want? For instance, how would you at best want to test your id generator? That makes it easier to reason about a possible solution. And preferably in ES5: just forget decorators at the moment, as that kind of gets in the way of the discussion (still just a proposal).
This doesn't concern the feature you want, but generally I think _not knowing_ how something is implemented when trying to stub it is a bad idea. Many try to use Sinon without understanding _what_ a stub is or how Sinon works on a basic level, which is why you get issues like this from time to time. I think you _should_ know whether something is a function or a getter, or whatever, when trying to stub it.
Made some changes. But I did not have time to make proper PR. Did not even tested it properly. Will do it a bit later. https://github.com/anion155/sinon . Main idea is to call method() on created stub, which will do wrapMethod(this.rootObj, this.propName, this)
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.