Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions src/sinon/mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import wrapMethod from "./util/core/wrap-method.js";

const { prototypes } = commons;
const { deepEqual } = samsam;
const { concat, filter, forEach, every, join, push, slice, unshift } =
const { concat, filter, forEach, every, join, push, reduce, slice, unshift } =
prototypes.array;

/**
Expand Down Expand Up @@ -125,6 +125,13 @@ extend(mock, {
? this.expectations[method]
: [];
const currentArgs = args || [];
const callIndex = reduce(
expectations,
function (count, expectation) {
return count + expectation.callCount;
},
0,
);
let available;

const expectationsWithMatchingArgs = filter(
Expand All @@ -151,7 +158,12 @@ extend(mock, {
);

if (expectationsToApply.length > 0) {
return expectationsToApply[0].apply(thisValue, args);
return invokeExpectation(
expectationsToApply[0],
thisValue,
args,
callIndex,
);
}

const messages = [];
Expand All @@ -166,7 +178,7 @@ extend(mock, {
});

if (available && exhausted === 0) {
return available.apply(thisValue, args);
return invokeExpectation(available, thisValue, args, callIndex);
}

forEach(expectations, function (expectation) {
Expand Down Expand Up @@ -202,3 +214,12 @@ extend(mock, {
mockExpectation.fail(join(messages, "\n"));
},
});

function invokeExpectation(expectation, thisValue, args, callIndex) {
expectation.behaviorCallIndex = callIndex;
try {
return expectation.apply(thisValue, args);
} finally {
delete expectation.behaviorCallIndex;
}
}
6 changes: 5 additions & 1 deletion src/sinon/stub.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,11 @@ function getDefaultBehavior(stubInstance) {
}

function getCurrentBehavior(stubInstance) {
const currentBehavior = stubInstance.behaviors[stubInstance.callCount - 1];
const currentCall =
typeof stubInstance.behaviorCallIndex === "number"
? stubInstance.behaviorCallIndex
: stubInstance.callCount - 1;
const currentBehavior = stubInstance.behaviors[currentCall];
return currentBehavior && currentBehavior.isPresent()
? currentBehavior
: getDefaultBehavior(stubInstance);
Expand Down
45 changes: 45 additions & 0 deletions test/src/mock-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1234,6 +1234,51 @@ describe("sinonMock", function () {
object.method(42);
});
});

it("returns callsFake values from ordered matching expectations", function () {
const object = {
accumulator: [],
accumulate: function (thing) {
this.accumulator.push(thing);
return `added ${thing}`;
},
};
const mock = sinonMock(object);

mock.expects("accumulate")
.withArgs("first thing")
.onCall(0)
.callsFake(function (thing) {
return `mock-added ${thing}`;
});
mock.expects("accumulate")
.withArgs("second thing")
.onCall(1)
.callsFake(function (thing) {
return `mock-added ${thing}`;
});
mock.expects("accumulate")
.withArgs("third thing")
.onCall(2)
.callsFake(function (thing) {
return `mock-added ${thing}`;
});

assert.equals(object.accumulator.length, 0);
assert.equals(
object.accumulate("first thing"),
"mock-added first thing",
);
assert.equals(
object.accumulate("second thing"),
"mock-added second thing",
);
assert.equals(
object.accumulate("third thing"),
"mock-added third thing",
);
mock.verify();
});
});

describe("mock function", function () {
Expand Down