Jest automock не применяется к модулю

#typescript #mocking #jestjs

#typescript #издевательство #jestjs

Вопрос:

У меня возникли проблемы с запуском тестов Jest для моих модулей — у меня простой класс начальной точки:

 import { Callback, CloudFrontRequestEvent, Context, Handler } from "aws-lambda";

import { CloudFrontHandler } from "./CloudFrontHandler";
import { OriginClient } from "./OriginClient";
import { ResponseRenderer } from "./ResponseRenderer";
import { TemplateRenderer } from "./TemplateRenderer";

export class LambdaHandler {
    private readonly renderer: TemplateRenderer;

    constructor(renderer: TemplateRenderer) {
        this.renderer = renderer;
    }

    public handle: Handler = (event: CloudFrontRequestEvent, _: Context, callback: Callback): void => {
        console.log(new CloudFrontHandler(null, null)); // <- just an empty object here! CloudFrontHandler {}
        console.log(new OriginClient(null)); // <- properly mocked
        console.log(new ResponseRenderer(null, null)); // <- properly mocked
        new CloudFrontHandler(
            new OriginClient(event.Records[0].cf.request),
            new ResponseRenderer(callback, this.renderer),
        )
            .handle(); // <- because CloudFrontHandler is not mocked, an error occurs here
    }
}
  

По какой-либо причине CloudFrontHandler класс не подвергается издевательству ( OriginClient и ResponseRenderer должным образом автоматически издевается). Ниже приведен мой тестовый класс:

 import "jest";
import { Callback, CloudFrontRequest, CloudFrontRequestEvent } from "aws-lambda";
import { mocked } from "ts-jest/utils";
import { LambdaHandler, TemplateRenderer } from "../../../main/nodejs";

import { CloudFrontHandler } from "../../../main/nodejs/edge/CloudFrontHandler";
import { OriginClient } from "../../../main/nodejs/edge/OriginClient";
import { ResponseRenderer } from "../../../main/nodejs/edge/ResponseRenderer";

jest.mock("../../../main/nodejs/edge/CloudFrontHandler");
jest.mock("../../../main/nodejs/edge/OriginClient");
jest.mock("../../../main/nodejs/edge/ResponseRenderer");

const MockedCloudFrontHandler = mocked(CloudFrontHandler);
const MockedOriginClient = mocked(OriginClient);
const MockedResponseRenderer = mocked(ResponseRenderer);

describe("LambdaHandler", (): void => {
        it("should handle CloudFront request", (): void => {
                const templateRenderer: TemplateRenderer = {} as TemplateRenderer;
                const callback: Callback = jest.fn() as Callback;
                const request: CloudFrontRequest = {} as CloudFrontRequest;
                const event: CloudFrontRequestEvent = {
                    Records: [
                        {
                            cf: {
                                request: request,
                            },
                        },
                    ],
                } as CloudFrontRequestEvent;

                let handler: LambdaHandler = new LambdaHandler(templateRenderer);
                handler.handle(event, null, callback)
                // todo

                expect(MockedCloudFrontHandler).toHaveBeenCalledTimes(1);
                expect(MockedOriginClient).toHaveBeenCalledTimes(1);
                expect(MockedResponseRenderer).toHaveBeenCalledTimes(1);
        });
});
  

(Я храню исходные файлы и тестовые файлы отдельно, поэтому все эти src/main src/test пути)

Есть ли причина, по которой Jest не стал бы издеваться над этим одним классом модуля?

-редактировать-

Сообщение об ошибке:

 TypeError: (intermediate value).handle is not a function
  

Комментарии:

1. Какую версию NodeJS вы используете? Я полагаю, что, возможно, я видел ту же проблему здесь , но только на NodeJS 11.x. Более старые версии NodeJS работают нормально.

2. Я использую ровно 11.0.0.

3. Пробовал с 10.13 и 8.15 — то же поведение.

4. github.com/kulshekhar/ts-jest/issues/998 Это как-то связано?

5. @10101010 Вы, вероятно, просто указали мне на основную причину — это функция со стрелкой, поэтому в TypeScript она переводится в JavaScript как свойство, назначенное в конструкторе. Я проверю это.

Ответ №1:

Комментарии под моим вопросом указали мне на основную причину — проблема здесь в том, что CloudFrontHandler.handle это функция со стрелкой, которую TypeScript преобразует в свойство, назначенное в конструкторе. Поскольку конструктор автоматически издевается, функция не назначается. Создание ручного макета для .handle() метода решает проблему.