为什么不显示我的 Jest 自定义匹配器的“消息”?

Why is the `message` for my Jest custom matcher not being displayed?

我创建了一个 Jest 自定义匹配器。它有效(意思是,它应该在 passes/fails 的时候),但我在 Jest 的输出中没有看到 message

我做错了什么?我必须做些什么来“启用”消息吗?我是不是完全误解了消息应该出现在哪里?

环境:NestJS、Prisma

执行命令:jest --watch

简化代码:

    declare global {
        namespace jest {
            interface Matchers<R> {
                toMatchHash(received: string, expected: string): R;
            }
        }
    }

    expect.extend({
        toMatchJsonHash(received, expected) {
            return {
                pass: false,
                message: () => `Why doesn't this work?!`,
            };
        },
    }); 
expect(prisma.name.findMany).toHaveBeenCalledWith(expect.toMatchJsonHash('db0110285c148c77943f996a17cbaf27'));

输出:

  ● MyService › should pass a test using a custom matcher

    expect(jest.fn()).toHaveBeenCalledWith(...expected)

    Expected: toMatchJsonHash<db0110285c148c77943f996a17cbaf27>
    Received: {<Big ol' object redacted for conciseness>}

    Number of calls: 1

      178 |
      179 |         // @ts-ignore
    > 180 |         expect(prisma.name.findMany).toHaveBeenCalledWith(expect.toMatchJsonHash('db0110285c148c77943f996a17cbaf27'));
          |                                      ^
      181 |         // expect(prisma.name.findMany).toHaveBeenCalledWith({
      182 |     //   select: { type: true, name: true },
      183 |     //   where: {

      at Object.<anonymous> (my/my.service.spec.ts:180:32)

我期待看到“为什么这不起作用?!”在输出的某处,但我没有。我错过了什么?

作为 ,原因是 Jest 正在显示来自“外部”匹配器的消息,.toHaveBeenCalledWith()

为了解决这个问题,我找到了 the source that defines the .toHaveBeenCalledWith() matcher 并将其代码“合并”到我的自定义匹配器中。

这使我的自定义匹配器能够有效地“扩展”.toHaveBeenCalledWith() 匹配器的功能,包括我自己的自定义代码和消息。

如果它对某人有帮助,我最终为我的特定用例编写的代码是:

declare global {
    namespace jest {
        interface Matchers<R> {
            toHaveBeenCalledWithObjectMatchingHash(expected: string): CustomMatcherResult;
        }
    }
}

expect.extend({toHaveBeenCalledWithObjectMatchingHash(received, expected) {
        const isSpy = (received: any) =>
            received != null &&
            received.calls != null &&
            typeof received.calls.all === 'function' &&
            typeof received.calls.count === 'function';
        
        const receivedIsSpy = isSpy(received);
        const receivedName = receivedIsSpy ? 'spy' : received.getMockName();

        const calls = receivedIsSpy
            ? received.calls.all().map((x: any) => x.args)
            : received.mock.calls;
        
        if(calls.length === 0) {
            return {
                pass: false,
                message: () => `expected the function to be called with an object that hashes to '${expected}'. Instead, the function was not called.`,
            };
        }

        if(calls[0].length === 0) {
            return {
                pass: false,
                message: () => `expected the function to be called with an object that hashes to '${expected}'. Instead, the function was called, but not with any arguments.`,
            };
        }

        const md5Hash = crypto.createHash('md5');
        const receivedHash = md5Hash.update(JSON.stringify(calls[0][0])).digest('hex');
        const pass = receivedHash === expected;
        
        if(pass) {
            return {
                pass: true,
                message: () => `expected the function to not be called with an object that hashes to '${expected}'. Instead, the passed object hashes to the same value.`,
            };
        } else {
            return {
                pass: false,
                message: () => `expected the function to be called with an object that hashes to '${expected}'. Instead, the passed object hashes to '${receivedHash}'.`,
            };
        }
    }});