Я пытаюсь написать модульный тест, который проверяет, вызывается ли метод .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()
});
});
});
Я просто сохраняю новую аналитику в переменную. Jest автоматически заменяет методы класса на jest.fn(), и я проверил, существует ли mockAnalytics.track. Просто не называется.
Но это не тот пример, который использует код, который вы пытаетесь протестировать, так почему вы ожидаете взаимодействия с ним? Это тоже вовсе не тестовый двойник, это реальный экземпляр.
Если я зарегистрирую это в файле console.ts перед возвратом, я все же получу шутливую насмешку.
Потому что вы используете jest.mock
для имитации модуля (так что это не настоящий экземпляр, извините за это), но экземпляр, который вы создаете в тестах, не обязательно является тем же экземпляром, созданным в тестируемом коде. Когда вы говорите, что тест не пройден, что именно происходит? А у вас есть ручная мокка, она настроена так, что трек возвращает промис?
Вы используете Автоматический макет, позвонив 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.
С помощью "@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
}
};
}
}
};
});
Как вы думаете, как
mockAnalytics
связан с тестируемым кодом?