如何让 Jest 自定义匹配器在打字稿中工作?

Mar*_*tao 19 matcher momentjs typescript jestjs ts-jest

我经常进行单元测试,我需要比较两个矩对象。我希望我们使用 moment 的内置函数 moment.isSame(moment) 来比较它们。但是,这意味着我的断言将如下所示:

expect(moment1.isSame(moment2)).toBeTrue();

我不太喜欢这个,特别是因为失败消息的信息量会较少。因此,我想编写一个自定义的笑话匹配器“toBeSameMoment”。以下代码似乎至少可以编译:

import moment from "moment";

declare global {
  namespace jest {
    interface MomentMatchers extends Matchers<moment.Moment> {
      toBeSameMoment: (expected: moment.Moment) => CustomMatcherResult;
    }
  }
}

expect.extend({
  toBeSameMoment(received: moment.Moment, expected: moment.Moment): jest.CustomMatcherResult {
    const pass: boolean = received.isSame(expected);
    const message: () => string = () => pass ? "" : `Received moment (${received.toISOString()}) is not the same as expected (${expected.toISOString()})`;

    return {
      message,
      pass,
    };
  },
});
Run Code Online (Sandbox Code Playgroud)

但是,我无法真正让它在我的单元测试中工作......当我尝试以下测试代码时:

import moment from "moment";
import "../jest-matchers/moment";

describe("Moment matcher", () => {

  test("should fail", () => {
    const moment1 = moment.utc();
    const moment2 = moment();

    expect(moment1).toBeSameMoment(moment2);
  });

});
Run Code Online (Sandbox Code Playgroud)

...然后我收到以下错误:

error TS2339: Property 'toBeSameMoment' does not exist on type 'JestMatchersShape<Matchers<void, Moment>, Matchers<Promise<void>, Moment>>'.
Run Code Online (Sandbox Code Playgroud)

不过,我不太明白这个错误。例如,this 所指的 void 类型是什么?我试过在谷歌上搜索它,但并没有真正找到一个好的指南。我确实注意到了这个问题:How to let know typescript compiler about jest custom matchers? ,这似乎基本上是重复的,但显然还不够清楚。

我的 tsconfig 中包含了玩笑类型

Jos*_*a T 20

您链接到的另一个问题和答案是正确的,您还可以在关于 react-testing-library 的github 评论中找到一个非常简洁的示例,说明如何扩展 jest 。

要为您的代码实现他们的解决方案,只需更改:

declare global {
  namespace jest {
    interface MomentMatchers extends Matchers<moment.Moment> {
      toBeSameMoment: (expected: moment.Moment) => CustomMatcherResult;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

到:

declare global {
  namespace jest {
    interface Matchers<R> {
      toBeSameMoment(expected: moment.Moment): CustomMatcherResult;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 您将 jest.d.ts 放在哪里才能使该解决方案真正发挥作用? (8认同)
  • `&lt;_&gt;` 表示 TypeScript 中的泛型,它基本上是由其他代码填充的类型的占位符。在这个特定场景中,我猜测他们使用“R”来代表 **R**eceived,这是有道理的,因为如果你查看“@types/jest/index.d.ts”,你可以看到他们还在匹配器上定义的方法中使用“&lt;E&gt;”,其中“E”表示期望值的类型。 (2认同)
  • 在 Typescript v4 中 [@typescript-eslint/no-namespace](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-namespace.md)失败并显示“ES2015 模块语法优于自定义 TypeScript 模块和命名空间”。有没有比简单地禁用此规则更好的方法?或者只要“jest”是全局的就必须禁用? (2认同)