feat(expect): strip down Expect types (#20601)

This only leaves:
- documented assertions;
- asymmetric matchers;
- `resolves`/`rejects`;
- `expect.extend()`;
- `expect.getState()` with selected properties.

References #20432.
This commit is contained in:
Dmitry Gozman 2023-02-03 15:56:31 -08:00 committed by GitHub
parent df6f500730
commit e64c623e61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 52 additions and 157 deletions

View File

@ -1,111 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
// -------------- Playwright -------------
// - Matcher types are relaxed in the overrides.
//
// import type { Config } from '@jest/types';
// import type * as jestMatcherUtils from 'jest-matcher-utils';
// import { INTERNAL_MATCHER_FLAG } from './jestMatchersObject';
//
// export declare type SyncExpectationResult = {
// pass: boolean;
// message: () => string;
// };
// export declare type AsyncExpectationResult = Promise<SyncExpectationResult>;
// export declare type ExpectationResult = SyncExpectationResult | AsyncExpectationResult;
// export declare type RawMatcherFn<T extends MatcherState = MatcherState> = {
// (this: T, received: any, expected: any, options?: any): ExpectationResult;
// [INTERNAL_MATCHER_FLAG]?: boolean;
// };
// export declare type ThrowingMatcherFn = (actual: any) => void;
// export declare type PromiseMatcherFn = (actual: any) => Promise<void>;
// ---------------------------------------
export declare type Tester = (a: any, b: any) => boolean | undefined;
export declare type MatcherState = {
assertionCalls: number;
currentTestName?: string;
dontThrow?: () => void;
error?: Error;
equals: (a: unknown, b: unknown, customTesters?: Array<Tester>, strictCheck?: boolean) => boolean;
expand?: boolean;
expectedAssertionsNumber?: number | null;
expectedAssertionsNumberError?: Error;
isExpectingAssertions?: boolean;
isExpectingAssertionsError?: Error;
isNot: boolean;
promise: string;
suppressedErrors: Array<Error>;
// -------------- Playwright -------------
// - Inline type
// testPath?: Config.Path;
testPath?: string;
// ---------------------------------------
// -------------- Playwright -------------
// - Further relax type in order to not drag the dependencies.
// utils: typeof jestMatcherUtils & {
// iterableEquality: Tester;
// subsetEquality: Tester;
// };
utils: any;
// ---------------------------------------
};
// -------------- Playwright -------------
// - Matcher types are relaxed in the override.
//
// export interface AsymmetricMatcher {
// asymmetricMatch(other: unknown): boolean;
// toString(): string;
// getExpectedType?(): string;
// toAsymmetricMatcher?(): string;
// }
//
// export declare type MatchersObject<T extends MatcherState = MatcherState> = {
// [id: string]: RawMatcherFn<T>;
// };
// export declare type ExpectedAssertionsErrors = Array<{
// actual: string | number;
// error: Error;
// expected: string;
// }>;
// ---------------------------------------
// -------------- Playwright -------------
// Following are inlined in the expect override.
// interface InverseAsymmetricMatchers {
// arrayContaining(sample: Array<unknown>): AsymmetricMatcher;
// objectContaining(sample: Record<string, unknown>): AsymmetricMatcher;
// stringContaining(expected: string): AsymmetricMatcher;
// stringMatching(expected: string | RegExp): AsymmetricMatcher;
// }
// interface AsymmetricMatchers extends InverseAsymmetricMatchers {
// any(expectedObject: unknown): AsymmetricMatcher;
// anything(): AsymmetricMatcher;
// }
// interface ExtraAsymmetricMatchers {
// [id: string]: (...sample: [unknown, ...Array<unknown>]) => AsymmetricMatcher;
// }
// export declare type Expect<State extends MatcherState = MatcherState> = {
// <T = unknown>(actual: T): Matchers<void>;
// addSnapshotSerializer(serializer: unknown): void;
// assertions(numberOfAssertions: number): void;
// extend<T extends MatcherState = State>(matchers: MatchersObject<T>): void;
// extractExpectedAssertionsErrors: () => ExpectedAssertionsErrors;
// getState(): State;
// hasAssertions(): void;
// setState(state: Partial<State>): void;
// } & AsymmetricMatchers & ExtraAsymmetricMatchers & {
// not: InverseAsymmetricMatchers & ExtraAsymmetricMatchers;
// };
// ---------------------------------------
export {};

View File

@ -3755,9 +3755,6 @@ type CustomProperties<T> = ExcludeProps<T, PlaywrightTestOptions & PlaywrightWor
export type PlaywrightTestProject<TestArgs = {}, WorkerArgs = {}> = Project<PlaywrightTestOptions & CustomProperties<TestArgs>, PlaywrightWorkerOptions & CustomProperties<WorkerArgs>>;
export type PlaywrightTestConfig<TestArgs = {}, WorkerArgs = {}> = Config<PlaywrightTestOptions & CustomProperties<TestArgs>, PlaywrightWorkerOptions & CustomProperties<WorkerArgs>>;
import type * as expectType from './expect-types';
import type { Suite } from './testReporter';
type AsymmetricMatcher = Record<string, any>;
type AsymmetricMatchers = {
@ -3770,13 +3767,6 @@ type AsymmetricMatchers = {
stringMatching(sample: string | RegExp): AsymmetricMatcher;
}
type Inverse<Matchers> = {
/**
* Inverse next matcher. If you know how to test something, `.not` lets you test its opposite.
*/
not: Matchers;
};
type IfAny<T, Y, N> = 0 extends (1 & T) ? Y : N;
type ExtraMatchers<T, Type, Matchers> = T extends Type ? Matchers : IfAny<T, Matchers, {}>;
@ -4222,16 +4212,6 @@ type MakeMatchers<R, T> = BaseMatchers<R, T> & {
toPass(options?: { timeout?: number, intervals?: number[] }): Promise<void>;
}>;
type BaseExpect = {
// Removed following methods because they rely on a test-runner integration from Jest which we don't support:
// assertions(numberOfAssertions: number): void;
// extractExpectedAssertionsErrors(): ExpectedAssertionsErrors;
// hasAssertions(): void;
extend(matchers: any): void;
getState(): expectType.MatcherState;
setState(state: Partial<expectType.MatcherState>): void;
}
export type Expect = {
<T = unknown>(actual: T, messageOrOptions?: string | { message?: string }): MakeMatchers<void, T>;
soft: <T = unknown>(actual: T, messageOrOptions?: string | { message?: string }) => MakeMatchers<void, T>;
@ -4241,9 +4221,15 @@ export type Expect = {
*/
not: BaseMatchers<Promise<void>, T>;
};
} & BaseExpect &
AsymmetricMatchers &
Inverse<Omit<AsymmetricMatchers, 'any' | 'anything'>>;
extend(matchers: any): void;
getState(): {
expand?: boolean;
isNot: boolean;
promise: string;
utils: any;
};
not: Omit<AsymmetricMatchers, 'any' | 'anything'>;
} & AsymmetricMatchers;
type Awaited<T> = T extends PromiseLike<infer U> ? U : T;

View File

@ -159,6 +159,23 @@ test('should work with generic matchers', async ({ runTSC }) => {
expect({}).toStrictEqual({});
expect(() => { throw new Error('Something bad'); }).toThrow('something');
expect(() => { throw new Error('Something bad'); }).toThrowError('something');
expect(['Bob', 'Eve']).not.toEqual(expect.arrayContaining(['Alice', 'Bob']));
expect({}).toEqual(expect.anything());
expect({ sum: 0.1 + 0.2 }).toEqual({ sum: expect.closeTo(0.3, 5) });
class Cat {}
expect(new Cat()).toEqual(expect.any(Cat));
expect({ x: 2, y: 3, foo: 'bar' }).toEqual(expect.objectContaining({
x: expect.any(Number),
y: expect.any(Number),
}));
expect('abc').toEqual(expect.stringContaining('bc'));
expect(['Alicia', 'Roberto', 'Evelina']).toEqual(
expect.arrayContaining([
expect.stringMatching(/^Alic/),
expect.stringMatching('Roberto'),
]),
);
`
});
expect(result.exitCode).toBe(0);
@ -200,6 +217,23 @@ test('should compile generic matchers', async ({ runTSC }) => {
expect(() => { throw new Error('Something bad'); }).toThrowError('something');
expect(() => { throw new Error('Something bad'); }).toThrowError();
expect(['Bob', 'Eve']).not.toEqual(expect.arrayContaining(['Alice', 'Bob']));
expect({}).toEqual(expect.anything());
expect({ sum: 0.1 + 0.2 }).toEqual({ sum: expect.closeTo(0.3, 5) });
class Cat {}
expect(new Cat()).toEqual(expect.any(Cat));
expect({ x: 2, y: 3, foo: 'bar' }).toEqual(expect.objectContaining({
x: expect.any(Number),
y: expect.any(Number),
}));
expect('abc').toEqual(expect.stringContaining('bc'));
expect(['Alicia', 'Roberto', 'Evelina']).toEqual(
expect.arrayContaining([
expect.stringMatching(/^Alic/),
expect.stringMatching('Roberto'),
]),
);
// @ts-expect-error
expect(42).toBe(123, 456);
// @ts-expect-error

View File

@ -261,9 +261,6 @@ type CustomProperties<T> = ExcludeProps<T, PlaywrightTestOptions & PlaywrightWor
export type PlaywrightTestProject<TestArgs = {}, WorkerArgs = {}> = Project<PlaywrightTestOptions & CustomProperties<TestArgs>, PlaywrightWorkerOptions & CustomProperties<WorkerArgs>>;
export type PlaywrightTestConfig<TestArgs = {}, WorkerArgs = {}> = Config<PlaywrightTestOptions & CustomProperties<TestArgs>, PlaywrightWorkerOptions & CustomProperties<WorkerArgs>>;
import type * as expectType from './expect-types';
import type { Suite } from './testReporter';
type AsymmetricMatcher = Record<string, any>;
type AsymmetricMatchers = {
@ -276,13 +273,6 @@ type AsymmetricMatchers = {
stringMatching(sample: string | RegExp): AsymmetricMatcher;
}
type Inverse<Matchers> = {
/**
* Inverse next matcher. If you know how to test something, `.not` lets you test its opposite.
*/
not: Matchers;
};
type IfAny<T, Y, N> = 0 extends (1 & T) ? Y : N;
type ExtraMatchers<T, Type, Matchers> = T extends Type ? Matchers : IfAny<T, Matchers, {}>;
@ -342,16 +332,6 @@ type MakeMatchers<R, T> = BaseMatchers<R, T> & {
toPass(options?: { timeout?: number, intervals?: number[] }): Promise<void>;
}>;
type BaseExpect = {
// Removed following methods because they rely on a test-runner integration from Jest which we don't support:
// assertions(numberOfAssertions: number): void;
// extractExpectedAssertionsErrors(): ExpectedAssertionsErrors;
// hasAssertions(): void;
extend(matchers: any): void;
getState(): expectType.MatcherState;
setState(state: Partial<expectType.MatcherState>): void;
}
export type Expect = {
<T = unknown>(actual: T, messageOrOptions?: string | { message?: string }): MakeMatchers<void, T>;
soft: <T = unknown>(actual: T, messageOrOptions?: string | { message?: string }) => MakeMatchers<void, T>;
@ -361,9 +341,15 @@ export type Expect = {
*/
not: BaseMatchers<Promise<void>, T>;
};
} & BaseExpect &
AsymmetricMatchers &
Inverse<Omit<AsymmetricMatchers, 'any' | 'anything'>>;
extend(matchers: any): void;
getState(): {
expand?: boolean;
isNot: boolean;
promise: string;
utils: any;
};
not: Omit<AsymmetricMatchers, 'any' | 'anything'>;
} & AsymmetricMatchers;
type Awaited<T> = T extends PromiseLike<infer U> ? U : T;