Имитация сегментной аналитики с помощью Jest в TS

Я пытаюсь написать модульный тест, который проверяет, вызывается ли метод .track Analytics. По какой-то причине тест продолжает давать сбой, хотя вызов функции через http вызывает вызов. Я не уверен, что я издевался над этим неправильно, или в чем может быть проблема?

index.ts:

import { Request } from "../types"
import { getSecret } from "../src/secrets"
import Analytics from "analytics-node"

const logger = (req: Request) => {
    const analytics = new Analytics(<string>process.env.WRITE_KEY);
    return analytics.track({
        userId: req.userId
    });
}

export default logger

index.test.ts:

jest.mock('analytics-node');
import { Request } from "../types"
import logger from "./index"
import Analytics from "analytics-node"

const mockAnalytics = new Analytics(process.env.WRITE_KEY = 'test');

describe('Logger tests', () => {
    it(`Should call analytics.track`, () => {
        const request: Request = {
            userId: 23
        }
        return logger(request).then(() => {
            expect(mockAnalytics.track).toHaveBeenCalled()
        });
    });
});

Как вы думаете, как mockAnalytics связан с тестируемым кодом?

jonrsharpe 22.12.2020 17:42

Я просто сохраняю новую аналитику в переменную. Jest автоматически заменяет методы класса на jest.fn(), и я проверил, существует ли mockAnalytics.track. Просто не называется.

lauraleonilla 22.12.2020 17:47

Но это не тот пример, который использует код, который вы пытаетесь протестировать, так почему вы ожидаете взаимодействия с ним? Это тоже вовсе не тестовый двойник, это реальный экземпляр.

jonrsharpe 22.12.2020 17:48

Если я зарегистрирую это в файле console.ts перед возвратом, я все же получу шутливую насмешку.

lauraleonilla 22.12.2020 19:11

Потому что вы используете jest.mock для имитации модуля (так что это не настоящий экземпляр, извините за это), но экземпляр, который вы создаете в тестах, не обязательно является тем же экземпляром, созданным в тестируемом коде. Когда вы говорите, что тест не пройден, что именно происходит? А у вас есть ручная мокка, она настроена так, что трек возвращает промис?

jonrsharpe 22.12.2020 19:13
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
5
2 406
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы используете Автоматический макет, позвонив jest.mock('analytics-node').

Вызов jest.mock('analytics-node') возвращает полезный «автоматический макет», который вы можете использовать для отслеживания вызовов конструктора класса и всех его методов. Он заменяет класс ES6 фиктивным конструктором и заменяет все его методы фиктивными функциями, которые всегда возвращают undefined. Вызовы методов сохраняются в theAutomaticMock.mock.instances[index].methodName.mock.calls.

Например.

index.ts:

import Analytics from 'analytics-node';

export interface Request {
  userId: string | number;
}

const logger = (req: Request) => {
  const analytics = new Analytics(<string>process.env.WRITE_KEY);
  return analytics.track({
    userId: req.userId,
    anonymousId: 1,
    event: '',
  });
};

export default logger;

index.test.ts:

import logger, { Request } from './';
import Analytics from 'analytics-node';

jest.mock('analytics-node');
const mockAnalytics = Analytics as jest.MockedClass<typeof Analytics>;

describe('Logger tests', () => {
  afterAll(() => {
    jest.resetAllMocks();
  });
  it(`Should call analytics.track`, () => {
    const WRITE_KEY = process.env.WRITE_KEY;
    process.env.WRITE_KEY = 'test key';
    const request: Request = {
      userId: 23,
    };
    logger(request);
    expect(mockAnalytics).toBeCalledWith('test key');
    expect(mockAnalytics.mock.instances[0].track).toHaveBeenCalled();
    process.env.WRITE_KEY = WRITE_KEY;
  });
});

результат модульного теста:

 PASS  examples/65412302/index.test.ts
  Logger tests
    ✓ Should call analytics.track (4 ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |     100 |      100 |     100 |     100 |                   
 index.ts |     100 |      100 |     100 |     100 |                   
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        5.954 s

Спасибо, есть идеи, как это можно сделать в ES5? Наши облачные функции еще не используют TS.

MorenoMdz 11.02.2022 20:10

С помощью "@segment/analytics-next": "1.49.2"

let analyticsInstance: AnalyticsBrowser | null | undefined;

export const loadAnalytics = (props?: LoadAnalyticsProps): typeof analyticsInstance => {
    if ((analyticsInstance && analyticsInstance.instance?.initialized) || !props) {
        return analyticsInstance;
    }
    const { segmentAnalyticsKey, anonymousId, userId } = props;

    if (!segmentAnalyticsKey) {
        return null;
    }

    analyticsInstance = AnalyticsBrowser.load({ writeKey: segmentAnalyticsKey });
    analyticsInstance.setAnonymousId(anonymousId);
    analyticsInstance.identify(userId);

    return analyticsInstance;
};

насмехаться

const setAnonymousIdMock = jest.fn();
const identifyMock = jest.fn();

jest.mock("@segment/analytics-next", () => {
    const originalModule = jest.requireActual("@segment/analytics-next");

    return {
        __esModule: true,
        ...originalModule,
        AnalyticsBrowser: {
            load: () => {
                return {
                    setAnonymousId: setAnonymousIdMock,
                    identify: identifyMock,
                    instance: {
                        initialized: true
                    }
                };
            }
        }
    };
});

Другие вопросы по теме