Skip to content

createStubInstance() doesn't receive per-sandbox callId context, breaking calledAfter/calledBefore vs spy() #2760

Description

@rlsf

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions