Describe the bug
22.1.0 introduced per-sandbox callId isolation for parallel test support (#2472, fixed by #2715). Fakes created via sandbox.spy() / sandbox.stub() now get their callId from an isolated sandboxContext object via .withContext(...).
However, createStubInstance() (both the top-level sinon.createStubInstance() and sandbox.createStubInstance()) was not updated as part of that fix. It still calls the plain stub(stubInstance) internally (see create-stub-instance.js / stub.js), which never receives a context and therefore falls back to the hardcoded module-level singleton defaultContext = { callId: 0 } in proxy-invoke.js.
The practical effect: any fake created via createStubInstance() is tracked on a totally different callId counter than fakes created via spy() / stub(). Both counters start at 0 independently, so calledAfter() / calledBefore() / calledImmediatelyBefore() / calledImmediatelyAfter() comparisons between a createStubInstance()-created method and a spy()/stub()-created fake become meaningless — they no longer reflect real call order.
This worked correctly before 22.1.0, when there was a single global callId counter shared by everything.
To Reproduce
const sinon = require('sinon')
class Foo {
bar () {}
}
const spy1 = sinon.spy(() => {})
spy1() // called first
const stubInst = sinon.createStubInstance(Foo)
stubInst.bar() // called second, strictly after spy1()
console.log(stubInst.bar.calledAfter(spy1)) // => false (should be true)
console.log('spy1 callIds:', spy1.callIds) // [0]
console.log('stub.bar callIds:', stubInst.bar.callIds) // [0]
Both callIds are 0 even though stubInst.bar() ran strictly after spy1(), because they're tracked on two unrelated counter objects.
Expected behavior
stubInst.bar.calledAfter(spy1) should return true, matching real call order, the same as it did in sinon 22.0.0.
Context
- Sinon version: 22.1.0
- Runtime: Node.js (any)
Additional context
Likely fix: have createStubInstance() accept/forward a context argument the same way stub.withContext does, and have sandbox.createStubInstance() pass its own sandboxContext through, similar to how sandbox.spy() / sandbox.stub() already do.
I found this while investigating a test regression after bumping from sinon 22.0.0 to 22.1.0 — a test comparing call order between a sinon.createStubInstance()-based stub and a sinon.spy() started failing intermittently even though the real call order was correct. The repro above reduces it to the minimal case, with no project-specific code.
Describe the bug
22.1.0 introduced per-sandbox
callIdisolation for parallel test support (#2472, fixed by #2715). Fakes created viasandbox.spy()/sandbox.stub()now get theircallIdfrom an isolatedsandboxContextobject via.withContext(...).However,
createStubInstance()(both the top-levelsinon.createStubInstance()andsandbox.createStubInstance()) was not updated as part of that fix. It still calls the plainstub(stubInstance)internally (seecreate-stub-instance.js/stub.js), which never receives a context and therefore falls back to the hardcoded module-level singletondefaultContext = { callId: 0 }inproxy-invoke.js.The practical effect: any fake created via
createStubInstance()is tracked on a totally differentcallIdcounter than fakes created viaspy()/stub(). Both counters start at0independently, socalledAfter()/calledBefore()/calledImmediatelyBefore()/calledImmediatelyAfter()comparisons between acreateStubInstance()-created method and aspy()/stub()-created fake become meaningless — they no longer reflect real call order.This worked correctly before 22.1.0, when there was a single global
callIdcounter shared by everything.To Reproduce
Both callIds are
0even thoughstubInst.bar()ran strictly afterspy1(), because they're tracked on two unrelated counter objects.Expected behavior
stubInst.bar.calledAfter(spy1)should returntrue, matching real call order, the same as it did in sinon 22.0.0.Context
Additional context
Likely fix: have
createStubInstance()accept/forward acontextargument the same waystub.withContextdoes, and havesandbox.createStubInstance()pass its ownsandboxContextthrough, similar to howsandbox.spy()/sandbox.stub()already do.I found this while investigating a test regression after bumping from sinon 22.0.0 to 22.1.0 — a test comparing call order between a
sinon.createStubInstance()-based stub and asinon.spy()started failing intermittently even though the real call order was correct. The repro above reduces it to the minimal case, with no project-specific code.