Skip to content

Commit

Permalink
feat: last jest compatible APIs (#365)
Browse files Browse the repository at this point in the history
  • Loading branch information
sheremet-va committed Dec 29, 2021
1 parent 4e3e004 commit c417945
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 49 deletions.
108 changes: 59 additions & 49 deletions 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'
Expand Down Expand Up @@ -39,64 +42,71 @@ declare global {
hasAssertions(): void
anything(): Anything
any(constructor: unknown): Any
addSnapshotSerializer(plugin: PrettyFormatPlugin): void
not: AsymmetricMatchersContaining
}

interface JestAssertions<T = void> {
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<O> = {
[K in keyof O]: O[K] extends (...args: infer A) => infer R ? O extends R ? Promisify<O[K]> : (...args: A) => Promise<R> : O[K]
[K in keyof O]: O[K] extends (...args: infer A) => infer R
? O extends R
? Promisify<O[K]>
: (...args: A) => Promise<R>
: O[K]
}

interface Assertion extends JestAssertions {
Expand Down
7 changes: 7 additions & 0 deletions 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'

Expand Down Expand Up @@ -478,4 +479,10 @@ export const JestChaiExpect: ChaiPlugin = (chai, utils) => {
})
},
)

utils.addMethod(
chai.expect,
'addSnapshotSerializer',
addSerializer,
)
}
30 changes: 30 additions & 0 deletions packages/vitest/src/integrations/snapshot/chai.ts
Expand Up @@ -9,6 +9,20 @@ export function getSnapshotClient(): SnapshotClient {
return _client
}

const getErrorString = (expected: () => void) => {
try {
expected()
}
catch (e) {
if (e instanceof Error)
return e.message

return e
}

throw new Error('snapshot function didn\'t threw')
}

export const SnapshotPlugin: ChaiPlugin = (chai, utils) => {
for (const key of ['matchSnapshot', 'toMatchSnapshot']) {
utils.addMethod(
Expand All @@ -28,4 +42,20 @@ export const SnapshotPlugin: ChaiPlugin = (chai, utils) => {
getSnapshotClient().assert(expected, message, true, inlineSnapshot)
},
)
utils.addMethod(
chai.Assertion.prototype,
'toThrowErrorMatchingSnapshot',
function(this: Record<string, unknown>, message?: string) {
const expected = utils.flag(this, 'object')
getSnapshotClient().assert(getErrorString(expected), message)
},
)
utils.addMethod(
chai.Assertion.prototype,
'toThrowErrorMatchingInlineSnapshot',
function(this: Record<string, unknown>, inlineSnapshot: string, message: string) {
const expected = utils.flag(this, 'object')
getSnapshotClient().assert(getErrorString(expected), message, true, inlineSnapshot)
},
)
}
10 changes: 10 additions & 0 deletions test/core/test/__snapshots__/snapshot.test.ts.snap
Expand Up @@ -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",
}
`;
36 changes: 36 additions & 0 deletions test/core/test/snapshot.test.ts
Expand Up @@ -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",
}
`)
})

0 comments on commit c417945

Please sign in to comment.