in packages/expect/src/spyMatchers.ts [1007:1136]
function (
this: MatcherState,
received: any,
nth: number,
expected: unknown,
): SyncExpectationResult {
const expectedArgument = 'n';
const options: MatcherHintOptions = {
expectedColor: (arg: string) => arg,
isNot: this.isNot,
promise: this.promise,
secondArgument: 'expected',
};
ensureMock(received, matcherName, expectedArgument, options);
if (!Number.isSafeInteger(nth) || nth < 1) {
throw new Error(
matcherErrorMessage(
matcherHint(matcherName, undefined, expectedArgument, options),
`${expectedArgument} must be a positive integer`,
printWithType(expectedArgument, nth, stringify),
),
);
}
const receivedName = received.getMockName();
const {calls, results} = received.mock;
const length = results.length;
const iNth = nth - 1;
const pass = iNth < length && isEqualReturn(expected, results[iNth]);
const message = pass
? () => {
// Display preceding and following results,
// in case assertions fails because index is off by one.
const indexedResults: Array<IndexedResult> = [];
if (iNth - 1 >= 0) {
indexedResults.push([iNth - 1, results[iNth - 1]]);
}
indexedResults.push([iNth, results[iNth]]);
if (iNth + 1 < length) {
indexedResults.push([iNth + 1, results[iNth + 1]]);
}
return (
// eslint-disable-next-line prefer-template
matcherHint(matcherName, receivedName, expectedArgument, options) +
'\n\n' +
`n: ${nth}\n` +
`Expected: not ${printExpected(expected)}\n` +
(results.length === 1 &&
results[0].type === 'return' &&
stringify(results[0].value) === stringify(expected)
? ''
: printReceivedResults(
'Received: ',
expected,
indexedResults,
results.length === 1,
iNth,
)) +
printNumberOfReturns(countReturns(results), calls.length)
);
}
: () => {
// Display preceding and following results:
// * nearest result that is equal to expected value
// * otherwise, adjacent result
// in case assertions fails because of index, especially off by one.
const indexedResults: Array<IndexedResult> = [];
if (iNth < length) {
if (iNth - 1 >= 0) {
let i = iNth - 1;
// Is there a preceding result that is equal to expected value?
while (i >= 0 && !isEqualReturn(expected, results[i])) {
i -= 1;
}
if (i < 0) {
i = iNth - 1; // otherwise, adjacent result
}
indexedResults.push([i, results[i]]);
}
indexedResults.push([iNth, results[iNth]]);
if (iNth + 1 < length) {
let i = iNth + 1;
// Is there a following result that is equal to expected value?
while (i < length && !isEqualReturn(expected, results[i])) {
i += 1;
}
if (i >= length) {
i = iNth + 1; // otherwise, adjacent result
}
indexedResults.push([i, results[i]]);
}
} else if (length > 0) {
// The number of received calls is fewer than the expected number.
let i = length - 1;
// Is there a result that is equal to expected value?
while (i >= 0 && !isEqualReturn(expected, results[i])) {
i -= 1;
}
if (i < 0) {
i = length - 1; // otherwise, last result
}
indexedResults.push([i, results[i]]);
}
return (
// eslint-disable-next-line prefer-template
matcherHint(matcherName, receivedName, expectedArgument, options) +
'\n\n' +
`n: ${nth}\n` +
`Expected: ${printExpected(expected)}\n` +
printReceivedResults(
'Received: ',
expected,
indexedResults,
results.length === 1,
iNth,
) +
printNumberOfReturns(countReturns(results), calls.length)
);
};
return {message, pass};
};