Skip to content

Commit

Permalink
Make error messages more explicit for toBeCalledWith assertions
Browse files Browse the repository at this point in the history
  • Loading branch information
mkubilayk committed Jul 5, 2017
1 parent a7acc5a commit 5b78d9b
Show file tree
Hide file tree
Showing 4 changed files with 390 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@ exports[`lastCalledWith works with Map 2`] = `
"<dim>expect(<red>jest.fn()</><dim>).lastCalledWith(<green>expected</><dim>)

Expected mock function to have been last called with:
<green>[Map {\\"a\\" => \\"b\\", \\"b\\" => \\"a\\"}]</>
But it was last called with:
<red>[Map {1 => 2, 2 => 1}]</>"
<green>Map {\\"a\\" => \\"b\\", \\"b\\" => \\"a\\"}</> as argument 1, but it was called with <red>Map {1 => 2, 2 => 1}</>."
`;

exports[`lastCalledWith works with Set 1`] = `
Expand All @@ -50,18 +48,14 @@ exports[`lastCalledWith works with Set 2`] = `
"<dim>expect(<red>jest.fn()</><dim>).lastCalledWith(<green>expected</><dim>)

Expected mock function to have been last called with:
<green>[Set {3, 4}]</>
But it was last called with:
<red>[Set {1, 2}]</>"
<green>Set {3, 4}</> as argument 1, but it was called with <red>Set {1, 2}</>."
`;

exports[`lastCalledWith works with arguments that don't match 1`] = `
"<dim>expect(<red>jest.fn()</><dim>).lastCalledWith(<green>expected</><dim>)

Expected mock function to have been last called with:
<green>[\\"foo\\", \\"bar\\"]</>
But it was last called with:
<red>[\\"foo\\", \\"bar1\\"]</>"
<green>\\"bar\\"</> as argument 2, but it was called with <red>\\"bar1\\"</>."
`;

exports[`lastCalledWith works with arguments that match 1`] = `
Expand All @@ -82,10 +76,7 @@ exports[`lastCalledWith works with many arguments that don't match 1`] = `
"<dim>expect(<red>jest.fn()</><dim>).lastCalledWith(<green>expected</><dim>)

Expected mock function to have been last called with:
<green>[\\"foo\\", \\"bar\\"]</>
But it was last called with:
<red>[\\"foo\\", \\"bar3\\"]</>
and <red>two more calls</>."
<green>\\"bar\\"</> as argument 2, but it was called with <red>\\"bar3\\"</>."
`;

exports[`toBeCalled works only on spies or jest.fn 1`] = `
Expand Down Expand Up @@ -262,9 +253,7 @@ exports[`toHaveBeenCalledWith works with Map 2`] = `
"<dim>expect(<red>jest.fn()</><dim>).toHaveBeenCalledWith(<green>expected</><dim>)

Expected mock function to have been called with:
<green>[Map {\\"a\\" => \\"b\\", \\"b\\" => \\"a\\"}]</>
But it was called with:
<red>[Map {1 => 2, 2 => 1}]</>"
<green>Map {\\"a\\" => \\"b\\", \\"b\\" => \\"a\\"}</> as argument 1, but it was called with <red>Map {1 => 2, 2 => 1}</>."
`;

exports[`toHaveBeenCalledWith works with Set 1`] = `
Expand All @@ -278,18 +267,14 @@ exports[`toHaveBeenCalledWith works with Set 2`] = `
"<dim>expect(<red>jest.fn()</><dim>).toHaveBeenCalledWith(<green>expected</><dim>)

Expected mock function to have been called with:
<green>[Set {3, 4}]</>
But it was called with:
<red>[Set {1, 2}]</>"
<green>Set {3, 4}</> as argument 1, but it was called with <red>Set {1, 2}</>."
`;

exports[`toHaveBeenCalledWith works with arguments that don't match 1`] = `
"<dim>expect(<red>jest.fn()</><dim>).toHaveBeenCalledWith(<green>expected</><dim>)

Expected mock function to have been called with:
<green>[\\"foo\\", \\"bar\\"]</>
But it was called with:
<red>[\\"foo\\", \\"bar1\\"]</>"
<green>\\"bar\\"</> as argument 2, but it was called with <red>\\"bar1\\"</>."
`;

exports[`toHaveBeenCalledWith works with arguments that match 1`] = `
Expand All @@ -310,9 +295,11 @@ exports[`toHaveBeenCalledWith works with many arguments that don't match 1`] = `
"<dim>expect(<red>jest.fn()</><dim>).toHaveBeenCalledWith(<green>expected</><dim>)

Expected mock function to have been called with:
<green>[\\"foo\\", \\"bar\\"]</>
But it was called with:
<red>[\\"foo\\", \\"bar3\\"]</>, <red>[\\"foo\\", \\"bar2\\"]</>, <red>[\\"foo\\", \\"bar1\\"]</>"
<green>\\"bar\\"</> as argument 2, but it was called with <red>\\"bar3\\"</>.

<green>\\"bar\\"</> as argument 2, but it was called with <red>\\"bar2\\"</>.

