1.0.3 • Published 3 months ago

@storm-trade/jest-config v1.0.3

Weekly downloads
-
License
-
Repository
-
Last release
3 months ago

testing

Библиотека для помощи в написании тестов на node.js.

Экспортирует несколько хеплеров:

[TOC]

defaultConfig

Дефолтный конфиг для юнит и интеграционных тестов. Старайтесь не добавлять в него проект-специфичные опции.

Использование: в файл jest.config.js напишите код:

const { createDefaultConfig } = require('@atmruback/testing');

module.exports = {
    ...createDefaultConfig(),
};

Если проект находится на стадии поднятия test coverage, то стоит зафиксировать coverageThreshold на текущем уровне, чтобы не происходила деградация. Параметр coverageThreshold можно установить как для global, так и для отдельных директорий. Пример:

const { createDefaultConfig } = require('@atmruback/testing');

module.exports = {
    ...createDefaultConfig(),
    coverageThreshold: {
        global: {
            statements: 30,
        },
        './src/work-days/': {
            statements: 40,
        }
    }
};

Подробнее: https://jestjs.io/docs/configuration#coveragethreshold-object

Для интеграционных тестов в файле src/utils/test-utils/setup-integrations-db.ts напишите код:

import { initializeDatabase } from '@atmruback/testing/int/init-db';

import { dataSourceOptions } from '../../datasource';

export default async (): Promise<void> => initializeDatabase(dataSourceOptions);

@atmruback/testing/int/mock-rmq - мокает взаимодействие с RabbitMQ.

@atmruback/testing/int/init-db - создаёт базу данных под каждый воркер jest. Это необходимо, чтобы тесты не мешали друг другу при параллельном запуске. Количество воркеров определяется переменной окружения JEST_MAX_WORKERS.

После этого в файле интеграционного теста *.int.spec.ts вам нужно будет указать для typeorm название базы данных под текущий воркер. Пример:

import { workerDatabaseName } from '@atmruback/testing/int/init-db';
//...
const moduleRef = await Test.createTestingModule({
    imports: [
        TypeOrmModule.forRoot(typeOrmModuleConfig({ database: workerDatabaseName })),
    ],
})

Для запуска всех тестов (интеграционных и юнит) используем команду:

DOTENV_CONFIG_PATH=.env.test node -r dotenv/config ./node_modules/.bin/jest --force-exit --coverage

Для запуска только юнит-тестов используем команду:

DOTENV_CONFIG_PATH=.env.test node -r dotenv/config ./node_modules/.bin/jest --force-exit --coverage --selectProjects unit

Для запуска только интеграционных тестов используем команду:

DOTENV_CONFIG_PATH=.env.test node -r dotenv/config ./node_modules/.bin/jest --force-exit --coverage --selectProjects int

Если энвы для данного проекта не применимы (библиотеки) то из команд запуска убираем подключение dotenv:

node ./node_modules/.bin/jest --force-exit --coverage

или

jest --force-exit --coverage

provideServiceDefaultMock

provideRepositoryDefaultMock

Создают моки сервиса/репозитория для использования в зависимостях для тестирования nest сервиса. Возвращают объект типа MockProxy<>. См. ниже "Библиотека jest-mock-extended".

provideRepositoryDefaultMock вынесена в файл @atmruback/testing/repository-mock-factory, чтобы не требовать от потребителей подключения @nestjs/typeorm.

Пример использования:

import { LoggerService } from '@atmruback/logger';
import { MockProxy, provideServiceDefaultMock } from '@atmruback/testing';
import { provideRepositoryDefaultMock } from '@atmruback/testing/repository-mock-factory';
import { Test, TestingModule } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { Repository } from 'typeorm';

import { MyService } from './my.service';

