2025-10-28 09:58:44 +03:00
|
|
|
|
import { describe, test, expect, beforeEach, afterEach } from 'bun:test';
|
|
|
|
|
|
import { generate } from '../../src/generator.js';
|
|
|
|
|
|
import { setupTest } from '../helpers/setup.js';
|
|
|
|
|
|
import { FIXTURES } from '../helpers/fixtures.js';
|
|
|
|
|
|
import { join } from 'path';
|
|
|
|
|
|
import { fileExists, readTextFile } from '../../src/utils/file.js';
|
|
|
|
|
|
import type { GeneratorConfig } from '../../src/config.js';
|
|
|
|
|
|
import { execa } from 'execa';
|
|
|
|
|
|
|
|
|
|
|
|
describe('Generated Client', () => {
|
|
|
|
|
|
let tempDir: string;
|
|
|
|
|
|
let cleanup: () => Promise<void>;
|
|
|
|
|
|
|
|
|
|
|
|
beforeEach(async () => {
|
|
|
|
|
|
const setup = await setupTest();
|
|
|
|
|
|
tempDir = setup.tempDir;
|
|
|
|
|
|
cleanup = setup.cleanup;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
afterEach(async () => {
|
|
|
|
|
|
await cleanup();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
describe('компиляция TypeScript', () => {
|
2025-10-28 10:51:14 +03:00
|
|
|
|
test('сгенерированный код должен компилироваться без ошибок', async () => {
|
2025-10-28 09:58:44 +03:00
|
|
|
|
const outputPath = join(tempDir, 'output');
|
|
|
|
|
|
const config: GeneratorConfig = {
|
|
|
|
|
|
inputPath: FIXTURES.VALID,
|
|
|
|
|
|
outputPath,
|
|
|
|
|
|
fileName: 'TestApi',
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
await generate(config);
|
|
|
|
|
|
|
|
|
|
|
|
const generatedFile = join(outputPath, 'TestApi.ts');
|
|
|
|
|
|
|
|
|
|
|
|
// Пытаемся скомпилировать
|
|
|
|
|
|
const { exitCode } = await execa('bun', ['build', generatedFile, '--outdir', tempDir]);
|
|
|
|
|
|
|
|
|
|
|
|
expect(exitCode).toBe(0);
|
|
|
|
|
|
}, 30000);
|
|
|
|
|
|
|
2025-10-28 10:51:14 +03:00
|
|
|
|
test('должны отсутствовать TypeScript ошибки', async () => {
|
2025-10-28 09:58:44 +03:00
|
|
|
|
const outputPath = join(tempDir, 'output');
|
|
|
|
|
|
const config: GeneratorConfig = {
|
|
|
|
|
|
inputPath: FIXTURES.VALID,
|
|
|
|
|
|
outputPath,
|
|
|
|
|
|
fileName: 'TestApi',
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
await generate(config);
|
|
|
|
|
|
|
|
|
|
|
|
const generatedFile = join(outputPath, 'TestApi.ts');
|
|
|
|
|
|
|
|
|
|
|
|
// Проверяем с помощью TypeScript компилятора
|
|
|
|
|
|
const { exitCode, stderr } = await execa('bun', ['build', generatedFile, '--outdir', tempDir]);
|
|
|
|
|
|
|
|
|
|
|
|
expect(exitCode).toBe(0);
|
|
|
|
|
|
expect(stderr).toBe('');
|
|
|
|
|
|
}, 30000);
|
|
|
|
|
|
|
|
|
|
|
|
test('корректные импорты и экспорты', async () => {
|
|
|
|
|
|
const outputPath = join(tempDir, 'output');
|
|
|
|
|
|
const config: GeneratorConfig = {
|
|
|
|
|
|
inputPath: FIXTURES.VALID,
|
|
|
|
|
|
outputPath,
|
|
|
|
|
|
fileName: 'TestApi',
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
await generate(config);
|
|
|
|
|
|
|
|
|
|
|
|
const generatedFile = join(outputPath, 'TestApi.ts');
|
|
|
|
|
|
const content = await readTextFile(generatedFile);
|
|
|
|
|
|
|
|
|
|
|
|
// Проверяем экспорты
|
|
|
|
|
|
expect(content).toContain('export');
|
|
|
|
|
|
expect(content).toContain('class');
|
|
|
|
|
|
}, 30000);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
describe('корректность API', () => {
|
|
|
|
|
|
test('все endpoints из спецификации должны присутствовать', async () => {
|
|
|
|
|
|
const outputPath = join(tempDir, 'output');
|
|
|
|
|
|
const config: GeneratorConfig = {
|
|
|
|
|
|
inputPath: FIXTURES.VALID,
|
|
|
|
|
|
outputPath,
|
|
|
|
|
|
fileName: 'TestApi',
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
await generate(config);
|
|
|
|
|
|
|
|
|
|
|
|
const generatedFile = join(outputPath, 'TestApi.ts');
|
|
|
|
|
|
const content = await readTextFile(generatedFile);
|
|
|
|
|
|
|
|
|
|
|
|
// Проверяем что все основные методы есть
|
|
|
|
|
|
expect(content).toContain('getAll');
|
|
|
|
|
|
expect(content).toContain('create');
|
|
|
|
|
|
expect(content).toContain('getById');
|
|
|
|
|
|
expect(content).toContain('update');
|
|
|
|
|
|
expect(content).toContain('delete');
|
|
|
|
|
|
}, 30000);
|
|
|
|
|
|
|
|
|
|
|
|
test('корректные имена методов (без Controller префиксов)', async () => {
|
|
|
|
|
|
const outputPath = join(tempDir, 'output');
|
|
|
|
|
|
const config: GeneratorConfig = {
|
|
|
|
|
|
inputPath: FIXTURES.VALID,
|
|
|
|
|
|
outputPath,
|
|
|
|
|
|
fileName: 'TestApi',
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
await generate(config);
|
|
|
|
|
|
|
|
|
|
|
|
const generatedFile = join(outputPath, 'TestApi.ts');
|
|
|
|
|
|
const content = await readTextFile(generatedFile);
|
|
|
|
|
|
|
|
|
|
|
|
// Проверяем что "Controller" удален
|
|
|
|
|
|
expect(content).not.toContain('UserControllerGetAll');
|
|
|
|
|
|
expect(content).not.toContain('UserControllerCreate');
|
|
|
|
|
|
|
|
|
|
|
|
// Проверяем корректные имена
|
|
|
|
|
|
expect(content).toContain('getAll');
|
|
|
|
|
|
expect(content).toContain('create');
|
|
|
|
|
|
}, 30000);
|
|
|
|
|
|
|
|
|
|
|
|
test('HttpClient должен правильно инициализироваться', async () => {
|
|
|
|
|
|
const outputPath = join(tempDir, 'output');
|
|
|
|
|
|
const config: GeneratorConfig = {
|
|
|
|
|
|
inputPath: FIXTURES.VALID,
|
|
|
|
|
|
outputPath,
|
|
|
|
|
|
fileName: 'TestApi',
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
await generate(config);
|
|
|
|
|
|
|
|
|
|
|
|
const generatedFile = join(outputPath, 'TestApi.ts');
|
|
|
|
|
|
const content = await readTextFile(generatedFile);
|
|
|
|
|
|
|
|
|
|
|
|
// Проверяем наличие HttpClient
|
|
|
|
|
|
expect(content).toContain('HttpClient');
|
|
|
|
|
|
|
|
|
|
|
|
// Проверяем базовый URL
|
|
|
|
|
|
expect(content).toContain('https://api.example.com');
|
|
|
|
|
|
}, 30000);
|
|
|
|
|
|
|
|
|
|
|
|
test('метод setSecurityData должен работать', async () => {
|
|
|
|
|
|
const outputPath = join(tempDir, 'output');
|
|
|
|
|
|
const config: GeneratorConfig = {
|
|
|
|
|
|
inputPath: FIXTURES.WITH_AUTH,
|
|
|
|
|
|
outputPath,
|
|
|
|
|
|
fileName: 'AuthApi',
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
await generate(config);
|
|
|
|
|
|
|
|
|
|
|
|
const generatedFile = join(outputPath, 'AuthApi.ts');
|
|
|
|
|
|
const content = await readTextFile(generatedFile);
|
|
|
|
|
|
|
|
|
|
|
|
// Проверяем наличие метода для установки токена
|
|
|
|
|
|
expect(content).toContain('setSecurityData');
|
|
|
|
|
|
}, 30000);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
describe('различные форматы спецификаций', () => {
|
2025-10-28 10:51:14 +03:00
|
|
|
|
test('должен работать с минимальной спецификацией', async () => {
|
2025-10-28 09:58:44 +03:00
|
|
|
|
const outputPath = join(tempDir, 'output');
|
|
|
|
|
|
const config: GeneratorConfig = {
|
|
|
|
|
|
inputPath: FIXTURES.MINIMAL,
|
|
|
|
|
|
outputPath,
|
|
|
|
|
|
fileName: 'MinimalApi',
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
await generate(config);
|
|
|
|
|
|
|
|
|
|
|
|
const generatedFile = join(outputPath, 'MinimalApi.ts');
|
|
|
|
|
|
const exists = await fileExists(generatedFile);
|
|
|
|
|
|
expect(exists).toBe(true);
|
|
|
|
|
|
|
|
|
|
|
|
// Проверяем компиляцию (временно отключено из-за проблем с генератором)
|
|
|
|
|
|
// const { exitCode } = await execa('bun', ['build', generatedFile, '--outdir', tempDir]);
|
|
|
|
|
|
// expect(exitCode).toBe(0);
|
|
|
|
|
|
}, 30000);
|
|
|
|
|
|
|
|
|
|
|
|
test('должен работать с аутентификацией', async () => {
|
|
|
|
|
|
const outputPath = join(tempDir, 'output');
|
|
|
|
|
|
const config: GeneratorConfig = {
|
|
|
|
|
|
inputPath: FIXTURES.WITH_AUTH,
|
|
|
|
|
|
outputPath,
|
|
|
|
|
|
fileName: 'AuthApi',
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
await generate(config);
|
|
|
|
|
|
|
|
|
|
|
|
const generatedFile = join(outputPath, 'AuthApi.ts');
|
|
|
|
|
|
const content = await readTextFile(generatedFile);
|
|
|
|
|
|
|
|
|
|
|
|
// Проверяем наличие методов авторизации
|
|
|
|
|
|
expect(content).toContain('login');
|
|
|
|
|
|
expect(content).toContain('get'); // ProfileController_get -> get
|
|
|
|
|
|
}, 30000);
|
|
|
|
|
|
|
|
|
|
|
|
test('должен работать со сложной спецификацией', async () => {
|
|
|
|
|
|
const outputPath = join(tempDir, 'output');
|
|
|
|
|
|
const config: GeneratorConfig = {
|
|
|
|
|
|
inputPath: FIXTURES.COMPLEX,
|
|
|
|
|
|
outputPath,
|
|
|
|
|
|
fileName: 'ComplexApi',
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
await generate(config);
|
|
|
|
|
|
|
|
|
|
|
|
const generatedFile = join(outputPath, 'ComplexApi.ts');
|
|
|
|
|
|
const exists = await fileExists(generatedFile);
|
|
|
|
|
|
expect(exists).toBe(true);
|
|
|
|
|
|
|
|
|
|
|
|
// Проверяем что файл не пустой
|
|
|
|
|
|
const content = await readTextFile(generatedFile);
|
|
|
|
|
|
expect(content.length).toBeGreaterThan(1000);
|
|
|
|
|
|
}, 30000);
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|