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: apply serializer to Error instance for thrown snapshot #4396

2 changes: 1 addition & 1 deletion packages/vitest/src/integrations/snapshot/chai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function getErrorString(expected: () => void | Error, promise: string | undefine
expected()
}
catch (e) {
return getErrorMessage(e)
return e
}

throw new Error('snapshot function didn\'t throw')
Expand Down
16 changes: 8 additions & 8 deletions test/core/test/__snapshots__/mocked.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

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

Received:

Expand All @@ -12,11 +12,11 @@ Received:


Number of calls: 1
"
]
`;

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

Received:

Expand All @@ -37,11 +37,11 @@ Received:


Number of calls: 3
"
]
`;

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

Received:

Expand All @@ -68,16 +68,16 @@ Received:


Number of calls: 3
"
]
`;

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

Received:



Number of calls: 0
"
]
`;
2 changes: 1 addition & 1 deletion test/core/test/__snapshots__/snapshot.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ exports[`single line snapshot 6`] = `"some string'"`;

exports[`single line snapshot 7`] = `"some 'string'"`;

exports[`throwing 1`] = `"omega"`;
exports[`throwing 1`] = `[Error: omega]`;

exports[`throwing 2`] = `"omega"`;

Expand Down
10 changes: 5 additions & 5 deletions test/core/test/jest-expect.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ describe('jest-expect', () => {
}).toEqual({
sum: expect.closeTo(0.4),
})
}).toThrowErrorMatchingInlineSnapshot(`"expected { sum: 0.30000000000000004 } to deeply equal { sum: CloseTo{ …(4) } }"`)
}).toThrowErrorMatchingInlineSnapshot(`[AssertionError: expected { sum: 0.30000000000000004 } to deeply equal { sum: CloseTo{ …(4) } }]`)

// TODO: support set
// expect(new Set(['bar'])).not.toEqual(new Set([expect.stringContaining('zoo')]))
Expand Down Expand Up @@ -302,14 +302,14 @@ describe('jest-expect', () => {

expect(() => {
expect(complex).toHaveProperty('a-b', false)
}).toThrowErrorMatchingInlineSnapshot('"expected { \'0\': \'zero\', foo: 1, …(4) } to have property "a-b" with value false"')
}).toThrowErrorMatchingInlineSnapshot(`[AssertionError: expected { '0': 'zero', foo: 1, …(4) } to have property "a-b" with value false]`)

expect(() => {
const x = { a: { b: { c: 1 } } }
const y = { a: { b: { c: 2 } } }
Object.freeze(x.a)
expect(x).toEqual(y)
}).toThrowErrorMatchingInlineSnapshot(`"expected { a: { b: { c: 1 } } } to deeply equal { a: { b: { c: 2 } } }"`)
}).toThrowErrorMatchingInlineSnapshot(`[AssertionError: expected { a: { b: { c: 1 } } } to deeply equal { a: { b: { c: 2 } } }]`)
})

it('assertions', () => {
Expand Down Expand Up @@ -406,14 +406,14 @@ describe('jest-expect', () => {
expect(() => {
expect(() => {
}).toThrow(Error)
}).toThrowErrorMatchingInlineSnapshot('"expected function to throw an error, but it didn\'t"')
}).toThrowErrorMatchingInlineSnapshot(`[AssertionError: expected function to throw an error, but it didn't]`)
})

it('async wasn\'t awaited', () => {
expect(() => {
expect(async () => {
}).toThrow(Error)
}).toThrowErrorMatchingInlineSnapshot('"expected function to throw an error, but it didn\'t"')
}).toThrowErrorMatchingInlineSnapshot(`[AssertionError: expected function to throw an error, but it didn't]`)
})
})
})
Expand Down
10 changes: 5 additions & 5 deletions test/core/test/nested-test.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,28 @@ import { describe, expect, test } from 'vitest'
test('nested test should throw error', () => {
expect(() => {
test('test inside test', () => {})
}).toThrowErrorMatchingInlineSnapshot(`"Nested tests are not allowed"`)
}).toThrowErrorMatchingInlineSnapshot(`[Error: Nested tests are not allowed]`)

expect(() => {
test.each([1, 2, 3])('test.each inside test %d', () => {})
}).toThrowErrorMatchingInlineSnapshot(`"Nested tests are not allowed"`)
}).toThrowErrorMatchingInlineSnapshot(`[Error: Nested tests are not allowed]`)

expect(() => {
test.skipIf(false)('test.skipIf inside test', () => {})
}).toThrowErrorMatchingInlineSnapshot(`"Nested tests are not allowed"`)
}).toThrowErrorMatchingInlineSnapshot(`[Error: Nested tests are not allowed]`)
})

describe('parallel tests', () => {
test.concurrent('parallel test 1 with nested test', () => {
expect(() => {
test('test inside test', () => {})
}).toThrowErrorMatchingInlineSnapshot(`"Nested tests are not allowed"`)
}).toThrowErrorMatchingInlineSnapshot(`[Error: Nested tests are not allowed]`)
})
test.concurrent('parallel test 2 without nested test', () => {})
test.concurrent('parallel test 3 without nested test', () => {})
test.concurrent('parallel test 4 with nested test', () => {
expect(() => {
test('test inside test', () => {})
}).toThrowErrorMatchingInlineSnapshot(`"Nested tests are not allowed"`)
}).toThrowErrorMatchingInlineSnapshot(`[Error: Nested tests are not allowed]`)
})
})
64 changes: 63 additions & 1 deletion test/core/test/snapshot-inline.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,72 @@ test('template literal', () => {
`)
})

test('custom serializer against thrown instance', async () => {
class ErrorWithDetails extends Error {
readonly details: unknown

constructor(message: string, options: ErrorOptions & { details: unknown }) {
super(message, options)
this.details = options.details
}
}

// without custom serializer
const error = new ErrorWithDetails('Example', { details: 'interesting detail' })
expect(error).toMatchInlineSnapshot(`[Error: Example]`)
expect(() => {
throw error
}).toThrowErrorMatchingInlineSnapshot(`[Error: Example]`)

// with custom serializer
expect.addSnapshotSerializer({
serialize(val, config, indentation, depth, refs, printer) {
const error = val as ErrorWithDetails
return `${error.message}: ${printer(error.details, config, indentation, depth, refs)}`
},
test(val) {
return val && val instanceof ErrorWithDetails
},
})
expect(() => {
throw error
}).toThrowErrorMatchingInlineSnapshot(`Example: "interesting detail"`) // serializer applied
expect(error).toMatchInlineSnapshot(`Example: "interesting detail"`) // serializer applied

//
// workaround 1 (for async error)
// by unwrapping with `rejects, it can assert error instance via `toMatchInlineSnapshot`
//
await expect(async () => {
throw error
}).rejects.toMatchInlineSnapshot(`Example: "interesting detail"`)

//
// workaround 2
// create a utility to catch error and use it to assert snapshot via `toMatchInlineSnapshot`
//
function wrapError<T>(f: () => T): { success: true; data: T } | { success: false; error: unknown } {
try {
return { success: true, data: f() }
}
catch (error) {
return { success: false, error }
}
}
expect(wrapError(() => {
throw error
})).toMatchInlineSnapshot(`
{
"error": Example: "interesting detail",
"success": false,
}
`)
})

test('throwing inline snapshots', async () => {
expect(() => {
throw new Error('omega')
}).toThrowErrorMatchingInlineSnapshot('"omega"')
}).toThrowErrorMatchingInlineSnapshot(`[Error: omega]`)

expect(() => {
// eslint-disable-next-line no-throw-literal
Expand Down