describe('myService', () => {
    let service: MyService;
    let myRepository: MockProxy<Repository<MyEntity>>;
    let loggerService: MockProxy<LoggerService>;

    beforeEach(async () => {
        const module: TestingModule = await Test.createTestingModule({
            providers: [MyService, provideRepositoryDefaultMock(MyEntity), provideServiceDefaultMock(LoggerService)],
        }).compile();

        service = module.get<MyService>(MyService);
        myRepository = module.get(getRepositoryToken(MyEntity));
        loggerService = module.get(LoggerService)
    });

    it('should do action', async () => {
        const criticalMock = loggerService.critical.calledWith('test').mockReturnValue('stub');
        const saveMock = myRepository.save.mockResolvedValue(<MyEntity>{});

        await service.doAction();

        expect(criticalMock).toHaveBeenCalledOnce();
        expect(saveMock).toHaveBeenCalledOnceWith({ testField: "testValue" });
    });

guardMock

createJwtGuardMock

interceptorMock

Моки гардов и интерцепторов для интеграционных тестов. createJwtGuardMock создаёт новый мок jwt гарда с проставлением payload'а. Пример:

const moduleRef = await Test.createTestingModule({
    imports: [...],
})
    .overrideGuard(JwtGuard)
    .useValue(createJwtGuardMock({ id: testUserId, aud: TokenAudience.ACCOUNT }))
    .overrideGuard(MfaGuard)
    .useValue(guardMock)
    .overrideGuard(AuditLogMfaInterceptor)
    .useValue(interceptorMock)
    .compile();

Библиотека @total-typescript/shoehorn

@atmruback/testing реэкспортирует методы из @total-typescript/shoehorn. Решает проблему передачи в функции параметра, который удовлетворяет типу лишь частично. Ранее мы использовали для этого конструкцию {} as MyType. Это не очень хорошо: мы привыкаем к нормальности as, который не является типобезопасным; и всегда нужно указывать конкретный тип.

Функции:

  • fromPartial - позволяет передать в функцию параметр с неполным набором полей. Кинет ошибку, если тип параметра не соответствует ожидаемому. Заменяет {} as MyType.
  • fromAny - позволяет передать в функцию параметр любого типа. НЕ кинет ошибку, если тип параметра не соответствует ожидаемому. Заменяет {} as unknown as MyType.
  • fromExact - заставляет указать весь набор полей для параметра. Полезно, при переключении между fromPartial/fromAny или когда хотите их удалить.

Пример использования:

import { fromPartial } from "@atmruback/testing";

requiresRequest(
  fromPartial({
    body: {
      id: "123",
    },
  }),
);

Подробнее: https://www.npmjs.com/package/@total-typescript/shoehorn

Библиотека jest-extended

@atmruback/testing реэкспортирует jest-extended. Добавляет набор матчеров для jest: https://jest-extended.jestcommunity.dev/docs/matchers

Нужно импортировать '@atmruback/testing' и матчеры будут добавлены в глобальный скоуп.

Пример использования:

import '@atmruback/testing';

describe('myService', () => {
    it('should do action', async () => {
        expect(null).toBeNil();
        expect(undefined).toBeNil();
        expect(true).not.toBeNil();
    });

Подробнее: https://www.npmjs.com/package/jest-extended

Библиотека jest-mock-extended

@atmruback/testing реэкспортирует методы и типы из jest-mock-extended. Библиотека для генерации типобезопасных моков для объектов и интерфейсов.

Пример:

import { MockProxy, mock } from '@atmruback/testing';

class MyClass {
    public fooBar(text: string): number {
        return text.length;
    }
}

describe('test', () => {
    let myMock: MockProxy<MyClass>;

    beforeEach(() => {
        myMock = mock<MyClass>();
    });

    it('should do action', () => {
        myMock.fooBar.calledWith('foo').mockReturnValue(1);
        myMock.fooBar.calledWith('bar').mockReturnValue(2);

        expect(myMock.fooBar('foo')).toBe(1);
        expect(myMock.fooBar('bar')).toBe(2);
        expect(myMock.fooBar('foobar')).toBeUndefined();
    });
});

});

Подробнее: https://www.npmjs.com/package/jest-mock-extended

1.0.3

3 months ago

1.0.2

4 months ago

1.0.1

4 months ago

1.0.0

4 months ago