From 4e2d0f03de79931057e1574f947abcbbbe9b8e7d Mon Sep 17 00:00:00 2001 From: "S.Gromov" Date: Tue, 28 Oct 2025 10:51:14 +0300 Subject: [PATCH] =?UTF-8?q?e2e=20=D0=B8=D0=BD=D1=82=D0=B5=D0=B3=D1=80?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D0=BE=D0=BD=D0=BD=D1=8B=D0=B5=20=D1=82=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bun.lock | 19 +- package.json | 3 + src/cli.ts | 4 +- src/config.ts | 2 + src/generator.ts | 37 ++-- src/templates/api.ejs | 7 +- src/templates/procedure-call.ejs | 4 +- tests/integration/e2e-generation.test.ts | 194 ++++++++++++++------- tests/integration/generated-client.test.ts | 6 +- 9 files changed, 191 insertions(+), 85 deletions(-) diff --git a/bun.lock b/bun.lock index 447dfc1..fffebd7 100644 --- a/bun.lock +++ b/bun.lock @@ -17,9 +17,12 @@ "@types/ejs": "^3.1.5", "@types/js-yaml": "^4.0.9", "@types/node": "^22.10.2", + "@types/react": "^18.3.0", "@types/tmp": "^0.2.6", "execa": "^8.0.0", "msw": "^2.0.0", + "react": "^18.3.0", + "swr": "^2.3.0", "tmp": "^0.2.1", }, "peerDependencies": { @@ -66,7 +69,9 @@ "@types/node": ["@types/node@22.18.12", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-BICHQ67iqxQGFSzfCFTT7MRQ5XcBjG5aeKh5Ok38UBbPe5fxTyE+aHFxwVrGyr8GNlqFMLKD1D3P2K/1ks8tog=="], - "@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="], + "@types/prop-types": ["@types/prop-types@15.7.15", "", {}, "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw=="], + + "@types/react": ["@types/react@18.3.26", "", { "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA=="], "@types/statuses": ["@types/statuses@2.0.6", "", {}, "sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA=="], @@ -120,6 +125,8 @@ "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], + "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], + "destr": ["destr@2.0.5", "", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="], "dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="], @@ -168,10 +175,14 @@ "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], + "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], + "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="], "mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="], @@ -228,6 +239,8 @@ "rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="], + "react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="], + "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], "reftools": ["reftools@1.1.9", "", {}, "sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w=="], @@ -270,6 +283,8 @@ "swagger2openapi": ["swagger2openapi@7.0.8", "", { "dependencies": { "call-me-maybe": "^1.0.1", "node-fetch": "^2.6.1", "node-fetch-h2": "^2.3.0", "node-readfiles": "^0.2.0", "oas-kit-common": "^1.0.8", "oas-resolver": "^2.5.6", "oas-schema-walker": "^1.1.5", "oas-validator": "^5.0.8", "reftools": "^1.1.9", "yaml": "^1.10.0", "yargs": "^17.0.1" }, "bin": { "swagger2openapi": "swagger2openapi.js", "oas-validate": "oas-validate.js", "boast": "boast.js" } }, "sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g=="], + "swr": ["swr@2.3.6", "", { "dependencies": { "dequal": "^2.0.3", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-wfHRmHWk/isGNMwlLGlZX5Gzz/uTgo0o2IRuTMcf4CPuPFJZlq0rDaKUx+ozB5nBOReNV1kiOyzMfj+MBMikLw=="], + "tinyexec": ["tinyexec@1.0.1", "", {}, "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw=="], "tldts": ["tldts@7.0.17", "", { "dependencies": { "tldts-core": "^7.0.17" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-Y1KQBgDd/NUc+LfOtKS6mNsC9CCaH+m2P1RoIZy7RAPo3C3/t8X45+zgut31cRZtZ3xKPjfn3TkGTrctC2TQIQ=="], @@ -290,6 +305,8 @@ "until-async": ["until-async@3.0.2", "", {}, "sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw=="], + "use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="], + "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], diff --git a/package.json b/package.json index 7ff9b92..e5ce9e1 100644 --- a/package.json +++ b/package.json @@ -29,9 +29,12 @@ "@types/ejs": "^3.1.5", "@types/js-yaml": "^4.0.9", "@types/node": "^22.10.2", + "@types/react": "^18.3.0", "@types/tmp": "^0.2.6", "execa": "^8.0.0", "msw": "^2.0.0", + "react": "^18.3.0", + "swr": "^2.3.0", "tmp": "^0.2.1" }, "peerDependencies": { diff --git a/src/cli.ts b/src/cli.ts index 5b46bdd..269b757 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -15,6 +15,7 @@ program .requiredOption('-i, --input ', 'Path to OpenAPI specification file (JSON or YAML)') .requiredOption('-o, --output ', 'Output directory for generated files') .option('-n, --name ', 'Name of generated file (without extension)') + .option('--swr', 'Generate SWR hooks for React') .action(async (options) => { try { // Создание конфигурации @@ -22,6 +23,7 @@ program inputPath: options.input, outputPath: options.output, fileName: options.name, + useSwr: options.swr || false, }; // Валидация конфигурации @@ -38,7 +40,7 @@ program // Генерация API await generate(config as GeneratorConfig); - console.log(chalk.green('\n✨ Done!\n')); + console.log(chalk.green('\n✨ API client generated successfully!\n')); } catch (error) { console.error(chalk.red('\n❌ Error:'), error instanceof Error ? error.message : error); console.error(); diff --git a/src/config.ts b/src/config.ts index b7424eb..0928290 100644 --- a/src/config.ts +++ b/src/config.ts @@ -8,6 +8,8 @@ export interface GeneratorConfig { outputPath: string; /** Имя сгенерированного файла (без расширения) */ fileName?: string; + /** Генерировать SWR hooks для React */ + useSwr?: boolean; } /** diff --git a/src/generator.ts b/src/generator.ts index f014b57..6059c7d 100644 --- a/src/generator.ts +++ b/src/generator.ts @@ -18,25 +18,34 @@ export async function generate(config: GeneratorConfig): Promise { // Путь к кастомным шаблонам const templatesPath = resolve(__dirname, '../src/templates'); - - // Читаем OpenAPI спецификацию - const inputPath = config.inputPath.startsWith('http://') || config.inputPath.startsWith('https://') - ? config.inputPath - : resolve(config.inputPath); - const spec = await readJsonFile(inputPath); + // Проверяем тип входного пути + const isUrl = config.inputPath.startsWith('http://') || config.inputPath.startsWith('https://'); + + // Для локальных файлов читаем спецификацию + let spec: any = null; + let inputPath: string | undefined = undefined; + let url: string | undefined = undefined; + + if (isUrl) { + url = config.inputPath; + // Для URL не читаем спецификацию заранее, swagger-typescript-api сделает это сам + } else { + inputPath = resolve(config.inputPath); + spec = await readJsonFile(inputPath); + } // Определяем имя файла let fileName = config.fileName; if (!fileName) { // Пытаемся получить имя из OpenAPI спецификации - fileName = spec.info?.title + fileName = spec?.info?.title ? spec.info.title.replace(/[^a-zA-Z0-9]/g, '') : 'Api'; } try { await swaggerGenerateApi({ - input: inputPath, + ...(isUrl ? { url } : { input: inputPath }), output: resolve(config.outputPath), fileName: `${fileName}.ts`, httpClientType: 'fetch', @@ -60,7 +69,7 @@ export async function generate(config: GeneratorConfig): Promise { sortRoutes: false, extractResponseError: false, fixInvalidEnumKeyPrefix: 'KEY', - silent: false, + silent: true, defaultResponseType: 'void', typePrefix: '', typeSuffix: '', @@ -90,18 +99,18 @@ export async function generate(config: GeneratorConfig): Promise { }, onInit: (configuration) => { // Получаем дефолтный baseUrl из OpenAPI спецификации - const defaultBaseUrl = spec.servers?.[0]?.url || ''; + const apiConfig = (configuration as any).apiConfig || {}; + const defaultBaseUrl = spec?.servers?.[0]?.url || apiConfig.baseUrl || ''; (configuration as any).apiConfig = (configuration as any).apiConfig || {}; (configuration as any).apiConfig.baseUrl = defaultBaseUrl; + // Передаем флаг useSwr в шаблоны + (configuration as any).useSwr = config.useSwr || false; return configuration; }, }, }); - console.log(`Generated files in ${config.outputPath}:`); - console.log(` - ${fileName}.ts (API endpoints)`); - console.log(' - http-client.ts (HTTP client)'); - console.log(' - data-contracts.ts (TypeScript types)'); + // Генерация успешна } catch (error) { console.error('❌ Generation failed:', error); throw error; diff --git a/src/templates/api.ejs b/src/templates/api.ejs index 5c690ba..a5c2940 100644 --- a/src/templates/api.ejs +++ b/src/templates/api.ejs @@ -26,8 +26,9 @@ const descriptionLines = _.compact([ %> +<% if (config.useSwr) { %> import useSWR from "swr"; -import { fetcher } from "./http-client"; +<% } %> <% if (config.httpClientType === config.constants.HTTP_CLIENT.AXIOS) { %> import type { AxiosRequestConfig, AxiosResponse } from "axios"; <% } %> @@ -44,8 +45,8 @@ export class <%~ config.apiClassName %><% if ( <% if(config.singleHttpClient) { %> http: HttpClient; - constructor (http: HttpClient) { - this.http = http; + constructor (http?: HttpClient) { + this.http = http || new HttpClient(); } <% } %> diff --git a/src/templates/procedure-call.ejs b/src/templates/procedure-call.ejs index 635e1dd..c59d2ed 100644 --- a/src/templates/procedure-call.ejs +++ b/src/templates/procedure-call.ejs @@ -102,9 +102,9 @@ const isValidIdentifier = (name) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name); ...<%~ _.get(requestConfigParam, "name") %>, })<%~ route.namespace ? ',' : '' %> <% -// Генерируем use* функцию для GET запросов +// Генерируем use* функцию для GET запросов (только если включен флаг useSwr) const isGetRequest = _.upperCase(method) === 'GET'; -if (isGetRequest) { +if (config.useSwr && isGetRequest) { const useMethodName = 'use' + _.upperFirst(route.routeName.usage); const argsWithoutParams = rawWrapperArgs.filter(arg => arg.name !== requestConfigParam.name); const useWrapperArgs = _ diff --git a/tests/integration/e2e-generation.test.ts b/tests/integration/e2e-generation.test.ts index 3340bce..424305a 100644 --- a/tests/integration/e2e-generation.test.ts +++ b/tests/integration/e2e-generation.test.ts @@ -38,7 +38,7 @@ describe('E2E Generation', () => { }); describe('полный цикл генерации', () => { - test.skip('CLI генерация → создание файла → импорт → использование', async () => { + test('CLI генерация → создание файла → импорт → использование', async () => { const outputPath = join(tempDir, 'output'); // 1. Генерация через CLI @@ -135,10 +135,91 @@ describe('E2E Generation', () => { 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.skip('GET запрос без параметров', async () => { + test('GET запрос без параметров', async () => { const outputPath = join(tempDir, 'output'); await execa('bun', [ @@ -152,26 +233,18 @@ describe('E2E Generation', () => { 'TestApi', ]); - // Создаем тестовый файл для вызова API - const testFile = join(tempDir, 'test-get.ts'); - const testCode = ` - import { Api } from '${join(outputPath, 'TestApi.ts')}'; - - const api = new Api(); - const result = await api.user.getAll(); - console.log(JSON.stringify(result)); - `; + // Динамически импортируем сгенерированный API + const generatedFile = join(outputPath, 'TestApi.ts'); + const { Api } = await import(generatedFile); - await Bun.write(testFile, testCode); + const api = new Api(); + const result = await api.users.getAll(); - const { stdout } = await execa('bun', ['run', testFile]); - const data = JSON.parse(stdout); - - expect(Array.isArray(data)).toBe(true); - expect(data.length).toBe(2); + expect(Array.isArray(result)).toBe(true); + expect(result.length).toBe(2); }, 60000); - test.skip('POST запрос с body', async () => { + test('POST запрос с body', async () => { const outputPath = join(tempDir, 'output'); await execa('bun', [ @@ -185,28 +258,21 @@ describe('E2E Generation', () => { 'TestApi', ]); - const testFile = join(tempDir, 'test-post.ts'); - const testCode = ` - import { Api } from '${join(outputPath, 'TestApi.ts')}'; - - const api = new Api(); - const result = await api.user.create({ - email: 'new@example.com', - password: 'password123' - }); - console.log(JSON.stringify(result)); - `; + // Динамически импортируем сгенерированный API + const generatedFile = join(outputPath, 'TestApi.ts'); + const { Api } = await import(generatedFile); - await Bun.write(testFile, testCode); + const api = new Api(); + const result = await api.users.create({ + email: 'new@example.com', + password: 'password123' + }); - const { stdout } = await execa('bun', ['run', testFile]); - const data = JSON.parse(stdout); - - expect(data.id).toBe('3'); - expect(data.email).toBe('new@example.com'); + expect(result.id).toBe('3'); + expect(result.email).toBe('new@example.com'); }, 60000); - test.skip('обработка 404 статуса', async () => { + test('обработка 404 статуса', async () => { const outputPath = join(tempDir, 'output'); await execa('bun', [ @@ -226,7 +292,7 @@ describe('E2E Generation', () => { const api = new Api(); try { - await api.user.getById('999'); + await api.users.getById('999'); } catch (error) { console.log('error'); } @@ -238,7 +304,7 @@ describe('E2E Generation', () => { expect(stdout).toContain('error'); }, 60000); - test.skip('Bearer token authentication', async () => { + test('Bearer token authentication', async () => { const outputPath = join(tempDir, 'output'); await execa('bun', [ @@ -252,32 +318,38 @@ describe('E2E Generation', () => { 'AuthApi', ]); - const testFile = join(tempDir, 'test-auth.ts'); - const testCode = ` - import { Api } from '${join(outputPath, 'AuthApi.ts')}'; - - const api = new Api(); - - // Логин - const { token } = await api.auth.login({ - email: 'test@example.com', - password: 'password' - }); - - // Установка токена - api.instance.setSecurityData(token); - - // Запрос с токеном - const profile = await api.profile.get(); - console.log(JSON.stringify(profile)); - `; + // Динамически импортируем сгенерированный API + const generatedFile = join(outputPath, 'AuthApi.ts'); + const { Api, HttpClient } = await import(generatedFile); - await Bun.write(testFile, testCode); + // Создаем HttpClient с securityWorker для добавления Bearer токена + const httpClient = new HttpClient({ + securityWorker: (securityData: string | null) => { + if (securityData) { + return { + headers: { + Authorization: `Bearer ${securityData}` + } + }; + } + } + }); - const { stdout } = await execa('bun', ['run', testFile]); - const data = JSON.parse(stdout); + const api = new Api(httpClient); - expect(data.email).toBe('test@example.com'); + // Логин + 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); }); }); \ No newline at end of file diff --git a/tests/integration/generated-client.test.ts b/tests/integration/generated-client.test.ts index 030cd2d..ec6a661 100644 --- a/tests/integration/generated-client.test.ts +++ b/tests/integration/generated-client.test.ts @@ -22,7 +22,7 @@ describe('Generated Client', () => { }); describe('компиляция TypeScript', () => { - test.skip('сгенерированный код должен компилироваться без ошибок', async () => { + test('сгенерированный код должен компилироваться без ошибок', async () => { const outputPath = join(tempDir, 'output'); const config: GeneratorConfig = { inputPath: FIXTURES.VALID, @@ -40,7 +40,7 @@ describe('Generated Client', () => { expect(exitCode).toBe(0); }, 30000); - test.skip('должны отсутствовать TypeScript ошибки', async () => { + test('должны отсутствовать TypeScript ошибки', async () => { const outputPath = join(tempDir, 'output'); const config: GeneratorConfig = { inputPath: FIXTURES.VALID, @@ -161,7 +161,7 @@ describe('Generated Client', () => { }); describe('различные форматы спецификаций', () => { - test.skip('должен работать с минимальной спецификацией', async () => { + test('должен работать с минимальной спецификацией', async () => { const outputPath = join(tempDir, 'output'); const config: GeneratorConfig = { inputPath: FIXTURES.MINIMAL,