如何让 TypeScript 了解自定义 Jest 匹配器?

joh*_*col 8 types typescript jasmine-matchers jestjs ts-jest

我有一个使用 jest 的 react/typescript 项目,其中有一个自定义匹配器,例如:

export const MyCustomMatchers = {
    toBeTheSameAsRemote: function(_util: any, _customEqualityTesters: any) {
        return {
            compare: function(actual: Brand, expected: RemoteBrand) {
                const pass: boolean = attributesMatch(actual, expected);
                const message: string = pass
                    ? 'Local matches Remote'
                    : 'Local does not match Remote';

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

我在我的测试中通过在describe函数内部进行引用:

beforeEach(() => {
  jasmine.addMatchers(MyCustomMatchers);
});
Run Code Online (Sandbox Code Playgroud)

并在it函数中像这样使用:

expect(localValue).toBeTheSameAsRemote(remoteValue);
Run Code Online (Sandbox Code Playgroud)

测试运行正常,但打字稿编译器无法识别匹配器,这是有道理的,因为我没有在类型系统中的任何地方定义它

Property 'toBeTheSameAsRemote' does not exist on type 'JestMatchersShape<Matchers<void, MyType[]>, Matchers<Promise<void>, MyType[]>>'.ts(2339)
Run Code Online (Sandbox Code Playgroud)

到目前为止,我发现的内容与扩展 jasmine 和/或 jest 的命名空间有关,例如

declare namespace jasmine {
    interface Matchers {
        toBeTheSameAsRemote(remote: any): any;
    }
}
Run Code Online (Sandbox Code Playgroud)

这对我不起作用。

你有什么主意吗?

And*_*ena 8

尝试这个:

以下文件声明了实际实现expect.extend和 TypeScript 声明。

custom-matcher.ts

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

expect.extend({
    /**
     * Notice that this implementation has 2 arguments, but the implementation inside the Matchers only has 1
     */
    toBeTheSameAsRemote(
    received: string,
    expected: string
  ) {
    return {
      pass: false,
      message: "A GraphQl error was expected"
    };
  }
});

// I am exporting nothing just so we can import this file
export default undefined;

Run Code Online (Sandbox Code Playgroud)

现在,在您的测试文件中,导入上述模块。

actual-test.ts

// importing the custom matcher file is important
import "../../testing/custom-matchers/custom-matcher";

describe("something", () => {
   it("should work", () => {
       expect(localValue).toBeTheSameAsRemote(remoteValue);
   });
});
Run Code Online (Sandbox Code Playgroud)

笔记:

  • expect.extend将从导入中自动调用。无需调用expect.extend每个测试文件。
  • declare global是必要的,因为jest没有明确导入(它是全局导入)。
  • toBeTheSameAsRemote函数的签名expect.extend在 TypeScript 中和在 TypeScript 上是不一样的。

  • 在 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”是全局的就必须禁用? (5认同)