Skip to content

Commit

Permalink
expect: Throw matcher error when received cannot be jasmine spy (#8747)
Browse files Browse the repository at this point in the history
* expect: Improve report when mock-spy matcher fails, part 5

* Update CHANGELOG.md

* Edit CHANGELOG.md
  • Loading branch information
pedrottimark committed Jul 25, 2019
1 parent cb322d1 commit f857d30
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 37 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -8,6 +8,7 @@
- `[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))
- `[expect]` Improve report when mock-spy matcher fails, part 4 ([#8710](https://github.com/facebook/jest/pull/8710))
- `[expect]` Throw matcher error when received cannot be jasmine spy ([#8747](https://github.com/facebook/jest/pull/8747))
- `[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
Expand Up @@ -180,7 +180,7 @@ Number of returns: <red>3</>"
exports[`lastReturnedWith works only on spies or jest.fn 1`] = `
"<dim>expect(</><red>received</><dim>).</>lastReturnedWith<dim>(</><green>expected</><dim>)</>

<bold>Matcher error</>: <red>received</> value must be a mock or spy function
<bold>Matcher error</>: <red>received</> value must be a mock function

Received has type: function
Received has value: <red>[Function fn]</>"
Expand Down Expand Up @@ -590,7 +590,7 @@ Number of returns: <red>3</>"
exports[`nthReturnedWith works only on spies or jest.fn 1`] = `
"<dim>expect(</><red>received</><dim>).</>nthReturnedWith<dim>(</><green>n</><dim>, </><green>expected</><dim>)</>

<bold>Matcher error</>: <red>received</> value must be a mock or spy function
<bold>Matcher error</>: <red>received</> value must be a mock function

Received has type: function
Received has value: <red>[Function fn]</>"
Expand Down Expand Up @@ -699,7 +699,7 @@ Expected has value: <green>555</>"
`;

exports[`toBeCalled .not passes when called 1`] = `
"<dim>expect(</><red>jest.fn()</><dim>).</>toBeCalled<dim>()</>
"<dim>expect(</><red>spy</><dim>).</>toBeCalled<dim>()</>

Expected number of calls: >= <green>1</>
Received number of calls: <red>0</>"
Expand Down Expand Up @@ -880,7 +880,7 @@ Expected has value: <green>[Function anonymous]</>"
`;

exports[`toBeCalledTimes passes if function called equal to expected times 1`] = `
"<dim>expect(</><red>jest.fn()</><dim>).</>not<dim>.</>toBeCalledTimes<dim>(</><green>expected</><dim>)</>
"<dim>expect(</><red>spy</><dim>).</>not<dim>.</>toBeCalledTimes<dim>(</><green>expected</><dim>)</>

Expected number of calls: not <green>2</>"
`;
Expand Down Expand Up @@ -1029,7 +1029,7 @@ Expected has value: <green>555</>"
`;

exports[`toHaveBeenCalled .not passes when called 1`] = `
"<dim>expect(</><red>jest.fn()</><dim>).</>toHaveBeenCalled<dim>()</>
"<dim>expect(</><red>spy</><dim>).</>toHaveBeenCalled<dim>()</>

Expected number of calls: >= <green>1</>
Received number of calls: <red>0</>"
Expand Down Expand Up @@ -1210,7 +1210,7 @@ Expected has value: <green>[Function anonymous]</>"
`;

exports[`toHaveBeenCalledTimes passes if function called equal to expected times 1`] = `
"<dim>expect(</><red>jest.fn()</><dim>).</>not<dim>.</>toHaveBeenCalledTimes<dim>(</><green>expected</><dim>)</>
"<dim>expect(</><red>spy</><dim>).</>not<dim>.</>toHaveBeenCalledTimes<dim>(</><green>expected</><dim>)</>

Expected number of calls: not <green>2</>"
`;
Expand Down Expand Up @@ -1689,7 +1689,7 @@ Number of returns: <red>3</>"
exports[`toHaveLastReturnedWith works only on spies or jest.fn 1`] = `
"<dim>expect(</><red>received</><dim>).</>toHaveLastReturnedWith<dim>(</><green>expected</><dim>)</>

<bold>Matcher error</>: <red>received</> value must be a mock or spy function
<bold>Matcher error</>: <red>received</> value must be a mock function

Received has type: function
Received has value: <red>[Function fn]</>"
Expand Down Expand Up @@ -1939,7 +1939,7 @@ Number of returns: <red>3</>"
exports[`toHaveNthReturnedWith works only on spies or jest.fn 1`] = `
"<dim>expect(</><red>received</><dim>).</>toHaveNthReturnedWith<dim>(</><green>n</><dim>, </><green>expected</><dim>)</>

<bold>Matcher error</>: <red>received</> value must be a mock or spy function
<bold>Matcher error</>: <red>received</> value must be a mock function

Received has type: function
Received has value: <red>[Function fn]</>"
Expand Down Expand Up @@ -2073,7 +2073,7 @@ Received number of returns: <red>0</>"
exports[`toHaveReturned .not works only on jest.fn 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toHaveReturned<dim>()</>

<bold>Matcher error</>: <red>received</> value must be a mock or spy function
<bold>Matcher error</>: <red>received</> value must be a mock function

Received has type: function
Received has value: <red>[Function fn]</>"
Expand Down Expand Up @@ -2135,6 +2135,15 @@ Received number of returns: <red>1</>
1: <red>undefined</>"
`;

exports[`toHaveReturned throw matcher error if received is spy 1`] = `
"<dim>expect(</><red>received</><dim>).</>toHaveReturned<dim>()</>

<bold>Matcher error</>: <red>received</> value must be a mock function

Received has type: function
Received has value: <red>[Function spy]</>"
`;

exports[`toHaveReturnedTimes .not only accepts a number argument 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toHaveReturnedTimes<dim>(</><green>expected</><dim>)</>

Expand Down Expand Up @@ -2300,13 +2309,13 @@ exports[`toHaveReturnedTimes passes if function returned equal to expected times
Expected number of returns: not <green>2</>"
`;

exports[`toHaveReturnedTimes works only on spies or jest.fn 1`] = `
"<dim>expect(</><red>received</><dim>).</>toHaveReturnedTimes<dim>(</><green>expected</><dim>)</>
exports[`toHaveReturnedTimes throw matcher error if received is spy 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toHaveReturnedTimes<dim>(</><green>expected</><dim>)</>

<bold>Matcher error</>: <red>received</> value must be a mock or spy function
<bold>Matcher error</>: <red>received</> value must be a mock function

Received has type: function
Received has value: <red>[Function fn]</>"
Received has value: <red>[Function spy]</>"
`;

exports[`toHaveReturnedWith a call that throws is not considered to have returned 1`] = `
Expand Down Expand Up @@ -2365,7 +2374,7 @@ Number of returns: <red>6</>"
exports[`toHaveReturnedWith works only on spies or jest.fn 1`] = `
"<dim>expect(</><red>received</><dim>).</>toHaveReturnedWith<dim>(</><green>expected</><dim>)</>

<bold>Matcher error</>: <red>received</> value must be a mock or spy function
<bold>Matcher error</>: <red>received</> value must be a mock function

Received has type: function
Received has value: <red>[Function fn]</>"
Expand Down Expand Up @@ -2489,7 +2498,7 @@ Received number of returns: <red>0</>"
exports[`toReturn .not works only on jest.fn 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toReturn<dim>()</>

<bold>Matcher error</>: <red>received</> value must be a mock or spy function
<bold>Matcher error</>: <red>received</> value must be a mock function

Received has type: function
Received has value: <red>[Function fn]</>"
Expand Down Expand Up @@ -2551,6 +2560,15 @@ Received number of returns: <red>1</>
1: <red>undefined</>"
`;

exports[`toReturn throw matcher error if received is spy 1`] = `
"<dim>expect(</><red>received</><dim>).</>toReturn<dim>()</>

<bold>Matcher error</>: <red>received</> value must be a mock function

Received has type: function
Received has value: <red>[Function spy]</>"
`;

exports[`toReturnTimes .not only accepts a number argument 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toReturnTimes<dim>(</><green>expected</><dim>)</>

Expand Down Expand Up @@ -2716,13 +2734,13 @@ exports[`toReturnTimes passes if function returned equal to expected times 1`] =
Expected number of returns: not <green>2</>"
`;

exports[`toReturnTimes works only on spies or jest.fn 1`] = `
"<dim>expect(</><red>received</><dim>).</>toReturnTimes<dim>(</><green>expected</><dim>)</>
exports[`toReturnTimes throw matcher error if received is spy 1`] = `
"<dim>expect(</><red>received</><dim>).</>not<dim>.</>toReturnTimes<dim>(</><green>expected</><dim>)</>

<bold>Matcher error</>: <red>received</> value must be a mock or spy function
<bold>Matcher error</>: <red>received</> value must be a mock function

Received has type: function
Received has value: <red>[Function fn]</>"
Received has value: <red>[Function spy]</>"
`;

exports[`toReturnWith a call that throws is not considered to have returned 1`] = `
Expand Down Expand Up @@ -2781,7 +2799,7 @@ Number of returns: <red>6</>"
exports[`toReturnWith works only on spies or jest.fn 1`] = `
"<dim>expect(</><red>received</><dim>).</>toReturnWith<dim>(</><green>expected</><dim>)</>

<bold>Matcher error</>: <red>received</> value must be a mock or spy function
<bold>Matcher error</>: <red>received</> value must be a mock function

Received has type: function
Received has value: <red>[Function fn]</>"
Expand Down
49 changes: 44 additions & 5 deletions packages/expect/src/__tests__/spyMatchers.test.js
Expand Up @@ -8,6 +8,22 @@
const Immutable = require('immutable');
const jestExpect = require('../');

// Given a Jest mock function, return a minimal mock of a Jasmine spy.
const createSpy = fn => {
const spy = function() {};

spy.calls = {
all() {
return fn.mock.calls.map(args => ({args}));
},
count() {
return fn.mock.calls.length;
},
};

return spy;
};

['toBeCalled', 'toHaveBeenCalled'].forEach(called => {
describe(`${called}`, () => {
test(`works only on spies or jest.fn`, () => {
Expand All @@ -19,15 +35,18 @@ const jestExpect = require('../');
test(`passes when called`, () => {
const fn = jest.fn();
fn('arg0', 'arg1', 'arg2');
jestExpect(createSpy(fn))[called]();
jestExpect(fn)[called]();
expect(() => jestExpect(fn).not[called]()).toThrowErrorMatchingSnapshot();
});

test(`.not passes when called`, () => {
const fn = jest.fn();
const spy = createSpy(fn);

jestExpect(spy).not[called]();
jestExpect(fn).not[called]();
expect(() => jestExpect(fn)[called]()).toThrowErrorMatchingSnapshot();
expect(() => jestExpect(spy)[called]()).toThrowErrorMatchingSnapshot();
});

test(`fails with any argument passed`, () => {
Expand Down Expand Up @@ -93,10 +112,12 @@ const jestExpect = require('../');
fn();
fn();

const spy = createSpy(fn);
jestExpect(spy)[calledTimes](2);
jestExpect(fn)[calledTimes](2);

expect(() =>
jestExpect(fn).not[calledTimes](2),
jestExpect(spy).not[calledTimes](2),
).toThrowErrorMatchingSnapshot();
});

Expand All @@ -106,6 +127,10 @@ const jestExpect = require('../');
fn();
fn();

const spy = createSpy(fn);
jestExpect(spy)[calledTimes](3);
jestExpect(spy).not[calledTimes](2);

jestExpect(fn)[calledTimes](3);
jestExpect(fn).not[calledTimes](2);

Expand All @@ -118,6 +143,10 @@ const jestExpect = require('../');
const fn = jest.fn();
fn();

const spy = createSpy(fn);
jestExpect(spy)[calledTimes](1);
jestExpect(spy).not[calledTimes](2);

jestExpect(fn)[calledTimes](1);
jestExpect(fn).not[calledTimes](2);

Expand Down Expand Up @@ -164,6 +193,7 @@ const jestExpect = require('../');

test(`works when not called`, () => {
const fn = jest.fn();
caller(jestExpect(createSpy(fn)).not[calledWith], 'foo', 'bar');
caller(jestExpect(fn).not[calledWith], 'foo', 'bar');

expect(() =>
Expand All @@ -174,13 +204,15 @@ const jestExpect = require('../');
test(`works with no arguments`, () => {
const fn = jest.fn();
fn();
caller(jestExpect(createSpy(fn))[calledWith]);
caller(jestExpect(fn)[calledWith]);
});

test(`works with arguments that don't match`, () => {
const fn = jest.fn();
fn('foo', 'bar1');

caller(jestExpect(createSpy(fn)).not[calledWith], 'foo', 'bar');
caller(jestExpect(fn).not[calledWith], 'foo', 'bar');

expect(() =>
Expand All @@ -192,6 +224,7 @@ const jestExpect = require('../');
const fn = jest.fn();
fn('foo', 'bar');

caller(jestExpect(createSpy(fn))[calledWith], 'foo', 'bar');
caller(jestExpect(fn)[calledWith], 'foo', 'bar');

expect(() =>
Expand Down Expand Up @@ -389,6 +422,12 @@ const jestExpect = require('../');
).toThrowErrorMatchingSnapshot();
});

test(`throw matcher error if received is spy`, () => {
const spy = createSpy(jest.fn());

expect(() => jestExpect(spy)[returned]()).toThrowErrorMatchingSnapshot();
});

test(`passes when returned`, () => {
const fn = jest.fn(() => 42);
fn();
Expand Down Expand Up @@ -525,11 +564,11 @@ const jestExpect = require('../');

['toReturnTimes', 'toHaveReturnedTimes'].forEach(returnedTimes => {
describe(`${returnedTimes}`, () => {
test('works only on spies or jest.fn', () => {
const fn = function fn() {};
test('throw matcher error if received is spy', () => {
const spy = createSpy(jest.fn());

expect(() =>
jestExpect(fn)[returnedTimes](2),
jestExpect(spy).not[returnedTimes](2),
).toThrowErrorMatchingSnapshot();
});

Expand Down

0 comments on commit f857d30

Please sign in to comment.