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: Throw matcher error when received cannot be jasmine spy #8747

Merged
merged 3 commits into from Jul 25, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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