/
inssane
/
Axios-api
Обзор
Документация
Войти
/
inssane
/
Axios-api
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
test/createApiClient.test.ts
102 строки
4 KB
Павел Чернышев
test: добавить vitest и тесты ядра с регрессами на P0
18 июн 2026, 12:04
18 июн 2026, 12:04
5a1e085
Код
Авторство
О чём код?
import { describe, expect, it, vi } from 'vitest'; import { Registry } from 'prom-client'; import type { Logger } from 'pino'; import type { AxiosAdapter, AxiosResponse, InternalAxiosRequestConfig } from 'axios'; import { createApiClient } from '../api/core/createApiClient'; import { defineMiddleware } from '../api/core/types'; import { prometheusMiddleware } from '../api/interceptors/prometheus'; import { loggerMiddleware } from '../api/interceptors/addLoggerInterceptor'; const baseURLS = { qa: 'https://qa.local', stage: 'https://stage.local', prod: 'https://prod.local' }; /** Адаптер-заглушка: отвечает 200 после задержки, возвращая тот же config. */ const makeAdapter = (delayMs = 0): AxiosAdapter => async (config: InternalAxiosRequestConfig): Promise<AxiosResponse> => { if (delayMs) await new Promise(resolve => setTimeout(resolve, delayMs)); return { data: { ok: true }, status: 200, statusText: 'OK', headers: {}, config } as AxiosResponse; }; describe('createApiClient', () => { it('выставляет baseURL дефолтом инстанса под текущее окружение', () => { const api = createApiClient({ baseURLS }).build(); expect(api.defaults.baseURL).toBe('https://qa.local'); }); it('применяет server-мидлвару и пропускает browser-мидлвару в Node', () => { const serverApply = vi.fn(); const browserApply = vi.fn(); createApiClient({ baseURLS }) .use(defineMiddleware({ name: 's', runtime: 'server', apply: serverApply })) .use(defineMiddleware({ name: 'b', runtime: 'browser', apply: browserApply })) .build(); expect(serverApply).toHaveBeenCalledOnce(); expect(browserApply).not.toHaveBeenCalled(); }); }); describe('prometheusMiddleware (регресс P0#1: длительность > 0)', () => { it('пишет ненулевую длительность и нормализованный endpoint', async () => { const register = new Registry(); const api = createApiClient({ baseURLS, axios: { adapter: makeAdapter(10) } }) .use(prometheusMiddleware, { register }) .build(); await api.get('/users/123'); // record() плавающий и async (динамический import prom-client) — дождёмся. await new Promise(resolve => setTimeout(resolve, 50)); const json = await register.getMetricsAsJSON(); const duration = json.find(m => m.name === 'http_client_request_duration_seconds'); const total = json.find(m => m.name === 'http_client_requests_total'); const sum = duration?.values.find(v => v.metricName?.endsWith('_sum')); expect(sum?.value).toBeGreaterThan(0); expect(total?.values[0]?.labels).toMatchObject({ method: 'GET', endpoint: '/users/:id', status: '200' }); }); }); describe('loggerMiddleware (регресс P0#2: маскирование вложенных ПДн)', () => { it('не пишет вложенные phone/firstName в логи, оставляя безопасные поля', async () => { const entries: unknown[] = []; const fakeLogger = { info: (obj: unknown) => entries.push(obj), debug: (obj: unknown) => entries.push(obj), error: (obj: unknown) => entries.push(obj) } as unknown as Logger; const api = createApiClient({ baseURLS, axios: { adapter: makeAdapter() } }) .use(loggerMiddleware, { logger: fakeLogger }) .build(); await api.post('/submit', { phone: '+79990001122', profile: { firstName: 'Иван' }, keep: 'visible' }); const dump = JSON.stringify(entries); expect(dump).not.toContain('79990001122'); expect(dump).not.toContain('Иван'); expect(dump).toContain('visible'); }); });