<green>\\"bar\\"</> as argument 2, but it was called with <red>\\"bar1\\"</>."
`;

exports[`toHaveBeenLastCalledWith works only on spies or jest.fn 1`] = `
Expand Down Expand Up @@ -349,9 +336,7 @@ exports[`toHaveBeenLastCalledWith works with Map 2`] = `
"<dim>expect(<red>jest.fn()</><dim>).toHaveBeenLastCalledWith(<green>expected</><dim>)

Expected mock function to have been last called with:
<green>[Map {\\"a\\" => \\"b\\", \\"b\\" => \\"a\\"}]</>
But it was last called with:
<red>[Map {1 => 2, 2 => 1}]</>"
<green>Map {\\"a\\" => \\"b\\", \\"b\\" => \\"a\\"}</> as argument 1, but it was called with <red>Map {1 => 2, 2 => 1}</>."
`;

exports[`toHaveBeenLastCalledWith works with Set 1`] = `
Expand All @@ -365,18 +350,14 @@ exports[`toHaveBeenLastCalledWith works with Set 2`] = `
"<dim>expect(<red>jest.fn()</><dim>).toHaveBeenLastCalledWith(<green>expected</><dim>)

Expected mock function to have been last called with:
<green>[Set {3, 4}]</>
But it was last called with:
<red>[Set {1, 2}]</>"
<green>Set {3, 4}</> as argument 1, but it was called with <red>Set {1, 2}</>."
`;

exports[`toHaveBeenLastCalledWith works with arguments that don't match 1`] = `
"<dim>expect(<red>jest.fn()</><dim>).toHaveBeenLastCalledWith(<green>expected</><dim>)

Expected mock function to have been last called with:
<green>[\\"foo\\", \\"bar\\"]</>
But it was last called with:
<red>[\\"foo\\", \\"bar1\\"]</>"
<green>\\"bar\\"</> as argument 2, but it was called with <red>\\"bar1\\"</>."
`;

exports[`toHaveBeenLastCalledWith works with arguments that match 1`] = `
Expand All @@ -397,8 +378,5 @@ exports[`toHaveBeenLastCalledWith works with many arguments that don't match 1`]
"<dim>expect(<red>jest.fn()</><dim>).toHaveBeenLastCalledWith(<green>expected</><dim>)

Expected mock function to have been last called with:
<green>[\\"foo\\", \\"bar\\"]</>
But it was last called with:
<red>[\\"foo\\", \\"bar3\\"]</>
and <red>two more calls</>."
<green>\\"bar\\"</> as argument 2, but it was called with <red>\\"bar3\\"</>."
`;
44 changes: 38 additions & 6 deletions packages/jest-matchers/src/spy_matchers.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
RECEIVED_COLOR,
} from 'jest-matcher-utils';
import {equals} from './jasmine_utils';
import {iterableEquality} from './utils';
import {iterableEquality, partition} from './utils';

const RECEIVED_NAME = {
'mock function': 'jest.fn()',
Expand Down Expand Up @@ -69,7 +69,11 @@ const createToBeCalledWithMatcher = matcherName => (
const calls = receivedIsSpy
? received.calls.all().map(x => x.args)
: received.mock.calls;
const pass = calls.some(call => equals(call, expected, [iterableEquality]));

const [match, fail] = partition(calls, call =>
equals(call, expected, [iterableEquality]),
);
const pass = match.length > 0;

const message = pass
? () =>
Expand All @@ -81,8 +85,7 @@ const createToBeCalledWithMatcher = matcherName => (
matcherHint(matcherName, RECEIVED_NAME[type]) +
'\n\n' +
`Expected ${type} to have been called with:\n` +
` ${printExpected(expected)}\n` +
formatReceivedCalls(calls, CALL_PRINT_LIMIT);
formatMismatchedCalls(fail, expected, CALL_PRINT_LIMIT);

return {message, pass};
};
Expand Down Expand Up @@ -110,8 +113,7 @@ const createLastCalledWithMatcher = matcherName => (
matcherHint(matcherName, RECEIVED_NAME[type]) +
'\n\n' +
`Expected ${type} to have been last called with:\n` +
` ${printExpected(expected)}\n` +
formatReceivedCalls(calls, LAST_CALL_PRINT_LIMIT, {isLast: true});
formatMismatchedCalls(calls, expected, LAST_CALL_PRINT_LIMIT);

return {message, pass};
};
Expand Down Expand Up @@ -198,4 +200,34 @@ const formatReceivedCalls = (calls, limit, options) => {
}
};

const formatMismatchedCalls = (calls, expected, limit) => {
if (calls.length) {
return calls
.slice(-limit)
.reverse()
.map(formatMismatchedArgs.bind(null, expected))
.join('\n\n');
} else {
return (
` ${printExpected(expected)}\n` +
`But it was ${RECEIVED_COLOR('not called')}.`
);
}
};

const formatMismatchedArgs = (expected, received) => {
const length = Math.max(expected.length, received.length);

const printedArgs = [];
for (let i = 0; i < length; i++) {
if (!equals(expected[i], received[i], [iterableEquality])) {
printedArgs.push(
` ${printExpected(expected[i])} as argument ${i + 1}, ` +
`but it was called with ${printReceived(received[i])}.`,
);
}
}
return printedArgs.join('\n');
};

export default spyMatchers;
11 changes: 11 additions & 0 deletions packages/jest-matchers/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,14 @@ export const iterableEquality = (a: any, b: any) => {
}
return true;
};

export const partition = <T>(
items: Array<T>,
predicate: T => boolean,
): [Array<T>, Array<T>] => {
const result = [[], []];

items.forEach(item => result[predicate(item) ? 0 : 1].push(item));

return result;
};
Loading

0 comments on commit 5b78d9b

Please sign in to comment.