javascript - Simularea Segment Analytics cu Jest în TS


Încerc să scriu un test unitar care verifică dacă metoda .track a modulului Analytics este apelată. Dintr-un anumit motiv, testul continuă să eșueze, deși apelarea funcției prin http declanșează apelul. Nu sunt sigur dacă am făcut mock-ul greșit sau care ar putea fi problema.

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

Răspuns #1

Utilizați mock automat apelând jest.mock('analytics-node').

Apelarea jest.mock('analytics-node') returnează un "mock automat" util pe care îl poți folosi pentru a supraveghea apelurile constructorului clasei și ale tuturor metodelor sale. Înlocuiește clasa ES6 cu un constructor mock și înlocuiește toate metodele sale cu funcții mock care returnează întotdeauna undefined. Apelurile metodelor sunt salvate în theAutomaticMock.mock.instances[index].methodName.mock.calls.

De ex.

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

rezultat test unitar:

 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

Răspunsul #2

Folosind "@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;
};

batjocori

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