marchaos / jest-mock-extended

Type safe mocking extensions for Jest https://www.npmjs.com/package/jest-mock-extended
MIT License
839 stars 57 forks source link

The captor function causes type errors when used with `calledWith`. #117

Open adam-arold opened 1 year ago

adam-arold commented 1 year ago

If I try to use the captor function in a calledWith call (which accepts a Matcher) I get:

Argument of type '[CaptorMatcher<StateEntity<string, unknown>>]' is not assignable to parameter of type '[stateInstance: StateEntity<string, unknown>] | [stateInstance: StateEntity<string, unknown> | Matcher<StateEntity<string, unknown>>]'.
  Type '[CaptorMatcher<StateEntity<string, unknown>>]' is not assignable to type '[stateInstance: StateEntity<string, unknown> | Matcher<StateEntity<string, unknown>>]'.
    Type 'CaptorMatcher<StateEntity<string, unknown>>' is not assignable to type 'StateEntity<string, unknown> | Matcher<StateEntity<string, unknown>>'.
      Property 'description' is missing in type 'CaptorMatcher<StateEntity<string, unknown>>' but required in type 'Matcher<StateEntity<string, unknown>>'.ts(2345)
Matchers.d.ts(4, 22): 'description' is declared here.

To me it seems that CaptorMatcher for some reason doesn't implement description, so Typescript complains.

If I do this however:

const c = captor<StateEntity<string, unknown>>();

stateRepository.upsert
    .calledWith(c as unknown as Matcher<StateEntity<string, unknown>>) // 👈 this part
    .mockReturnValue(TE.right(c.value));

then it works as intended. I suggest implementing description properly. This is a working implementation:

import { Matcher } from "jest-mock-extended";

export class FixedCaptorMatcher<T> extends Matcher<T> {
    public readonly value!: T;
    public readonly values: T[] = [];

    constructor() {
        super((actualValue: T) => {
            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
            // @ts-ignore
            this.value = actualValue;
            this.values.push(actualValue);
            return true;
        }, "captor");
    }

    override getExpectedType() {
        return "Object";
    }
}