callsFake() on mocks only returns a value the first time
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 45/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Stale
- Tech stack
- javascript
- Domain
- testing-qa
Research direction
Start by running the JavaScript reproduction in the issue with Sinon 17.0.1 and inspect the mock expectation path for callsFake() across multiple onCall() calls. The fix is complete when each fake returns its expected value, all three assertions pass, mock.verify() succeeds, and the accumulator remains empty.
Written by the indexing model from the issue text.
Description
Describe the bug
If multiple distinct expectations, for multiple calls to the same mock, are set, and callsFake() is used on each of them, while the fake functions do get called, the return value is discarded for all of them but the first one.
To Reproduce
it("Does not return all values from fake functions for mocks", function() {
obj = {
accumulator: [],
accumulate: function(thing) {
this.accumulator.push(thing);
return `added ${thing}`;
}
}
mock = sinon.mock(obj);
mock.expects("accumulate")
.withArgs("first thing").onCall(0).callsFake(thing => "mock-added first thing"); // .returns("mock-added first thing");
mock.expects("accumulate")
.withArgs("second thing").onCall(1).callsFake(thing => "mock-added second thing"); // .returns("mock-added second thing");
mock.expects("accumulate")
.withArgs("third thing").onCall(2).callsFake(thing => "mock-added third thing"); // .returns("mock-added third thing");
expect(obj.accumulator).to.have.lengthOf(0);
expect(obj.accumulate("first thing")).to.equal("mock-added first thing");
expect(obj.accumulate("second thing")).to.equal("mock-added second thing");
expect(obj.accumulate("third thing")).to.equal("mock-added third thing");
mock.verify();
});
Expected behavior
All expectations in the three lines before mock.verify() that verify calls to obj.accumulate() should pass, while obj.accumulator should stay empty.
Actual behavior
obj.accumulator does stay empty, because the first expect(...) statement passes. But the test fails in the second expect(...).to.equal(...) line, with this error message:
AssertionError: expected undefined to equal 'mock-added second thing'
If the commented out .returns(...) fragments are enabled, the test passes.
What's odd and inconsistent, however, is that if only the last two .returns(...) fragments are enabled, while the first one is left commented out, the test still passes. So the return value of the first callsFake(...) is returned, but the return values of subsequent calls to fake functions installed by callsFake() are discarded, and require an explicit additional returns(...) for a return value to be returned from the mocked call.
Screenshots
n.a.
Context (please complete the following information):
- Sinon version : 17.0.1
- Runtime: Node v22.19.0
- Output of
npx envinfo --browsers --binaries:
- Output of
Binaries:
Node: 22.19.0 - /usr/bin/node
npm: 10.9.2 - ~/KBV/src/kbv-devops/certs-updater/node_modules/.bin/npm
Browsers:
Chrome: 140.0.7339.127
- Other relevant environmental info:
- Other libraries you are using: Chai 4.5.0, mocha 11.0.1
- Example URL: n.a.
Additional context
n.a.
- Dominant language
- JavaScript
- Stars
- 9.8k
- Forks
- 809
- PR merge metrics
- No merged PRs in 30d
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from sinonjs/sinon
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
Difficulty 3/5 1-2 days Newbie friendliness 72/100
-
Difficulty 4/5 3-5 days Newbie friendliness 38/100
-
Documentation
Difficulty 4/5 3-5 days Newbie friendliness 55/100
-
Difficulty 5/5 Over a week Newbie friendliness 25/100
Similar issues
-
code-quality refactoring
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
github/gh-aw-firewall#8816 ·
-
integration:quickjs org:external priority:backlog topic:code-interpreter topic:middleware type:feature
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
langchain-ai/deepagents#6450 ·
-
optimization optimization:agents-md-curator
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
githubnext/gh-aw-cao#13143 ·
-
status: needs triage
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100