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

fix(vitest): return detailed error when using toHaveReturnedWith #2163

Merged
merged 9 commits into from Oct 19, 2022
36 changes: 31 additions & 5 deletions packages/vitest/src/integrations/chai/jest-expect.ts
Expand Up @@ -394,6 +394,20 @@ export const JestChaiExpect: ChaiPlugin = (chai, utils) => {
msg += c.gray(`\n\nNumber of calls: ${c.bold(spy.mock.calls.length)}\n`)
return msg
}
const formatReturns = (spy: EnhancedSpy, msg: string, actualReturn?: any) => {
msg += c.gray(`\n\nReceived: \n${spy.mock.results.map((callReturn, i) => {
let methodCall = c.bold(` ${ordinalOf(i + 1)} ${spy.getMockName()} call return:\n\n`)
if (actualReturn)
methodCall += unifiedDiff(stringify(callReturn.value), stringify(actualReturn), { showLegend: false })
else
methodCall += stringify(callReturn).split('\n').map(line => ` ${line}`).join('\n')

methodCall += '\n'
return methodCall
}).join('\n')}`)
msg += c.gray(`\n\nNumber of calls: ${c.bold(spy.mock.calls.length)}\n`)
return msg
}
def(['toHaveBeenCalledTimes', 'toBeCalledTimes'], function (number: number) {
const spy = getSpy(this)
const spyName = spy.getMockName()
Expand Down Expand Up @@ -589,12 +603,24 @@ export const JestChaiExpect: ChaiPlugin = (chai, utils) => {
const spy = getSpy(this)
const spyName = spy.getMockName()
const pass = spy.mock.results.some(({ type, value: result }) => type === 'return' && jestEquals(value, result))
this.assert(
pass,
`expected "${spyName}" to be successfully called with #{exp}`,
`expected "${spyName}" to not be successfully called with #{exp}`,
value,
const isNot = utils.flag(this, 'negate') as boolean

let msg = utils.getMessage(
this,
[
pass,
`expected "${spyName}" to return with: #{exp} at least once`,
`expected "${spyName}" to not return with: #{exp}`,
value,
],
)

if ((pass && isNot) || (!pass && !isNot)) {
msg = formatReturns(spy, msg, value)
const err = new Error(msg)
err.name = 'AssertionError'
throw err
}
})
def(['toHaveLastReturnedWith', 'lastReturnedWith'], function (value: any) {
const spy = getSpy(this)
Expand Down
79 changes: 79 additions & 0 deletions test/core/test/__snapshots__/mocked.test.ts.snap
@@ -0,0 +1,79 @@
// Vitest Snapshot v1

exports[`mocked function which fails on toReturnWith > just one call 1`] = `
"expected \\"spy\\" to return with: 2 at least once

Received:
 1st spy call return:

 2
1


Number of calls: 1
"
`;

exports[`mocked function which fails on toReturnWith > multi calls 1`] = `
"expected \\"spy\\" to return with: 2 at least once

Received:
 1st spy call return:

 2
1

 2nd spy call return:

 2
1

 3rd spy call return:

 2
1


Number of calls: 3
"
`;

exports[`mocked function which fails on toReturnWith > oject type 1`] = `
"expected \\"spy\\" to return with: { a: '4' } at least once

Received:
 1st spy call return:

 Object {
- \\"a\\": \\"4\\",
+ \\"a\\": \\"1\\",
}

 2nd spy call return:

 Object {
- \\"a\\": \\"4\\",
+ \\"a\\": \\"1\\",
}

 3rd spy call return:

 Object {
- \\"a\\": \\"4\\",
+ \\"a\\": \\"1\\",
}


Number of calls: 3
"
`;

exports[`mocked function which fails on toReturnWith > zero call 1`] = `
"expected \\"spy\\" to return with: 2 at least once

Received:


Number of calls: 0
"
`;
29 changes: 29 additions & 0 deletions test/core/test/mocked.test.ts
Expand Up @@ -134,6 +134,35 @@ test('async functions should be mocked', () => {
expect(asyncFunc()).resolves.toBe('foo')
})

describe('mocked function which fails on toReturnWith', () => {
test('zero call', () => {
const mock = vi.fn(() => 1)
expect(() => expect(mock).toReturnWith(2)).toThrowErrorMatchingSnapshot()
})

test('just one call', () => {
const mock = vi.fn(() => 1)
mock()
expect(() => expect(mock).toReturnWith(2)).toThrowErrorMatchingSnapshot()
})

test('multi calls', () => {
const mock = vi.fn(() => 1)
mock()
mock()
mock()
expect(() => expect(mock).toReturnWith(2)).toThrowErrorMatchingSnapshot()
})

test('oject type', () => {
const mock = vi.fn(() => { return { a: '1' } })
mock()
mock()
mock()
expect(() => expect(mock).toReturnWith({ a: '4' })).toThrowErrorMatchingSnapshot()
})
})

// This is here because mocking streams previously caused some problems (#1671).
test('streams', () => {
expect(exportedStream).toBeDefined()
Expand Down