Add type tests for all `expect` matchers (#11949)

This commit is contained in:
mrazauskas 2021-10-15 14:06:30 +03:00 committed by GitHub
parent 46c9c13811
commit ae1f04bf0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 412 additions and 107 deletions

View File

@ -4,7 +4,8 @@
### Fixes
- `[jest-runtime]` Ensure absolute paths can be resolved within test modules ([11943](https://github.com/facebook/jest/pull/11943))
- `[expect]` Tweak and improve types ([#11949](https://github.com/facebook/jest/pull/11949))
- `[jest-runtime]` Ensure absolute paths can be resolved within test modules ([#11943](https://github.com/facebook/jest/pull/11943))
- `[jest-runtime]` Fix `instanceof` for `ModernFakeTimers` and `LegacyFakeTimers` methods ([#11946](https://github.com/facebook/jest/pull/11946))
### Chore & Maintenance

View File

@ -37,6 +37,7 @@ describe('.hasAssertions()', () => {
it('throws if expected is not undefined', () => {
jestExpect(() => {
// @ts-expect-error
jestExpect.hasAssertions(2);
}).toThrowErrorMatchingSnapshot();
});

View File

@ -431,7 +431,7 @@ const expectExport = expect as Expect;
declare namespace expectExport {
export type MatcherState = JestMatcherState;
export interface Matchers<R> extends MatcherInterface<R> {}
export interface Matchers<R, T> extends MatcherInterface<R, T> {}
}
export = expectExport;

View File

@ -98,15 +98,14 @@ export const setMatchers = <State extends MatcherState = MatcherState>(
}
}
expect[key] = (...sample: [unknown, ...Array<unknown>]) =>
new CustomMatcher(false, ...sample);
if (!expect.not) {
throw new Error(
'`expect.not` is not defined - please report this bug to https://github.com/facebook/jest',
);
}
expect.not[key] = (...sample: [unknown, ...Array<unknown>]) =>
new CustomMatcher(true, ...sample);
Object.defineProperty(expect, key, {
value: (...sample: [unknown, ...Array<unknown>]) =>
new CustomMatcher(false, ...sample),
});
Object.defineProperty(expect.not, key, {
value: (...sample: [unknown, ...Array<unknown>]) =>
new CustomMatcher(true, ...sample),
});
}
});

View File

@ -6,8 +6,6 @@
*
*/
/* eslint-disable local/ban-types-eventually */
import type {Config} from '@jest/types';
import type * as jestMatcherUtils from 'jest-matcher-utils';
import {INTERNAL_MATCHER_FLAG} from './jestMatchersObject';
@ -72,26 +70,17 @@ export type ExpectedAssertionsErrors = Array<{
expected: string;
}>;
interface InverseAsymmetricMatchers {
interface AsymmetricMatchers {
any(sample: unknown): AsymmetricMatcher;
anything(): AsymmetricMatcher;
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;
}
// Should use interface merging somehow
interface ExtraAsymmetricMatchers {
// at least one argument is needed - that's probably wrong. Should allow `expect.toBeDivisibleBy2()` like `expect.anything()`
[id: string]: (...sample: [unknown, ...Array<unknown>]) => AsymmetricMatcher;
stringContaining(sample: string): AsymmetricMatcher;
stringMatching(sample: string | RegExp): AsymmetricMatcher;
}
export type Expect<State extends MatcherState = MatcherState> = {
<T = unknown>(actual: T): Matchers<void>;
<T = unknown>(actual: T): Matchers<void, T>;
// TODO: this is added by test runners, not `expect` itself
addSnapshotSerializer(serializer: unknown): void;
assertions(numberOfAssertions: number): void;
@ -101,43 +90,42 @@ export type Expect<State extends MatcherState = MatcherState> = {
getState(): State;
hasAssertions(): void;
setState(state: Partial<State>): void;
} & AsymmetricMatchers &
ExtraAsymmetricMatchers & {
not: InverseAsymmetricMatchers & ExtraAsymmetricMatchers;
} & AsymmetricMatchers & {
not: Omit<AsymmetricMatchers, 'any' | 'anything'>;
};
// This is a copy from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/de6730f4463cba69904698035fafd906a72b9664/types/jest/index.d.ts#L570-L817
export interface Matchers<R> {
export interface Matchers<R, T = unknown> {
/**
* Ensures the last call to a mock function was provided specific args.
*/
lastCalledWith(...args: Array<unknown>): R;
lastCalledWith(...expected: [unknown, ...Array<unknown>]): R;
/**
* Ensure that the last call to a mock function has returned a specified value.
*/
lastReturnedWith(value: unknown): R;
lastReturnedWith(expected: unknown): R;
/**
* If you know how to test something, `.not` lets you test its opposite.
*/
not: Matchers<R>;
not: Matchers<R, T>;
/**
* Ensure that a mock function is called with specific arguments on an Nth call.
*/
nthCalledWith(nthCall: number, ...args: Array<unknown>): R;
nthCalledWith(nth: number, ...expected: [unknown, ...Array<unknown>]): R;
/**
* Ensure that the nth call to a mock function has returned a specified value.
*/
nthReturnedWith(n: number, value: unknown): R;
nthReturnedWith(nth: number, expected: unknown): R;
/**
* Use resolves to unwrap the value of a fulfilled promise so any other
* matcher can be chained. If the promise is rejected the assertion fails.
*/
resolves: Matchers<Promise<R>>;
resolves: Matchers<Promise<R>, T>;
/**
* Unwraps the reason of a rejected promise so any other matcher can be chained.
* If the promise is fulfilled the assertion fails.
*/
rejects: Matchers<Promise<R>>;
rejects: Matchers<Promise<R>, T>;
/**
* Checks that a value is what you expect. It uses `===` to check strict equality.
* Don't use `toBe` with floating-point numbers.
@ -154,13 +142,13 @@ export interface Matchers<R> {
/**
* Ensure that a mock function is called with specific arguments.
*/
toBeCalledWith(...args: Array<unknown>): R;
toBeCalledWith(...expected: [unknown, ...Array<unknown>]): R;
/**
* Using exact equality with floating point numbers is a bad idea.
* Rounding means that intuitive things fail.
* The default for numDigits is 2.
* The default for `precision` is 2.
*/
toBeCloseTo(expected: number, numDigits?: number): R;
toBeCloseTo(expected: number, precision?: number): R;
/**
* Ensure that a variable is not undefined.
*/
@ -182,7 +170,7 @@ export interface Matchers<R> {
* Ensure that an object is an instance of a class.
* This matcher uses `instanceof` underneath.
*/
toBeInstanceOf(expected: Function): R;
toBeInstanceOf(expected: unknown): R;
/**
* For comparing floating point numbers.
*/
@ -237,16 +225,19 @@ export interface Matchers<R> {
/**
* Ensure that a mock function is called with specific arguments.
*/
toHaveBeenCalledWith(...args: Array<unknown>): R;
toHaveBeenCalledWith(...expected: [unknown, ...Array<unknown>]): R;
/**
* Ensure that a mock function is called with specific arguments on an Nth call.
*/
toHaveBeenNthCalledWith(nthCall: number, ...args: Array<unknown>): R;
toHaveBeenNthCalledWith(
nth: number,
...expected: [unknown, ...Array<unknown>]
): R;
/**
* If you have a mock function, you can use `.toHaveBeenLastCalledWith`
* to test what arguments it was last called with.
*/
toHaveBeenLastCalledWith(...args: Array<unknown>): R;
toHaveBeenLastCalledWith(...expected: [unknown, ...Array<unknown>]): R;
/**
* Use to test the specific value that a mock function last returned.
* If the last call to the mock function threw an error, then this matcher will fail
@ -263,7 +254,7 @@ export interface Matchers<R> {
* If the nth call to the mock function threw an error, then this matcher will fail
* no matter what value you provided as the expected return value.
*/
toHaveNthReturnedWith(nthCall: number, expected: unknown): R;
toHaveNthReturnedWith(nth: number, expected: unknown): R;
/**
* Use to check if property at provided reference keyPath exists for an object.
* For checking deeply nested properties in an object you may use dot notation or an array containing
@ -277,7 +268,10 @@ export interface Matchers<R> {
*
* expect(houseForSale).toHaveProperty('kitchen.area', 20);
*/
toHaveProperty(keyPath: string | Array<string>, value?: unknown): R;
toHaveProperty(
expectedPath: string | Array<string>,
expectedValue?: unknown,
): R;
/**
* Use to test that the mock function successfully returned (i.e., did not throw an error) at least one time
*/
@ -298,7 +292,9 @@ export interface Matchers<R> {
/**
* Used to check that a JavaScript object matches a subset of the properties of an object
*/
toMatchObject(expected: Record<string, unknown> | Array<unknown>): R;
toMatchObject(
expected: Record<string, unknown> | Array<Record<string, unknown>>,
): R;
/**
* Ensure that a mock function has returned (as opposed to thrown) at least once.
*/
@ -306,11 +302,11 @@ export interface Matchers<R> {
/**
* Ensure that a mock function has returned (as opposed to thrown) a specified number of times.
*/
toReturnTimes(count: number): R;
toReturnTimes(expected: number): R;
/**
* Ensure that a mock function has returned a specified value at least once.
*/
toReturnWith(value: unknown): R;
toReturnWith(expected: unknown): R;
/**
* Use to test that objects have the same types as well as structure.
*/
@ -318,34 +314,25 @@ export interface Matchers<R> {
/**
* Used to test that a function throws when it is called.
*/
toThrow(error?: unknown): R;
toThrow(expected?: unknown): R;
/**
* If you want to test that a specific error is thrown inside a function.
*/
toThrowError(error?: unknown): R;
toThrowError(expected?: unknown): R;
/* TODO: START snapshot matchers are not from `expect`, the types should not be here */
/**
* This ensures that a value matches the most recent snapshot with property matchers.
* Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information.
*/
toMatchSnapshot<T extends {[P in keyof R]: unknown}>(
propertyMatchers: Partial<T>,
snapshotName?: string,
): R;
toMatchSnapshot(hint?: string): R;
/**
* This ensures that a value matches the most recent snapshot.
* Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information.
*/
toMatchSnapshot(snapshotName?: string): R;
/**
* This ensures that a value matches the most recent snapshot with property matchers.
* Instead of writing the snapshot value to a .snap file, it will be written into the source code automatically.
* Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information.
*/
toMatchInlineSnapshot<T extends {[P in keyof R]: unknown}>(
propertyMatchers: Partial<T>,
snapshot?: string,
toMatchSnapshot<U extends Record<keyof T, unknown>>(
propertyMatchers: Partial<U>,
hint?: string,
): R;
/**
* This ensures that a value matches the most recent snapshot with property matchers.
@ -353,10 +340,19 @@ export interface Matchers<R> {
* Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information.
*/
toMatchInlineSnapshot(snapshot?: string): R;
/**
* This ensures that a value matches the most recent snapshot with property matchers.
* Instead of writing the snapshot value to a .snap file, it will be written into the source code automatically.
* Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information.
*/
toMatchInlineSnapshot<U extends Record<keyof T, unknown>>(
propertyMatchers: Partial<U>,
snapshot?: string,
): R;
/**
* Used to test that a function throws a error matching the most recent snapshot when it is called.
*/
toThrowErrorMatchingSnapshot(): R;
toThrowErrorMatchingSnapshot(hint?: string): R;
/**
* Used to test that a function throws a error matching the most recent snapshot when it is called.
* Instead of writing the snapshot value to a .snap file, it will be written into the source code automatically.

View File

@ -0,0 +1,348 @@
/**
* 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.
*
* @type ./empty.d.ts
*/
import {expectError, expectType} from 'mlh-tsd';
import {expect} from '@jest/globals';
// asymmetric matchers
expectType<void>(expect('value').toEqual(expect.any(String)));
expectError(expect(123).toEqual(expect.any()));
expectError(expect('value').toEqual(expect.not.any(Number)));
expectType<void>(expect(jest.fn()).toBeCalledWith(expect.anything()));
expectError(expect(jest.fn()).toBeCalledWith(expect.anything(true)));
expectError(expect(jest.fn()).toBeCalledWith(expect.not.anything()));
expectType<void>(expect(['A', 'B']).toEqual(expect.arrayContaining(['A'])));
expectError(expect(['A']).toEqual(expect.arrayContaining('A')));
expectError(expect(['A']).toEqual(expect.arrayContaining()));
expectType<void>(expect(['B']).toEqual(expect.not.arrayContaining(['A'])));
expectError(expect(['A']).toEqual(expect.not.arrayContaining('A')));
expectError(expect(['A']).toEqual(expect.not.arrayContaining()));
expectType<void>(expect({a: 1}).toEqual(expect.objectContaining({a: 1})));
expectError(expect({a: 1}).toEqual(expect.objectContaining(1)));
expectError(expect({a: 1}).toEqual(expect.objectContaining()));
expectType<void>(expect({b: 2}).toEqual(expect.not.objectContaining({a: 1})));
expectError(expect({a: 1}).toEqual(expect.not.objectContaining(1)));
expectError(expect({a: 1}).toEqual(expect.not.objectContaining()));
expectType<void>(expect('one').toEqual(expect.stringContaining('n')));
expectError(expect('two').toEqual(expect.stringContaining(2)));
expectError(expect('three').toEqual(expect.stringContaining()));
expectType<void>(expect('one').toEqual(expect.not.stringContaining('m')));
expectError(expect('two').toEqual(expect.not.stringContaining(2)));
expectError(expect('three').toEqual(expect.not.stringContaining()));
expectType<void>(expect('one').toEqual(expect.stringMatching(/^[No]ne/)));
expectError(expect('one').toEqual(expect.stringMatching(2)));
expectError(expect('one').toEqual(expect.stringMatching()));
expectType<void>(expect('two').toEqual(expect.not.stringMatching(/^[No]ne/)));
expectError(expect('two').toEqual(expect.not.stringMatching(1)));
expectError(expect('two').toEqual(expect.not.stringMatching()));
// chainers and utilities
expectType<void>(expect.assertions(2));
expectError(expect.assertions());
expectType<void>(expect.hasAssertions());
expectError(expect.hasAssertions(true));
expectType<Promise<void>>(
expect(Promise.resolve('lemon')).resolves.toBe('lemon'),
);
expectType<Promise<void>>(
expect(Promise.reject(new Error('octopus'))).rejects.toThrow('octopus'),
);
// equality and relational matchers
expectType<void>(expect(2).toBe(2));
expectType<void>(expect('three').not.toBe('four'));
expectError(expect(false).toBe());
expectType<void>(expect(0.2 + 0.1).toBeCloseTo(0.3));
expectType<void>(expect(0.2 + 0.1).toBeCloseTo(0.3, 5));
expectError(expect(0.2 + 0.1).toBeCloseTo());
expectError(expect(0.2 + 0.1).toBeCloseTo('three'));
expectError(expect(BigInt(0.2 + 0.1)).toBeCloseTo(BigInt(0.3)));
expectError(expect(0.2 + 0.1).toBeCloseTo(0.3, false));
expectType<void>(expect('value').toBeDefined());
expectError(expect(true).not.toBeDefined(false));
expectType<void>(expect(0).toBeFalsy());
expectError(expect(true).not.toBeFalsy(true));
expectType<void>(expect(10).toBeGreaterThan(5));
expectType<void>(expect(BigInt(5.65)).toBeGreaterThan(BigInt(5.61)));
expectError(expect(10).toBeGreaterThan());
expectError(expect(10).toBeGreaterThan('1'));
expectType<void>(expect(10).toBeGreaterThanOrEqual(5));
expectType<void>(expect(BigInt(5.65)).toBeGreaterThanOrEqual(BigInt(5.61)));
expectError(expect(10).toBeGreaterThanOrEqual());
expectError(expect(10).toBeGreaterThanOrEqual('1'));
expectType<void>(expect(5).toBeLessThan(10));
expectType<void>(expect(BigInt(5.61)).toBeLessThan(BigInt(5.65)));
expectError(expect(1).toBeLessThan());
expectError(expect(1).toBeLessThan('10'));
expectType<void>(expect(5).toBeLessThanOrEqual(10));
expectType<void>(expect(BigInt(5.61)).toBeLessThanOrEqual(BigInt(5.65)));
expectError(expect(1).toBeLessThanOrEqual());
expectError(expect(1).toBeLessThanOrEqual('10'));
expectType<void>(expect(() => {}).toBeInstanceOf(Function));
expectError(expect(() => {}).toBeInstanceOf());
expectType<void>(expect(Number('ten')).toBeNaN());
expectError(expect(Number('10')).not.toBeNaN(true));
expectType<void>(expect(null).toBeNull());
expectError(expect('not null').not.toBeNull(true));
expectType<void>(expect('true').toBeTruthy());
expectError(expect(false).not.toBeTruthy(true));
expectType<void>(expect(undefined).toBeUndefined());
expectError(expect('value').not.toBeUndefined(false));
expectType<void>(expect(['lemon', 'lime']).not.toContain('orange'));
expectType<void>(expect('citrus fruits').toContain('fruit'));
const a = {key1: true, key2: false};
expectType<void>(expect([{key1: true, key2: false}]).toContainEqual(a));
expectType<void>(expect({a: 1, b: undefined}).toEqual({a: 1}));
expectError(expect({a: 1}).toEqual());
expectType<void>(expect({a: 1, b: 2}).toStrictEqual({a: 1, b: 2}));
expectError(expect({a: 1}).toStrictEqual());
expectType<void>(expect([1, 2, 3]).toHaveLength(3));
expectType<void>(expect('abc').not.toHaveLength(5));
expectError(expect('abc').toHaveLength());
expectType<void>(
expect({kitchen: {area: 20}}).toHaveProperty('kitchen.area', 20),
);
expectType<void>(
expect({kitchen: {area: 20}}).not.toHaveProperty(['kitchen', 'color']),
);
expectError(expect({kitchen: {area: 20}}).toHaveProperty());
expectError(expect({kitchen: {area: 20}}).toHaveProperty(true));
expectType<void>(expect('grapefruits').toMatch(/fruit/));
expectType<void>(expect('grapefruits').toMatch('fruit'));
expectError(expect('grapefruits').toMatch(true));
expectType<void>(expect({a: 1, b: 2}).toMatchObject({b: 2}));
expectType<void>(
expect([{a: 1}, {b: 2, c: true}]).toMatchObject([{a: 1}, {b: 2}]),
);
expectError(expect({c: true}).toMatchObject(true));
expectError(expect({c: true}).toMatchObject());
// error matchers
expectType<void>(expect(() => {}).toThrow());
expectType<void>(expect(() => {}).toThrow(/error/));
expectType<void>(expect(() => {}).toThrow('error'));
expectType<void>(expect(() => {}).toThrow(Error));
expectType<void>(expect(() => {}).toThrow(new Error('error')));
expectType<void>(expect(() => {}).toThrowError());
expectType<void>(expect(() => {}).toThrowError(/error/));
expectType<void>(expect(() => {}).toThrowError('error'));
expectType<void>(expect(() => {}).toThrowError(Error));
expectType<void>(expect(() => {}).toThrowError(new Error('error')));
// mock matchers
expectType<void>(expect(jest.fn()).toBeCalled());
expectError(expect(jest.fn()).toBeCalled('value'));
expectType<void>(expect(jest.fn()).toHaveBeenCalled());
expectError(expect(jest.fn()).toHaveBeenCalled(false));
expectType<void>(expect(jest.fn()).toBeCalledTimes(1));
expectError(expect(jest.fn()).toBeCalledTimes('twice'));
expectError(expect(jest.fn()).toBeCalledTimes());
expectType<void>(expect(jest.fn()).toHaveBeenCalledTimes(3));
expectError(expect(jest.fn()).toHaveBeenCalledTimes(true));
expectError(expect(jest.fn()).toHaveBeenCalledTimes());
expectType<void>(expect(jest.fn()).toBeCalledWith('value'));
expectType<void>(expect(jest.fn()).toBeCalledWith('value', 123));
// expectError(expect(jest.fn()).toBeCalledWith());
expectType<void>(expect(jest.fn()).toHaveBeenCalledWith(123));
expectType<void>(expect(jest.fn()).toHaveBeenCalledWith(123, 'value'));
// expectError(expect(jest.fn()).toHaveBeenCalledWith());
expectType<void>(expect(jest.fn()).lastCalledWith('value'));
expectType<void>(expect(jest.fn()).lastCalledWith('value', 123));
// expectError(expect(jest.fn()).lastCalledWith());
expectType<void>(expect(jest.fn()).toHaveBeenLastCalledWith(123));
expectType<void>(expect(jest.fn()).toHaveBeenLastCalledWith(123, 'value'));
// expectError(expect(jest.fn()).toHaveBeenLastCalledWith());
expectType<void>(expect(jest.fn()).nthCalledWith(1, 'value'));
expectType<void>(expect(jest.fn()).nthCalledWith(1, 'value', 123));
// expectError(expect(jest.fn()).nthCalledWith());
// expectError(expect(jest.fn()).nthCalledWith(2));
expectType<void>(expect(jest.fn()).toHaveBeenNthCalledWith(1, 'value'));
expectType<void>(expect(jest.fn()).toHaveBeenNthCalledWith(1, 'value', 123));
// expectError(expect(jest.fn()).toHaveBeenNthCalledWith());
// expectError(expect(jest.fn()).toHaveBeenNthCalledWith(2));
expectType<void>(expect(jest.fn()).toReturn());
expectError(expect(jest.fn()).toReturn('value'));
expectType<void>(expect(jest.fn()).toHaveReturned());
expectError(expect(jest.fn()).toHaveReturned(false));
expectType<void>(expect(jest.fn()).toReturnTimes(1));
expectError(expect(jest.fn()).toReturnTimes('twice'));
expectError(expect(jest.fn()).toReturnTimes());
expectType<void>(expect(jest.fn()).toHaveReturnedTimes(3));
expectError(expect(jest.fn()).toHaveReturnedTimes(true));
expectError(expect(jest.fn()).toHaveReturnedTimes());
expectType<void>(expect(jest.fn()).toReturnWith('value'));
expectError(expect(jest.fn()).toReturnWith());
expectType<void>(expect(jest.fn()).toHaveReturnedWith(123));
expectError(expect(jest.fn()).toHaveReturnedWith());
expectType<void>(expect(jest.fn()).lastReturnedWith('value'));
expectError(expect(jest.fn()).lastReturnedWith());
expectType<void>(expect(jest.fn()).toHaveLastReturnedWith(123));
expectError(expect(jest.fn()).toHaveLastReturnedWith());
expectType<void>(expect(jest.fn()).nthReturnedWith(1, 'value'));
expectError(expect(jest.fn()).nthReturnedWith());
expectError(expect(jest.fn()).nthReturnedWith(2));
expectType<void>(expect(jest.fn()).toHaveNthReturnedWith(1, 'value'));
expectError(expect(jest.fn()).toHaveNthReturnedWith());
expectError(expect(jest.fn()).toHaveNthReturnedWith(2));
// snapshot matchers
expectType<void>(expect({a: 1}).toMatchSnapshot());
expectType<void>(expect({a: 1}).toMatchSnapshot('hint'));
expectError(expect({a: 1}).toMatchSnapshot(true));
expectType<void>(
expect({
date: new Date(),
name: 'John Doe',
}).toMatchSnapshot({
date: expect.any(Date),
name: expect.any(String),
}),
);
expectType<void>(
expect({
date: new Date(),
name: 'John Doe',
}).toMatchSnapshot(
{
date: expect.any(Date),
name: expect.any(String),
},
'hint',
),
);
expectError(
expect({
date: new Date(),
name: 'John Doe',
}).toMatchSnapshot({
date: expect.any(Date),
time: expect.any(Date),
}),
);
expectType<void>(expect('abc').toMatchInlineSnapshot());
expectType<void>(expect('abc').toMatchInlineSnapshot('inline snapshot here'));
expectError(expect('abc').toMatchInlineSnapshot(true));
expectType<void>(
expect({
date: new Date(),
name: 'John Doe',
}).toMatchInlineSnapshot({
date: expect.any(Date),
name: expect.any(String),
}),
);
expectType<void>(
expect({
date: new Date(),
name: 'John Doe',
}).toMatchInlineSnapshot(
{
date: expect.any(Date),
name: expect.any(String),
},
'inline snapshot here',
),
);
expectError(
expect({
date: new Date(),
name: 'John Doe',
}).toMatchInlineSnapshot({
date: expect.any(Date),
time: expect.any(Date),
}),
);
expectType<void>(expect(jest.fn()).toThrowErrorMatchingSnapshot());
expectType<void>(expect(jest.fn()).toThrowErrorMatchingSnapshot('hint'));
expectError(expect(jest.fn()).toThrowErrorMatchingSnapshot(true));
expectType<void>(expect(jest.fn()).toThrowErrorMatchingInlineSnapshot());
expectType<void>(
expect(jest.fn()).toThrowErrorMatchingInlineSnapshot('inline snapshot here'),
);
expectError(expect(jest.fn()).toThrowErrorMatchingInlineSnapshot(true));
// extend
expectType<void>(
expect.extend({
toBeDivisibleBy(actual: number, expected: number) {
expectType<boolean>(this.isNot);
const pass = actual % expected === 0;
const message = pass
? () =>
`expected ${this.utils.printReceived(
actual,
)} not to be divisible by ${expected}`
: () =>
`expected ${this.utils.printReceived(
actual,
)} to be divisible by ${expected}`;
return {message, pass};
},
}),
);
// TODO
// expect(4).toBeDivisibleBy(2);
// expect.toBeDivisibleBy(2);

View File

@ -14,7 +14,6 @@ import {
beforeAll,
beforeEach,
describe,
expect,
test,
} from '@jest/globals';
import type {Global} from '@jest/types';
@ -109,42 +108,3 @@ expectType<void>(describe.only.each(testTable)(testName, fn));
expectType<void>(describe.only.each(testTable)(testName, fn, timeout));
expectType<void>(describe.skip.each(testTable)(testName, fn));
expectType<void>(describe.skip.each(testTable)(testName, fn, timeout));
/// expect
expectType<void>(expect(2).toBe(2));
expectType<Promise<void>>(expect(2).resolves.toBe(2));
expectType<void>(expect(() => {}).toThrow());
expectType<void>(expect(() => {}).toThrow(/error/));
expectType<void>(expect(() => {}).toThrow('error'));
expectType<void>(expect(() => {}).toThrow(Error));
expectType<void>(expect(() => {}).toThrow(new Error('error')));
expectType<void>(expect('Hello').toEqual(expect.any(String)));
// this currently does not error due to `[id: string]` in ExtraAsymmetricMatchers - we should have nothing there and force people to use interface merging
// expectError(expect('Hello').toEqual(expect.not.any(Number)));
expectType<void>(
expect.extend({
toBeDivisibleBy(actual: number, expected: number) {
expectType<boolean>(this.isNot);
const pass = actual % expected === 0;
const message = pass
? () =>
`expected ${this.utils.printReceived(
actual,
)} not to be divisible by ${expected}`
: () =>
`expected ${this.utils.printReceived(
actual,
)} to be divisible by ${expected}`;
return {message, pass};
},
}),
);
// TODO: some way of calling `expect(4).toBeDivisbleBy(2)` and `expect.toBeDivisbleBy(2)`