Files
api-codegen/tests/integration/e2e-generation.test.ts

355 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { describe, test, expect, beforeEach, afterEach, beforeAll, afterAll } from 'bun:test';
import { execa } from 'execa';
import { setupTest } from '../helpers/setup.js';
import { createMockServer, type MockServer } from '../helpers/mock-server.js';
import { FIXTURES } from '../helpers/fixtures.js';
import { join } from 'path';
import { fileExists, readTextFile } from '../../src/utils/file.js';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const CLI_PATH = join(__dirname, '../../src/cli.ts');
describe('E2E Generation', () => {
let tempDir: string;
let cleanup: () => Promise<void>;
let mockServer: MockServer;
beforeAll(() => {
mockServer = createMockServer();
mockServer.start();
});
afterAll(() => {
mockServer.stop();
});
beforeEach(async () => {
const setup = await setupTest();
tempDir = setup.tempDir;
cleanup = setup.cleanup;
mockServer.reset();
});
afterEach(async () => {
await cleanup();
});
describe('полный цикл генерации', () => {
test('CLI генерация → создание файла → импорт → использование', async () => {
const outputPath = join(tempDir, 'output');
// 1. Генерация через CLI
const { exitCode } = await execa('bun', [
'run',
CLI_PATH,
'--input',
FIXTURES.VALID,
'--output',
outputPath,
'--name',
'TestApi',
]);
expect(exitCode).toBe(0);
// 2. Проверка создания файла
const generatedFile = join(outputPath, 'TestApi.ts');
const exists = await fileExists(generatedFile);
expect(exists).toBe(true);
// 3. Проверка импорта (компиляция TypeScript)
const testFile = join(tempDir, 'test-import.ts');
const testCode = `
import { Api } from '${generatedFile}';
const api = new Api();
console.log('Import successful');
`;
await Bun.write(testFile, testCode);
// Компилируем тестовый файл
const { exitCode: compileExitCode } = await execa('bun', ['build', testFile, '--outdir', tempDir]);
expect(compileExitCode).toBe(0);
}, 60000);
test('генерация из локального файла', async () => {
const outputPath = join(tempDir, 'output');
const { exitCode } = await execa('bun', [
'run',
CLI_PATH,
'--input',
FIXTURES.MINIMAL,
'--output',
outputPath,
]);
expect(exitCode).toBe(0);
const generatedFile = join(outputPath, 'MinimalAPI.ts');
const exists = await fileExists(generatedFile);
expect(exists).toBe(true);
}, 30000);
test('повторная генерация (перезапись файлов)', async () => {
const outputPath = join(tempDir, 'output');
const fileName = 'TestApi';
// Первая генерация
await execa('bun', [
'run',
CLI_PATH,
'--input',
FIXTURES.MINIMAL,
'--output',
outputPath,
'--name',
fileName,
]);
const generatedFile = join(outputPath, `${fileName}.ts`);
const firstContent = await readTextFile(generatedFile);
// Вторая генерация (перезапись)
await execa('bun', [
'run',
CLI_PATH,
'--input',
FIXTURES.VALID,
'--output',
outputPath,
'--name',
fileName,
]);
const secondContent = await readTextFile(generatedFile);
// Содержимое должно отличаться
expect(firstContent).not.toBe(secondContent);
// Файл должен существовать
const exists = await fileExists(generatedFile);
expect(exists).toBe(true);
}, 60000);
test('генерация из HTTP URL', async () => {
const outputPath = join(tempDir, 'output');
// Используем публичный OpenAPI spec
const { exitCode } = await execa('bun', [
'run',
CLI_PATH,
'--input',
'https://petstore3.swagger.io/api/v3/openapi.json',
'--output',
outputPath,
'--name',
'PetStore',
]);
expect(exitCode).toBe(0);
const generatedFile = join(outputPath, 'PetStore.ts');
const exists = await fileExists(generatedFile);
expect(exists).toBe(true);
// Проверяем что файл не пустой
const content = await readTextFile(generatedFile);
expect(content.length).toBeGreaterThan(1000);
}, 60000);
test('генерация с флагом --swr', async () => {
const outputPath = join(tempDir, 'output');
const { exitCode } = await execa('bun', [
'run',
CLI_PATH,
'--input',
FIXTURES.VALID,
'--output',
outputPath,
'--name',
'SwrApi',
'--swr',
]);
expect(exitCode).toBe(0);
const generatedFile = join(outputPath, 'SwrApi.ts');
const content = await readTextFile(generatedFile);
// Проверяем наличие импорта useSWR
expect(content).toContain('import useSWR from "swr"');
// Проверяем наличие use* хуков для GET запросов
expect(content).toContain('useGetAll');
expect(content).toContain('useGetById');
}, 30000);
test('генерация без флага --swr не содержит хуки', async () => {
const outputPath = join(tempDir, 'output');
const { exitCode } = await execa('bun', [
'run',
CLI_PATH,
'--input',
FIXTURES.VALID,
'--output',
outputPath,
'--name',
'NoSwrApi',
]);
expect(exitCode).toBe(0);
const generatedFile = join(outputPath, 'NoSwrApi.ts');
const content = await readTextFile(generatedFile);
// Проверяем отсутствие импорта useSWR
expect(content).not.toContain('import useSWR from "swr"');
// Проверяем отсутствие use* хуков
expect(content).not.toContain('useGetAll');
expect(content).not.toContain('useGetById');
}, 30000);
});
describe('HTTP запросы с mock сервером', () => {
test('GET запрос без параметров', async () => {
const outputPath = join(tempDir, 'output');
await execa('bun', [
'run',
CLI_PATH,
'--input',
FIXTURES.VALID,
'--output',
outputPath,
'--name',
'TestApi',
]);
// Динамически импортируем сгенерированный API
const generatedFile = join(outputPath, 'TestApi.ts');
const { Api } = await import(generatedFile);
const api = new Api();
const result = await api.users.getAll();
expect(Array.isArray(result)).toBe(true);
expect(result.length).toBe(2);
}, 60000);
test('POST запрос с body', async () => {
const outputPath = join(tempDir, 'output');
await execa('bun', [
'run',
CLI_PATH,
'--input',
FIXTURES.VALID,
'--output',
outputPath,
'--name',
'TestApi',
]);
// Динамически импортируем сгенерированный API
const generatedFile = join(outputPath, 'TestApi.ts');
const { Api } = await import(generatedFile);
const api = new Api();
const result = await api.users.create({
email: 'new@example.com',
password: 'password123'
});
expect(result.id).toBe('3');
expect(result.email).toBe('new@example.com');
}, 60000);
test('обработка 404 статуса', async () => {
const outputPath = join(tempDir, 'output');
await execa('bun', [
'run',
CLI_PATH,
'--input',
FIXTURES.VALID,
'--output',
outputPath,
'--name',
'TestApi',
]);
const testFile = join(tempDir, 'test-404.ts');
const testCode = `
import { Api } from '${join(outputPath, 'TestApi.ts')}';
const api = new Api();
try {
await api.users.getById('999');
} catch (error) {
console.log('error');
}
`;
await Bun.write(testFile, testCode);
const { stdout } = await execa('bun', ['run', testFile]);
expect(stdout).toContain('error');
}, 60000);
test('Bearer token authentication', async () => {
const outputPath = join(tempDir, 'output');
await execa('bun', [
'run',
CLI_PATH,
'--input',
FIXTURES.WITH_AUTH,
'--output',
outputPath,
'--name',
'AuthApi',
]);
// Динамически импортируем сгенерированный API
const generatedFile = join(outputPath, 'AuthApi.ts');
const { Api, HttpClient } = await import(generatedFile);
// Создаем HttpClient с securityWorker для добавления Bearer токена
const httpClient = new HttpClient({
securityWorker: (securityData: string | null) => {
if (securityData) {
return {
headers: {
Authorization: `Bearer ${securityData}`
}
};
}
}
});
const api = new Api(httpClient);
// Логин
const loginResult = await api.auth.login({
email: 'test@example.com',
password: 'password'
});
// Установка токена
httpClient.setSecurityData(loginResult.token);
// Запрос с токеном
const profile = await api.profile.get();
expect(profile.email).toBe('test@example.com');
}, 60000);
});
});