Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(expect): replace RawMatcherFn with MatcherFunction and MatcherFunctionWithState types #12376

Merged
merged 13 commits into from Feb 15, 2022
6 changes: 3 additions & 3 deletions examples/expect-extend/toBeWithinRange.ts
Expand Up @@ -6,13 +6,13 @@
*/

import {expect} from '@jest/globals';
import type {RawMatcherFn} from 'expect';
import type {ExpectationResult} from 'expect';

const toBeWithinRange: RawMatcherFn = (
SimenB marked this conversation as resolved.
Show resolved Hide resolved
const toBeWithinRange = (
actual: number,
floor: number,
ceiling: number,
) => {
): ExpectationResult => {
mrazauskas marked this conversation as resolved.
Show resolved Hide resolved
const pass = actual >= floor && actual <= ceiling;
if (pass) {
return {
Expand Down
2 changes: 1 addition & 1 deletion packages/expect/src/index.ts
Expand Up @@ -52,9 +52,9 @@ import type {
export type {
AsymmetricMatchers,
Expect,
ExpectationResult,
MatcherState,
Matchers,
RawMatcherFn,
} from './types';

export class JestAssertionError extends Error {
Expand Down
2 changes: 1 addition & 1 deletion packages/expect/src/types.ts
Expand Up @@ -21,7 +21,7 @@ export type AsyncExpectationResult = Promise<SyncExpectationResult>;
export type ExpectationResult = SyncExpectationResult | AsyncExpectationResult;

export type RawMatcherFn<T extends MatcherState = MatcherState> = {
(this: T, actual: any, expected: any, options?: any): ExpectationResult;
(this: T, actual: any, ...expected: Array<any>): ExpectationResult;
/** @internal */
[INTERNAL_MATCHER_FLAG]?: boolean;
};
Expand Down
16 changes: 4 additions & 12 deletions packages/jest-jasmine2/src/jestExpect.ts
Expand Up @@ -7,7 +7,7 @@

/* eslint-disable local/prefer-spread-eventually */

import {type MatcherState, type RawMatcherFn, expect} from 'expect';
import {type MatcherState, expect} from 'expect';
import {
addSerializer,
toMatchInlineSnapshot,
Expand Down Expand Up @@ -41,23 +41,15 @@ export default function jestExpect(config: {expand: boolean}): void {
jestMatchersObject[name] = function (
this: MatcherState,
...args: Array<unknown>
): RawMatcherFn {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function has inferred return type of ExpectationResult without this extra type.

) {
// use "expect.extend" if you need to use equality testers (via this.equal)
const result = jasmineMatchersObject[name](null, null);
// if there is no 'negativeCompare', both should be handled by `compare`
const negativeCompare = result.negativeCompare || result.compare;

return this.isNot
? negativeCompare.apply(
null,
// @ts-expect-error
args,
)
: result.compare.apply(
null,
// @ts-expect-error
args,
);
? negativeCompare.apply(null, args)
: result.compare.apply(null, args);
};
});

Expand Down
6 changes: 3 additions & 3 deletions packages/jest-jasmine2/src/types.ts
Expand Up @@ -7,7 +7,7 @@

import type {AssertionError} from 'assert';
import type {Config} from '@jest/types';
import type {Expect, RawMatcherFn} from 'expect';
import type {Expect, ExpectationResult} from 'expect';
import type CallTracker from './jasmine/CallTracker';
import type Env from './jasmine/Env';
import type JsApiReporter from './jasmine/JsApiReporter';
Expand Down Expand Up @@ -48,8 +48,8 @@ export interface Spy extends Record<string, any> {

type JasmineMatcher = {
(matchersUtil: unknown, context: unknown): JasmineMatcher;
compare: () => RawMatcherFn;
negativeCompare: () => RawMatcherFn;
compare(...args: Array<unknown>): ExpectationResult;
negativeCompare(...args: Array<unknown>): ExpectationResult;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle. To be precise this type should be () => (...args: Array<unknown>) => ExpectationResult, but my version eliminates these @ts-expect-error: https://github.com/facebook/jest/blob/faef0b4b7082df574a0e4423b86d468847360f17/packages/jest-jasmine2/src/jestExpect.ts#L50-L60

};

export type JasmineMatchersObject = {[id: string]: JasmineMatcher};
Expand Down
87 changes: 47 additions & 40 deletions packages/jest-snapshot/src/index.ts
Expand Up @@ -7,7 +7,7 @@

import * as fs from 'graceful-fs';
import type {Config} from '@jest/types';
import type {RawMatcherFn} from 'expect';
import type {ExpectationResult} from 'expect';
import type {FS as HasteFS} from 'jest-haste-map';
import {
BOLD_WEIGHT,
Expand Down Expand Up @@ -156,11 +156,12 @@ export const cleanup = (
};
};

export const toMatchSnapshot: RawMatcherFn<Context> = function (
export const toMatchSnapshot = function (
mrazauskas marked this conversation as resolved.
Show resolved Hide resolved
this: Context,
received: unknown,
propertiesOrHint?: object | Config.Path,
hint?: Config.Path,
) {
): ExpectationResult {
const matcherName = 'toMatchSnapshot';
let properties;

Expand Down Expand Up @@ -214,11 +215,12 @@ export const toMatchSnapshot: RawMatcherFn<Context> = function (
});
};

export const toMatchInlineSnapshot: RawMatcherFn<Context> = function (
export const toMatchInlineSnapshot = function (
this: Context,
received: unknown,
propertiesOrSnapshot?: object | string,
inlineSnapshot?: string,
) {
): ExpectationResult {
const matcherName = 'toMatchInlineSnapshot';
let properties;

Expand Down Expand Up @@ -407,11 +409,12 @@ const _toMatchSnapshot = (config: MatchSnapshotConfig) => {
};
};

export const toThrowErrorMatchingSnapshot: RawMatcherFn<Context> = function (
export const toThrowErrorMatchingSnapshot = function (
this: Context,
received: unknown,
hint: string | undefined, // because error TS1016 for hint?: string
fromPromise: boolean,
) {
hint?: string,
fromPromise?: boolean,
): ExpectationResult {
const matcherName = 'toThrowErrorMatchingSnapshot';

// Future breaking change: Snapshot hint must be a string
Expand All @@ -429,40 +432,44 @@ export const toThrowErrorMatchingSnapshot: RawMatcherFn<Context> = function (
);
};

export const toThrowErrorMatchingInlineSnapshot: RawMatcherFn<Context> =
function (received: unknown, inlineSnapshot?: string, fromPromise?: boolean) {
const matcherName = 'toThrowErrorMatchingInlineSnapshot';

if (inlineSnapshot !== undefined && typeof inlineSnapshot !== 'string') {
const options: MatcherHintOptions = {
expectedColor: noColor,
isNot: this.isNot,
promise: this.promise,
};
export const toThrowErrorMatchingInlineSnapshot = function (
this: Context,
received: unknown,
inlineSnapshot?: string,
fromPromise?: boolean,
): ExpectationResult {
const matcherName = 'toThrowErrorMatchingInlineSnapshot';

throw new Error(
matcherErrorMessage(
matcherHint(matcherName, undefined, SNAPSHOT_ARG, options),
'Inline snapshot must be a string',
printWithType('Inline snapshot', inlineSnapshot, serialize),
),
);
}
if (inlineSnapshot !== undefined && typeof inlineSnapshot !== 'string') {
const options: MatcherHintOptions = {
expectedColor: noColor,
isNot: this.isNot,
promise: this.promise,
};

return _toThrowErrorMatchingSnapshot(
{
context: this,
inlineSnapshot:
inlineSnapshot !== undefined
? stripAddedIndentation(inlineSnapshot)
: undefined,
isInline: true,
matcherName,
received,
},
fromPromise,
throw new Error(
matcherErrorMessage(
matcherHint(matcherName, undefined, SNAPSHOT_ARG, options),
'Inline snapshot must be a string',
printWithType('Inline snapshot', inlineSnapshot, serialize),
),
);
};
}

return _toThrowErrorMatchingSnapshot(
{
context: this,
inlineSnapshot:
inlineSnapshot !== undefined
? stripAddedIndentation(inlineSnapshot)
: undefined,
isInline: true,
matcherName,
received,
},
fromPromise,
);
};

const _toThrowErrorMatchingSnapshot = (
config: MatchSnapshotConfig,
Expand Down