Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expect: Improve report when mock-spy matcher fails, part 3 #8697

Merged
merged 2 commits into from
Jul 16, 2019
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- `[expect]` Highlight substring differences when matcher fails, part 2 ([#8528](https://github.com/facebook/jest/pull/8528))
- `[expect]` Improve report when mock-spy matcher fails, part 1 ([#8640](https://github.com/facebook/jest/pull/8640))
- `[expect]` Improve report when mock-spy matcher fails, part 2 ([#8649](https://github.com/facebook/jest/pull/8649))
- `[expect]` Improve report when mock-spy matcher fails, part 3 ([#8697](https://github.com/facebook/jest/pull/8697))
- `[jest-snapshot]` Highlight substring differences when matcher fails, part 3 ([#8569](https://github.com/facebook/jest/pull/8569))
- `[jest-cli]` Improve chai support (with detailed output, to match jest exceptions) ([#8454](https://github.com/facebook/jest/pull/8454))
- `[*]` Manage the global timeout with `--testTimeout` command line argument. ([#8456](https://github.com/facebook/jest/pull/8456))
Expand Down
110 changes: 100 additions & 10 deletions packages/expect/src/__tests__/__snapshots__/spyMatchers.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,32 @@ Expected mock function \\"named-mock\\" first call to not have been called with:
<green>[\\"foo\\", \\"bar\\"]</>"
`;

exports[`nthCalledWith should reject non integer nth value 1`] = `"nth value <red>0.1</> must be a positive integer greater than <green>0</>"`;
exports[`nthCalledWith negative throw matcher error for n that is not integer 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>nthCalledWith<dim>(</><green>n</><dim>, </><green>...expected</><dim>)</>

exports[`nthCalledWith should reject nth value smaller than 1 1`] = `"nth value <red>0</> must be a positive integer greater than <green>0</>"`;
<bold>Matcher error</>: <green>n</> must be a positive integer

n has type: number
n has value: <green>Infinity</>"
`;

exports[`nthCalledWith positive throw matcher error for n that is not integer 1`] = `
"<dim>expect(</><red>received</><dim>).</>nthCalledWith<dim>(</><green>n</><dim>, </><green>...expected</><dim>)</>

<bold>Matcher error</>: <green>n</> must be a positive integer

n has type: number
n has value: <green>0.1</>"
`;

exports[`nthCalledWith positive throw matcher error for n that is not positive integer 1`] = `
"<dim>expect(</><red>received</><dim>).</>nthCalledWith<dim>(</><green>n</><dim>, </><green>...expected</><dim>)</>

<bold>Matcher error</>: <green>n</> must be a positive integer

n has type: number
n has value: <green>0</>"
`;

exports[`nthCalledWith should replace 1st, 2nd, 3rd with first, second, third 1`] = `
"<dim>expect(</><red>jest.fn()</><dim>).nthCalledWith(</><green>expected</><dim>)</>
Expand Down Expand Up @@ -460,7 +483,31 @@ But the 4th call returned exactly:
<red>0</>"
`;

exports[`nthReturnedWith nthReturnedWith should reject non integer nth value 1`] = `"nth value <red>0.1</> must be a positive integer greater than <green>0</>"`;
exports[`nthReturnedWith nthReturnedWith negative throw matcher error for n that is not number 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>nthReturnedWith<dim>(</><green>n</><dim>, </><green>expected</><dim>)</>

<bold>Matcher error</>: <green>n</> must be a positive integer

n has value: <green>undefined</>"
`;

exports[`nthReturnedWith nthReturnedWith positive throw matcher error for n that is not integer 1`] = `
"<dim>expect(</><red>received</><dim>).</>nthReturnedWith<dim>(</><green>n</><dim>, </><green>expected</><dim>)</>

<bold>Matcher error</>: <green>n</> must be a positive integer

n has type: number
n has value: <green>0.1</>"
`;

exports[`nthReturnedWith nthReturnedWith positive throw matcher error for n that is not positive integer 1`] = `
"<dim>expect(</><red>received</><dim>).</>nthReturnedWith<dim>(</><green>n</><dim>, </><green>expected</><dim>)</>

<bold>Matcher error</>: <green>n</> must be a positive integer

n has type: number
n has value: <green>0</>"
`;

exports[`nthReturnedWith nthReturnedWith should reject nth value greater than number of calls 1`] = `
"<dim>expect(</><red>jest.fn()</><dim>).nthReturnedWith(</><green>expected</><dim>)</>
Expand All @@ -470,8 +517,6 @@ Expected mock function 4th call to have returned with:
But it was only called <red>3</> times"
`;

exports[`nthReturnedWith nthReturnedWith should reject nth value smaller than 1 1`] = `"nth value <red>0</> must be a positive integer greater than <green>0</>"`;

exports[`nthReturnedWith nthReturnedWith should replace 1st, 2nd, 3rd with first, second, third 1`] = `
"<dim>expect(</><red>jest.fn()</><dim>).nthReturnedWith(</><green>expected</><dim>)</>

Expand Down Expand Up @@ -1390,9 +1435,32 @@ Expected mock function \\"named-mock\\" first call to not have been called with:
<green>[\\"foo\\", \\"bar\\"]</>"
`;

exports[`toHaveBeenNthCalledWith should reject non integer nth value 1`] = `"nth value <red>0.1</> must be a positive integer greater than <green>0</>"`;
exports[`toHaveBeenNthCalledWith negative throw matcher error for n that is not integer 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toHaveBeenNthCalledWith<dim>(</><green>n</><dim>, </><green>...expected</><dim>)</>

exports[`toHaveBeenNthCalledWith should reject nth value smaller than 1 1`] = `"nth value <red>0</> must be a positive integer greater than <green>0</>"`;
<bold>Matcher error</>: <green>n</> must be a positive integer

n has type: number
n has value: <green>Infinity</>"
`;

exports[`toHaveBeenNthCalledWith positive throw matcher error for n that is not integer 1`] = `
"<dim>expect(</><red>received</><dim>).</>toHaveBeenNthCalledWith<dim>(</><green>n</><dim>, </><green>...expected</><dim>)</>

<bold>Matcher error</>: <green>n</> must be a positive integer

n has type: number
n has value: <green>0.1</>"
`;

exports[`toHaveBeenNthCalledWith positive throw matcher error for n that is not positive integer 1`] = `
"<dim>expect(</><red>received</><dim>).</>toHaveBeenNthCalledWith<dim>(</><green>n</><dim>, </><green>...expected</><dim>)</>

<bold>Matcher error</>: <green>n</> must be a positive integer

n has type: number
n has value: <green>0</>"
`;

exports[`toHaveBeenNthCalledWith should replace 1st, 2nd, 3rd with first, second, third 1`] = `
"<dim>expect(</><red>jest.fn()</><dim>).toHaveBeenNthCalledWith(</><green>expected</><dim>)</>
Expand Down Expand Up @@ -1717,7 +1785,31 @@ But the 4th call returned exactly:
<red>0</>"
`;

exports[`toHaveNthReturnedWith nthReturnedWith should reject non integer nth value 1`] = `"nth value <red>0.1</> must be a positive integer greater than <green>0</>"`;
exports[`toHaveNthReturnedWith nthReturnedWith negative throw matcher error for n that is not number 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toHaveNthReturnedWith<dim>(</><green>n</><dim>, </><green>expected</><dim>)</>

<bold>Matcher error</>: <green>n</> must be a positive integer

n has value: <green>undefined</>"
`;

exports[`toHaveNthReturnedWith nthReturnedWith positive throw matcher error for n that is not integer 1`] = `
"<dim>expect(</><red>received</><dim>).</>toHaveNthReturnedWith<dim>(</><green>n</><dim>, </><green>expected</><dim>)</>

<bold>Matcher error</>: <green>n</> must be a positive integer

n has type: number
n has value: <green>0.1</>"
`;

exports[`toHaveNthReturnedWith nthReturnedWith positive throw matcher error for n that is not positive integer 1`] = `
"<dim>expect(</><red>received</><dim>).</>toHaveNthReturnedWith<dim>(</><green>n</><dim>, </><green>expected</><dim>)</>

<bold>Matcher error</>: <green>n</> must be a positive integer

n has type: number
n has value: <green>0</>"
`;

exports[`toHaveNthReturnedWith nthReturnedWith should reject nth value greater than number of calls 1`] = `
"<dim>expect(</><red>jest.fn()</><dim>).toHaveNthReturnedWith(</><green>expected</><dim>)</>
Expand All @@ -1727,8 +1819,6 @@ Expected mock function 4th call to have returned with:
But it was only called <red>3</> times"
`;

exports[`toHaveNthReturnedWith nthReturnedWith should reject nth value smaller than 1 1`] = `"nth value <red>0</> must be a positive integer greater than <green>0</>"`;

exports[`toHaveNthReturnedWith nthReturnedWith should replace 1st, 2nd, 3rd with first, second, third 1`] = `
"<dim>expect(</><red>jest.fn()</><dim>).toHaveNthReturnedWith(</><green>expected</><dim>)</>

Expand Down
26 changes: 22 additions & 4 deletions packages/expect/src/__tests__/spyMatchers.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ const jestExpect = require('../');
}).toThrowErrorMatchingSnapshot();
});

test('should reject nth value smaller than 1', async () => {
test('positive throw matcher error for n that is not positive integer', async () => {
const fn = jest.fn();
fn('foo1', 'bar');

Expand All @@ -347,14 +347,23 @@ const jestExpect = require('../');
}).toThrowErrorMatchingSnapshot();
});

test('should reject non integer nth value', async () => {
test('positive throw matcher error for n that is not integer', async () => {
const fn = jest.fn();
fn('foo1', 'bar');

expect(() => {
jestExpect(fn)[calledWith](0.1, 'foo1', 'bar');
}).toThrowErrorMatchingSnapshot();
});

test('negative throw matcher error for n that is not integer', async () => {
const fn = jest.fn();
fn('foo1', 'bar');

expect(() => {
jestExpect(fn).not[calledWith](Infinity, 'foo1', 'bar');
}).toThrowErrorMatchingSnapshot();
});
}

test(`includes the custom mock name in the error message`, () => {
Expand Down Expand Up @@ -963,7 +972,7 @@ const jestExpect = require('../');
}).toThrowErrorMatchingSnapshot();
});

test('should reject nth value smaller than 1', async () => {
test('positive throw matcher error for n that is not positive integer', async () => {
const fn = jest.fn(() => 'foo');
fn();

Expand All @@ -983,7 +992,7 @@ const jestExpect = require('../');
}).toThrowErrorMatchingSnapshot();
});

test('should reject non integer nth value', async () => {
test('positive throw matcher error for n that is not integer', async () => {
const fn = jest.fn(() => 'foo');
fn('foo');

Expand All @@ -992,6 +1001,15 @@ const jestExpect = require('../');
}).toThrowErrorMatchingSnapshot();
});

test('negative throw matcher error for n that is not number', async () => {
const fn = jest.fn(() => 'foo');
fn('foo');

expect(() => {
jestExpect(fn).not[returnedWith]();
}).toThrowErrorMatchingSnapshot();
});

test(`incomplete recursive calls are handled properly`, () => {
// sums up all integers from 0 -> value, using recursion
const fn = jest.fn(value => {
Expand Down
47 changes: 29 additions & 18 deletions packages/expect/src/spyMatchers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
diff,
ensureExpectedIsNumber,
ensureNoExpected,
EXPECTED_COLOR,
matcherErrorMessage,
matcherHint,
MatcherHintOptions,
Expand Down Expand Up @@ -422,19 +423,24 @@ const createNthCalledWithMatcher = (matcherName: string) =>
};
ensureMock(received, matcherName.slice(1), expectedArgument, options);

if (!Number.isSafeInteger(nth) || nth < 1) {
throw new Error(
matcherErrorMessage(
matcherHint(
matcherName.slice(1),
undefined,
expectedArgument,
options,
),
`${EXPECTED_COLOR(expectedArgument)} must be a positive integer`,
printWithType(expectedArgument, nth, printExpected),
),
);
}

const receivedIsSpy = isSpy(received);
const type = receivedIsSpy ? 'spy' : 'mock function';

// @ts-ignore
if (typeof nth !== 'number' || parseInt(nth, 10) !== nth || nth < 1) {
const message = () =>
`nth value ${printReceived(
nth,
)} must be a positive integer greater than ${printExpected(0)}`;
const pass = false;
return {message, pass};
}

const receivedName = receivedIsSpy ? 'spy' : received.getMockName();
const identifier =
receivedIsSpy || receivedName === 'jest.fn()'
Expand Down Expand Up @@ -483,14 +489,19 @@ const createNthReturnedWithMatcher = (matcherName: string) =>
};
ensureMock(received, matcherName.slice(1), expectedArgument, options);

//@ts-ignore
if (typeof nth !== 'number' || parseInt(nth, 10) !== nth || nth < 1) {
const message = () =>
`nth value ${printReceived(
nth,
)} must be a positive integer greater than ${printExpected(0)}`;
const pass = false;
return {message, pass};
if (!Number.isSafeInteger(nth) || nth < 1) {
throw new Error(
matcherErrorMessage(
matcherHint(
matcherName.slice(1),
undefined,
expectedArgument,
options,
),
`${EXPECTED_COLOR(expectedArgument)} must be a positive integer`,
printWithType(expectedArgument, nth, printExpected),
),
);
}

const receivedName = received.getMockName();
Expand Down