UNPKG

@inngest/test

Version:
323 lines (322 loc) 12.7 kB
interface MockResultReturn<T> { type: "return"; /** * The value that was returned from the function. If function returned a Promise, then this will be a resolved value. */ value: T; } interface MockResultIncomplete { type: "incomplete"; value: undefined; } interface MockResultThrow { type: "throw"; /** * An error that was thrown during function execution. */ value: any; } interface MockSettledResultFulfilled<T> { type: "fulfilled"; value: T; } interface MockSettledResultRejected { type: "rejected"; value: any; } export type MockResult<T> = MockResultReturn<T> | MockResultThrow | MockResultIncomplete; export type MockSettledResult<T> = MockSettledResultFulfilled<T> | MockSettledResultRejected; export interface MockContext<T extends Procedure> { /** * This is an array containing all arguments for each call. One item of the array is the arguments of that call. * * @example * const fn = vi.fn() * * fn('arg1', 'arg2') * fn('arg3') * * fn.mock.calls === [ * ['arg1', 'arg2'], // first call * ['arg3'], // second call * ] */ calls: Parameters<T>[]; /** * This is an array containing all instances that were instantiated when mock was called with a `new` keyword. Note that this is an actual context (`this`) of the function, not a return value. */ instances: ReturnType<T>[]; /** * An array of `this` values that were used during each call to the mock function. */ contexts: ThisParameterType<T>[]; /** * The order of mock's execution. This returns an array of numbers which are shared between all defined mocks. * * @example * const fn1 = vi.fn() * const fn2 = vi.fn() * * fn1() * fn2() * fn1() * * fn1.mock.invocationCallOrder === [1, 3] * fn2.mock.invocationCallOrder === [2] */ invocationCallOrder: number[]; /** * This is an array containing all values that were `returned` from the function. * * The `value` property contains the returned value or thrown error. If the function returned a `Promise`, then `result` will always be `'return'` even if the promise was rejected. * * @example * const fn = vi.fn() * .mockReturnValueOnce('result') * .mockImplementationOnce(() => { throw new Error('thrown error') }) * * const result = fn() * * try { * fn() * } * catch {} * * fn.mock.results === [ * { * type: 'return', * value: 'result', * }, * { * type: 'throw', * value: Error, * }, * ] */ results: MockResult<ReturnType<T>>[]; /** * An array containing all values that were `resolved` or `rejected` from the function. * * This array will be empty if the function was never resolved or rejected. * * @example * const fn = vi.fn().mockResolvedValueOnce('result') * * const result = fn() * * fn.mock.settledResults === [] * fn.mock.results === [ * { * type: 'return', * value: Promise<'result'>, * }, * ] * * await result * * fn.mock.settledResults === [ * { * type: 'fulfilled', * value: 'result', * }, * ] */ settledResults: MockSettledResult<Awaited<ReturnType<T>>>[]; /** * This contains the arguments of the last call. If spy wasn't called, will return `undefined`. */ lastCall: Parameters<T> | undefined; } type Procedure = (...args: any[]) => any; type NormalizedPrecedure<T extends Procedure> = (...args: Parameters<T>) => ReturnType<T>; type Methods<T> = keyof { [K in keyof T as T[K] extends Procedure ? K : never]: T[K]; }; type Properties<T> = { [K in keyof T]: T[K] extends Procedure ? never : K; }[keyof T] & (string | symbol); type Classes<T> = { [K in keyof T]: T[K] extends new (...args: any[]) => any ? K : never; }[keyof T] & (string | symbol); export interface MockInstance<T extends Procedure = Procedure> { /** * Use it to return the name given to mock with method `.mockName(name)`. */ getMockName(): string; /** * Sets internal mock name. Useful to see the name of the mock if an assertion fails. */ mockName(n: string): this; /** * Current context of the mock. It stores information about all invocation calls, instances, and results. */ mock: MockContext<T>; /** * Clears all information about every call. After calling it, all properties on `.mock` will return an empty state. This method does not reset implementations. * * It is useful if you need to clean up mock between different assertions. */ mockClear(): this; /** * Does what `mockClear` does and makes inner implementation an empty function (returning `undefined` when invoked). This also resets all "once" implementations. * * This is useful when you want to completely reset a mock to the default state. */ mockReset(): this; /** * Does what `mockReset` does and restores inner implementation to the original function. * * Note that restoring mock from `vi.fn()` will set implementation to an empty function that returns `undefined`. Restoring a `vi.fn(impl)` will restore implementation to `impl`. */ mockRestore(): void; /** * Returns current mock implementation if there is one. * * If mock was created with `vi.fn`, it will consider passed down method as a mock implementation. * * If mock was created with `vi.spyOn`, it will return `undefined` unless a custom implementation was provided. */ getMockImplementation(): NormalizedPrecedure<T> | undefined; /** * Accepts a function that will be used as an implementation of the mock. * @example * const increment = vi.fn().mockImplementation(count => count + 1); * expect(increment(3)).toBe(4); */ mockImplementation(fn: NormalizedPrecedure<T>): this; /** * Accepts a function that will be used as a mock implementation during the next call. Can be chained so that multiple function calls produce different results. * @example * const fn = vi.fn(count => count).mockImplementationOnce(count => count + 1); * expect(fn(3)).toBe(4); * expect(fn(3)).toBe(3); */ mockImplementationOnce(fn: NormalizedPrecedure<T>): this; /** * Overrides the original mock implementation temporarily while the callback is being executed. * @example * const myMockFn = vi.fn(() => 'original') * * myMockFn.withImplementation(() => 'temp', () => { * myMockFn() // 'temp' * }) * * myMockFn() // 'original' */ withImplementation<T2>(fn: NormalizedPrecedure<T>, cb: () => T2): T2 extends Promise<unknown> ? Promise<this> : this; /** * Use this if you need to return `this` context from the method without invoking actual implementation. */ mockReturnThis(): this; /** * Accepts a value that will be returned whenever the mock function is called. */ mockReturnValue(obj: ReturnType<T>): this; /** * Accepts a value that will be returned during the next function call. If chained, every consecutive call will return the specified value. * * When there are no more `mockReturnValueOnce` values to use, mock will fallback to the previously defined implementation if there is one. * @example * const myMockFn = vi * .fn() * .mockReturnValue('default') * .mockReturnValueOnce('first call') * .mockReturnValueOnce('second call') * * // 'first call', 'second call', 'default' * console.log(myMockFn(), myMockFn(), myMockFn()) */ mockReturnValueOnce(obj: ReturnType<T>): this; /** * Accepts a value that will be resolved when async function is called. * @example * const asyncMock = vi.fn().mockResolvedValue(42) * asyncMock() // Promise<42> */ mockResolvedValue(obj: Awaited<ReturnType<T>>): this; /** * Accepts a value that will be resolved during the next function call. If chained, every consecutive call will resolve specified value. * @example * const myMockFn = vi * .fn() * .mockResolvedValue('default') * .mockResolvedValueOnce('first call') * .mockResolvedValueOnce('second call') * * // Promise<'first call'>, Promise<'second call'>, Promise<'default'> * console.log(myMockFn(), myMockFn(), myMockFn()) */ mockResolvedValueOnce(obj: Awaited<ReturnType<T>>): this; /** * Accepts an error that will be rejected when async function is called. * @example * const asyncMock = vi.fn().mockRejectedValue(new Error('Async error')) * await asyncMock() // throws 'Async error' */ mockRejectedValue(obj: any): this; /** * Accepts a value that will be rejected during the next function call. If chained, every consecutive call will reject specified value. * @example * const asyncMock = vi * .fn() * .mockResolvedValueOnce('first call') * .mockRejectedValueOnce(new Error('Async error')) * * await asyncMock() // first call * await asyncMock() // throws "Async error" */ mockRejectedValueOnce(obj: any): this; } export interface Mock<T extends Procedure = Procedure> extends MockInstance<T> { new (...args: Parameters<T>): ReturnType<T>; (...args: Parameters<T>): ReturnType<T>; } type PartialMaybePromise<T> = T extends Promise<Awaited<T>> ? Promise<Partial<Awaited<T>>> : Partial<T>; export interface PartialMock<T extends Procedure = Procedure> extends MockInstance<(...args: Parameters<T>) => PartialMaybePromise<ReturnType<T>>> { new (...args: Parameters<T>): ReturnType<T>; (...args: Parameters<T>): ReturnType<T>; } export type MaybeMockedConstructor<T> = T extends new (...args: Array<any>) => infer R ? Mock<(...args: ConstructorParameters<T>) => R> : T; export type MockedFunction<T extends Procedure> = Mock<T> & { [K in keyof T]: T[K]; }; export type PartiallyMockedFunction<T extends Procedure> = PartialMock<T> & { [K in keyof T]: T[K]; }; export type MockedFunctionDeep<T extends Procedure> = Mock<T> & MockedObjectDeep<T>; export type PartiallyMockedFunctionDeep<T extends Procedure> = PartialMock<T> & MockedObjectDeep<T>; export type MockedObject<T> = MaybeMockedConstructor<T> & { [K in Methods<T>]: T[K] extends Procedure ? MockedFunction<T[K]> : T[K]; } & { [K in Properties<T>]: T[K]; }; export type MockedObjectDeep<T> = MaybeMockedConstructor<T> & { [K in Methods<T>]: T[K] extends Procedure ? MockedFunctionDeep<T[K]> : T[K]; } & { [K in Properties<T>]: MaybeMockedDeep<T[K]>; }; export type MaybeMockedDeep<T> = T extends Procedure ? MockedFunctionDeep<T> : T extends object ? MockedObjectDeep<T> : T; export type MaybePartiallyMockedDeep<T> = T extends Procedure ? PartiallyMockedFunctionDeep<T> : T extends object ? MockedObjectDeep<T> : T; export type MaybeMocked<T> = T extends Procedure ? MockedFunction<T> : T extends object ? MockedObject<T> : T; export type MaybePartiallyMocked<T> = T extends Procedure ? PartiallyMockedFunction<T> : T extends object ? MockedObject<T> : T; interface Constructable { new (...args: any[]): any; } export type MockedClass<T extends Constructable> = MockInstance<(...args: ConstructorParameters<T>) => InstanceType<T>> & { prototype: T extends { prototype: any; } ? Mocked<T["prototype"]> : never; } & T; export type Mocked<T> = { [P in keyof T]: T[P] extends Procedure ? MockInstance<T[P]> : T[P] extends Constructable ? MockedClass<T[P]> : T[P]; } & T; export declare const mocks: Set<MockInstance>; export declare function isMockFunction(fn: any): fn is MockInstance; export declare function spyOn<T, S extends Properties<Required<T>>>(obj: T, methodName: S, accessType: "get"): MockInstance<() => T[S]>; export declare function spyOn<T, G extends Properties<Required<T>>>(obj: T, methodName: G, accessType: "set"): MockInstance<(arg: T[G]) => void>; export declare function spyOn<T, M extends Classes<Required<T>> | Methods<Required<T>>>(obj: T, methodName: M): Required<T>[M] extends { new (...args: infer A): infer R; } ? MockInstance<(this: R, ...args: A) => R> : T[M] extends Procedure ? MockInstance<T[M]> : never; export declare function fn<T extends Procedure = Procedure>(implementation?: T): Mock<T>; export declare const mockAny: <T>(obj: T) => T; export {};