Как сообщить TypeScript о пользовательских сопоставлениях Jest?

У меня есть проект реагирования / машинописного текста, использующий шутку, где у меня есть собственный сопоставитель, например:

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 };
            }
        };
    }
};

на которые я ссылаюсь в своих тестах, выполняя внутри функции describe:

beforeEach(() => {
  jasmine.addMatchers(MyCustomMatchers);
});

И используйте это в it функциях:

expect(localValue).toBeTheSameAsRemote(remoteValue);

Тесты выполняются правильно, но компилятор машинописного текста не распознает сопоставитель, что имеет смысл, потому что я нигде не определил его в системе типов.

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

То, что я нашел до сих пор, относится к расширению пространства имен для жасмина и/или шутки, например.

declare namespace jasmine {
    interface Matchers {
        toBeTheSameAsRemote(remote: any): any;
    }
}

который не работал для меня.

Есть ли у вас какие-либо идеи?


person johncol    schedule 27.12.2019    source источник


Ответы (1)


Попробуй это:

В следующем файле объявляется как фактическая реализация 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;

Теперь в вашем тестовом файле импортируйте указанный выше модуль.

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);
   });
});

Заметки:

  • expect.extend будет вызываться автоматически из импорта. Нет необходимости вызывать expect.extend для каждого тестового файла.
  • declare global необходим, потому что jest явно не импортируется (это глобальный импорт).
  • Сигнатура функции toBeTheSameAsRemote внутри expect.extend и на TypeScript не одинакова.
person André Pena    schedule 13.01.2020
comment
В Typescript v4 @typescript-eslint/no-namespace не работает с ES2015 module syntax is preferred over custom TypeScript modules and namespaces. Есть ли лучший подход, чем просто отключить это правило? Или отключение необходимо, если jest является глобальным? - person Raine Revere; 29.10.2020
comment
ESLint: синтаксис модуля ES2015 предпочтительнее пользовательских модулей и пространств имен TypeScript.(@typescript-eslint/no-namespace) - person Alexey Sh.; 24.03.2021