From 1e479e7a76cee4a230cad9f285cc90fd12d8829c Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Wed, 29 Dec 2021 20:37:56 +0300 Subject: [PATCH 1/2] feat: last jest compatible APIs --- packages/vitest/src/index.ts | 108 ++++++++++-------- .../src/integrations/chai/jest-expect.ts | 7 ++ .../vitest/src/integrations/snapshot/chai.ts | 29 +++++ .../test/__snapshots__/snapshot.test.ts.snap | 10 ++ test/core/test/snapshot.test.ts | 36 ++++++ 5 files changed, 141 insertions(+), 49 deletions(-) diff --git a/packages/vitest/src/index.ts b/packages/vitest/src/index.ts index c267d1e9accc..b798af5be70c 100644 --- a/packages/vitest/src/index.ts +++ b/packages/vitest/src/index.ts @@ -1,3 +1,6 @@ +import type { + Plugin as PrettyFormatPlugin, +} from 'pretty-format' import type { Any, Anything, ArrayContaining, ObjectContaining, StringMatching } from './integrations/chai/jest-asymmetric-matchers' import type { MatchersObject } from './integrations/chai/types' import type { InlineConfig } from './types' @@ -39,64 +42,71 @@ declare global { hasAssertions(): void anything(): Anything any(constructor: unknown): Any + addSnapshotSerializer(plugin: PrettyFormatPlugin): void not: AsymmetricMatchersContaining } - interface JestAssertions { + interface JestAssertions { // Snapshot - toMatchSnapshot(message?: string): T - toMatchInlineSnapshot(snapshot?: string, message?: string): T - matchSnapshot(message?: string): T + toMatchSnapshot(message?: string): void + toMatchInlineSnapshot(snapshot?: string, message?: string): void + toThrowErrorMatchingSnapshot(message?: string): void + toThrowErrorMatchingInlineSnapshot(snapshot?: string, message?: string): void + matchSnapshot(message?: string): void // Jest compact - toEqual(expected: any): T - toStrictEqual(expected: any): T - toBe(expected: any): T - toMatch(expected: string | RegExp): T - toMatchObject(expected: any): T - toContain(item: any): T - toContainEqual(item: any): T - toBeTruthy(): T - toBeFalsy(): T - toBeGreaterThan(num: number): T - toBeGreaterThanOrEqual(num: number): T - toBeLessThan(num: number): T - toBeLessThanOrEqual(num: number): T - toBeNaN(): T - toBeUndefined(): T - toBeNull(): T - toBeDefined(): T - toBeInstanceOf(c: any): T - toBeCalledTimes(n: number): T - toHaveLength(l: number): T - toHaveProperty(p: string, value?: any): T - toBeCloseTo(number: number, numDigits?: number): T - toHaveBeenCalledTimes(n: number): T - toHaveBeenCalledOnce(): T - toHaveBeenCalled(): T - toBeCalled(): T - toHaveBeenCalledWith(...args: any[]): T - toBeCalledWith(...args: any[]): T - toHaveBeenNthCalledWith(n: number, ...args: any[]): T - nthCalledWith(n: number, ...args: any[]): T - toHaveBeenLastCalledWith(...args: any[]): T - lastCalledWith(...args: any[]): T - toThrow(expected?: string | RegExp): T - toThrowError(expected?: string | RegExp): T - toReturn(): T - toHaveReturned(): T - toReturnTimes(times: number): T - toHaveReturnedTimes(times: number): T - toReturnWith(value: any): T - toHaveReturnedWith(value: any): T - toHaveLastReturnedWith(value: any): T - lastReturnedWith(value: any): T - toHaveNthReturnedWith(nthCall: number, value: any): T - nthReturnedWith(nthCall: number, value: any): T + toEqual(expected: any): void + toStrictEqual(expected: any): void + toBe(expected: any): void + toMatch(expected: string | RegExp): void + toMatchObject(expected: any): void + toContain(item: any): void + toContainEqual(item: any): void + toBeTruthy(): void + toBeFalsy(): void + toBeGreaterThan(num: number): void + toBeGreaterThanOrEqual(num: number): void + toBeLessThan(num: number): void + toBeLessThanOrEqual(num: number): void + toBeNaN(): void + toBeUndefined(): void + toBeNull(): void + toBeDefined(): void + toBeInstanceOf(c: any): void + toBeCalledTimes(n: number): void + toHaveLength(l: number): void + toHaveProperty(p: string, value?: any): void + toBeCloseTo(number: number, numDigits?: number): void + toHaveBeenCalledTimes(n: number): void + toHaveBeenCalledOnce(): void + toHaveBeenCalled(): void + toBeCalled(): void + toHaveBeenCalledWith(...args: any[]): void + toBeCalledWith(...args: any[]): void + toHaveBeenNthCalledWith(n: number, ...args: any[]): void + nthCalledWith(n: number, ...args: any[]): void + toHaveBeenLastCalledWith(...args: any[]): void + lastCalledWith(...args: any[]): void + toThrow(expected?: string | RegExp): void + toThrowError(expected?: string | RegExp): void + toReturn(): void + toHaveReturned(): void + toReturnTimes(times: number): void + toHaveReturnedTimes(times: number): void + toReturnWith(value: any): void + toHaveReturnedWith(value: any): void + toHaveLastReturnedWith(value: any): void + lastReturnedWith(value: any): void + toHaveNthReturnedWith(nthCall: number, value: any): void + nthReturnedWith(nthCall: number, value: any): void } type Promisify = { - [K in keyof O]: O[K] extends (...args: infer A) => infer R ? O extends R ? Promisify : (...args: A) => Promise : O[K] + [K in keyof O]: O[K] extends (...args: infer A) => infer R + ? O extends R + ? Promisify + : (...args: A) => Promise + : O[K] } interface Assertion extends JestAssertions { diff --git a/packages/vitest/src/integrations/chai/jest-expect.ts b/packages/vitest/src/integrations/chai/jest-expect.ts index bf8d96c6b9a9..be7262fd7104 100644 --- a/packages/vitest/src/integrations/chai/jest-expect.ts +++ b/packages/vitest/src/integrations/chai/jest-expect.ts @@ -1,4 +1,5 @@ import type { EnhancedSpy } from '../jest-mock' +import { addSerializer } from '../snapshot/port/plugins' import type { ChaiPlugin } from './types' import { arrayBufferEquality, equals as asymmetricEquals, hasAsymmetric, iterableEquality, sparseArrayEquality, typeEquality } from './jest-utils' @@ -478,4 +479,10 @@ export const JestChaiExpect: ChaiPlugin = (chai, utils) => { }) }, ) + + utils.addMethod( + chai.expect, + 'addSnapshotSerializer', + addSerializer, + ) } diff --git a/packages/vitest/src/integrations/snapshot/chai.ts b/packages/vitest/src/integrations/snapshot/chai.ts index 6ad3ea0061e2..b580c4e53801 100644 --- a/packages/vitest/src/integrations/snapshot/chai.ts +++ b/packages/vitest/src/integrations/snapshot/chai.ts @@ -9,6 +9,19 @@ export function getSnapshotClient(): SnapshotClient { return _client } +const getErrorString = (expected: () => void) => { + try { + expected() + throw new Error('snapshot function didn\'t threw') + } + catch (e) { + if (e instanceof Error) + return e.message + + return e + } +} + export const SnapshotPlugin: ChaiPlugin = (chai, utils) => { for (const key of ['matchSnapshot', 'toMatchSnapshot']) { utils.addMethod( @@ -28,4 +41,20 @@ export const SnapshotPlugin: ChaiPlugin = (chai, utils) => { getSnapshotClient().assert(expected, message, true, inlineSnapshot) }, ) + utils.addMethod( + chai.Assertion.prototype, + 'toThrowErrorMatchingSnapshot', + function(this: Record, message?: string) { + const expected = utils.flag(this, 'object') + getSnapshotClient().assert(getErrorString(expected), message) + }, + ) + utils.addMethod( + chai.Assertion.prototype, + 'toThrowErrorMatchingInlineSnapshot', + function(this: Record, inlineSnapshot: string, message: string) { + const expected = utils.flag(this, 'object') + getSnapshotClient().assert(getErrorString(expected), message, true, inlineSnapshot) + }, + ) } diff --git a/test/core/test/__snapshots__/snapshot.test.ts.snap b/test/core/test/__snapshots__/snapshot.test.ts.snap index c0eb2f6586e0..b6dac51369dd 100644 --- a/test/core/test/__snapshots__/snapshot.test.ts.snap +++ b/test/core/test/__snapshots__/snapshot.test.ts.snap @@ -63,3 +63,13 @@ exports[`snapshot with big string 1`] = ` }, } `; + +exports[`throwing snapshots 1`] = `"omega"`; + +exports[`throwing snapshots 2`] = `"omega"`; + +exports[`throwing snapshots 3`] = ` +{ + "error": "omega", +} +`; diff --git a/test/core/test/snapshot.test.ts b/test/core/test/snapshot.test.ts index 96f5d1b882f1..42b9915350a2 100644 --- a/test/core/test/snapshot.test.ts +++ b/test/core/test/snapshot.test.ts @@ -28,3 +28,39 @@ test('snapshot with big string', () => { this: { is: new Set(['one', new Array(30).fill('zoo').join()]) }, }).toMatchSnapshot() }) + +test('throwing snapshots', () => { + expect(() => { + throw new Error('omega') + }).toThrowErrorMatchingSnapshot() + + expect(() => { + // eslint-disable-next-line no-throw-literal + throw 'omega' + }).toThrowErrorMatchingSnapshot() + + expect(() => { + // eslint-disable-next-line no-throw-literal + throw { error: 'omega' } + }).toThrowErrorMatchingSnapshot() +}) + +test('throwing inline snapshots', () => { + expect(() => { + throw new Error('omega') + }).toThrowErrorMatchingInlineSnapshot('"omega"') + + expect(() => { + // eslint-disable-next-line no-throw-literal + throw 'omega' + }).toThrowErrorMatchingInlineSnapshot('"omega"') + + expect(() => { + // eslint-disable-next-line no-throw-literal + throw { error: 'omega' } + }).toThrowErrorMatchingInlineSnapshot(` +{ + "error": "omega", +} +`) +}) From 3aa51cff1f8fe26bd0d065f48d4db532df265602 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Wed, 29 Dec 2021 20:40:16 +0300 Subject: [PATCH 2/2] fix: moved throwing snapshot error --- packages/vitest/src/integrations/snapshot/chai.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/vitest/src/integrations/snapshot/chai.ts b/packages/vitest/src/integrations/snapshot/chai.ts index b580c4e53801..88992c1e41aa 100644 --- a/packages/vitest/src/integrations/snapshot/chai.ts +++ b/packages/vitest/src/integrations/snapshot/chai.ts @@ -12,7 +12,6 @@ export function getSnapshotClient(): SnapshotClient { const getErrorString = (expected: () => void) => { try { expected() - throw new Error('snapshot function didn\'t threw') } catch (e) { if (e instanceof Error) @@ -20,6 +19,8 @@ const getErrorString = (expected: () => void) => { return e } + + throw new Error('snapshot function didn\'t threw') } export const SnapshotPlugin: ChaiPlugin = (chai, utils) => {