Describe the bug
createStubInstance
ignores own properties and, on a super class, is blind to its inherited methods and properties
To Reproduce
class SubTest {
name;
constructor({ name }) { this.name = name }
something() {}
}
export default class SuperTest extends SubTest {
description;
constructor(...props) {
super(props);
this.description = props.description;
}
noop() {}
}
import sinon from 'sinon';
import SuperTest from './SuperTest.js';
sinon.createStubInstance(SuperTest, {
description: 'Lorem Ipsum',
name: 'Foobar',
noop() {},
something() {},
});
Error: Cannot stub description. Property does not exist!
at …/sinon/lib/sinon/stub.js:129:19
at Array.forEach (<anonymous>)
at stub.createStubInstance (…/sinon/lib/sinon/stub.js:120:5)
after commenting out description: 'Lorem Ipsum',
:
Error: Cannot stub name. Property does not exist!
at …/sinon/lib/sinon/stub.js:129:19
at Array.forEach (<anonymous>)
at stub.createStubInstance (…/sinon/lib/sinon/stub.js:120:5)
after also commenting out name: 'Foobar',
:
Error: Cannot stub something. Property does not exist!
at …/sinon/lib/sinon/stub.js:129:19
at Array.forEach (<anonymous>)
at stub.createStubInstance (…/sinon/lib/sinon/stub.js:120:5)
With only noop() {}
in the overrides, it works.
Expected behavior
I expect createStubInstance
to stub any/all fields that exist on the provided class.
Context (please complete the following information):
EDIT: I originally over-simplified the above test and omitted super()
, but it had no effect on sinon's behaviour. Test above is corrected.
Thanks for bringing this up. There are several things wrong or being misunderstood here:
createStubInstance
isn't documented (I wasn't even aware of it 😄).The documentation explicitly states that
The given constructor function is not invoked.
So the assumption that it can be used to pass initial arguments can not work.
{ something: sinon.stub() }
).{ something: 42 }
).This clearly needs better documentation, but it's not a bug.
How you can make your use case work:
Note that you're creating a new object from the "class" prototype. You're not actually making an instance of the class because the constructor isn't called. Basically the return value of createStubInstance
just has the same interface as your class with all functions being replaced with stubs. Therefore, if you need properties on this stub instance, you can just assign them.
thanks for your quick answer!
Note that you're creating a new object from the "class" prototype. You're not actually making an instance of the class because the constructor isn't called. Basically the return value of
createStubInstance
just has the same interface as your class with all functions being replaced with stubs. Therefore, if you need properties on this stub instance, you can just assign them.
Might it be worthwhile to support that within createStubInstance?
function createStubInstance (…) {
// …
return Object.assign(stubbedInstance, propertyValuePairs); // anything it doesn't recognise
}
@jshado1 Sure, we could do that. If you're interested in this feature, you're welcome to send a pull request 🙂