diff --git a/TESTING-PLAN.md b/TESTING-PLAN.md deleted file mode 100644 index 64fca10..0000000 --- a/TESTING-PLAN.md +++ /dev/null @@ -1,393 +0,0 @@ -# План реализации тестирования API CodeGen - -## Общая информация - -**Цель:** Максимальное покрытие тестами CLI инструмента и сгенерированного клиента - -**Итого тестовых кейсов:** ~72 - -**Запуск:** `bun test` (одна команда) - ---- - -## Технологический стек - -### Основные инструменты -- [x] **Bun test** - встроенный test runner (быстрый, совместим с Jest API) -- [ ] **msw** `^2.0.0` - Mock Service Worker для HTTP мокирования -- [ ] **tmp** `^0.2.1` - создание временных директорий для тестов -- [ ] **@types/tmp** `^0.2.6` - типы для tmp -- [ ] **execa** `^8.0.0` - запуск CLI команд в тестах - -### Преимущества выбранного стека -- ✅ Быстрое выполнение тестов (Bun) -- ✅ Реалистичное HTTP мокирование (msw) -- ✅ Изолированное тестовое окружение (tmp) -- ✅ Удобное тестирование CLI (execa) -- ✅ Совместимость с Jest API (легкая миграция при необходимости) - ---- - -## Структура проекта с тестами - -``` -api-codegen/ -├── tests/ -│ ├── fixtures/ # Тестовые OpenAPI спецификации -│ │ ├── minimal.json # Минимальная валидная спецификация -│ │ ├── valid.json # Полная валидная спецификация -│ │ ├── complex.json # Сложная (100+ endpoints) -│ │ ├── invalid.json # Невалидная спецификация -│ │ ├── with-auth.json # С authentication схемами -│ │ ├── edge-cases.json # Unicode, спецсимволы -│ │ └── empty.json # Пустая спецификация -│ │ -│ ├── unit/ # Юнит тесты -│ │ ├── cli.test.ts # Тесты CLI команд -│ │ ├── generator.test.ts # Тесты генератора -│ │ ├── config.test.ts # Тесты валидации конфигурации -│ │ └── utils/ -│ │ └── file.test.ts # Тесты файловых утилит -│ │ -│ ├── integration/ # Интеграционные тесты -│ │ ├── e2e-generation.test.ts # End-to-end генерация -│ │ └── generated-client.test.ts # Тесты сгенерированного клиента -│ │ -│ └── helpers/ # Вспомогательные функции -│ ├── setup.ts # Настройка окружения -│ ├── mock-server.ts # Mock HTTP сервер (msw) -│ └── fixtures.ts # Утилиты для работы с фикстурами -│ -└── package.json -``` - ---- - -## Этапы реализации - -### Этап 1: Подготовка инфраструктуры - -#### 1.1. Установка зависимостей -- [ ] Добавить `msw` в devDependencies -- [ ] Добавить `tmp` и `@types/tmp` в devDependencies -- [ ] Добавить `execa` в devDependencies -- [ ] Выполнить `bun install` - -#### 1.2. Создание структуры директорий -- [ ] Создать `tests/` -- [ ] Создать `tests/fixtures/` -- [ ] Создать `tests/unit/` -- [ ] Создать `tests/unit/utils/` -- [ ] Создать `tests/integration/` -- [ ] Создать `tests/helpers/` - -#### 1.3. Настройка package.json -- [ ] Добавить скрипт `"test": "bun test"` -- [ ] Добавить скрипт `"test:unit": "bun test tests/unit"` -- [ ] Добавить скрипт `"test:integration": "bun test tests/integration"` -- [ ] Добавить скрипт `"test:watch": "bun test --watch"` -- [ ] Добавить скрипт `"test:coverage": "bun test --coverage"` - ---- - -### Этап 2: Создание тестовых фикстур - -#### 2.1. minimal.json - минимальная спецификация -- [ ] Базовая структура OpenAPI 3.0 -- [ ] Один GET endpoint -- [ ] Минимальная info секция -- [ ] Без servers -- [ ] Простой response - -#### 2.2. valid.json - полная валидная спецификация -- [ ] Все основные HTTP методы (GET, POST, PUT, PATCH, DELETE) -- [ ] Path параметры -- [ ] Query параметры -- [ ] Request body (JSON) -- [ ] Response schemas -- [ ] Базовые типы данных -- [ ] Описания и примеры -- [ ] Servers с baseUrl - -#### 2.3. complex.json - сложная спецификация -- [ ] 100+ endpoints -- [ ] Вложенные объекты -- [ ] Массивы объектов -- [ ] Enum типы -- [ ] Референсы ($ref) -- [ ] Множественные tags -- [ ] Различные content types - -#### 2.4. with-auth.json - с аутентификацией -- [ ] Bearer token authentication -- [ ] API Key authentication -- [ ] Security schemes -- [ ] Защищенные endpoints - -#### 2.5. edge-cases.json - edge cases -- [ ] Unicode символы в названиях -- [ ] Специальные символы в путях -- [ ] Очень длинные названия -- [ ] Зарезервированные слова -- [ ] Нестандартные HTTP методы - -#### 2.6. invalid.json - невалидная спецификация -- [ ] Отсутствующие обязательные поля -- [ ] Неправильная структура -- [ ] Невалидные типы данных - -#### 2.7. empty.json - пустая спецификация -- [ ] Только обязательные поля -- [ ] Без paths -- [ ] Без components - ---- - -### Этап 3: Вспомогательные функции - -#### 3.1. tests/helpers/setup.ts -- [ ] `beforeEach` для инициализации -- [ ] `afterEach` для очистки -- [ ] Создание временных директорий -- [ ] Очистка временных файлов - -#### 3.2. tests/helpers/mock-server.ts -- [ ] Настройка MSW -- [ ] Mock handlers для разных endpoints -- [ ] Симуляция различных HTTP статусов -- [ ] Симуляция network errors -- [ ] Симуляция timeouts - -#### 3.3. tests/helpers/fixtures.ts -- [ ] Загрузка фикстур -- [ ] Валидация OpenAPI спецификаций -- [ ] Создание тестовых конфигураций -- [ ] Утилиты для сравнения сгенерированного кода - ---- - -### Этап 4: Юнит тесты CLI (15 кейсов) - -#### 4.1. tests/unit/cli.test.ts - базовые сценарии -- [ ] ✅ Запуск с корректными параметрами (локальный файл) -- [ ] ✅ Запуск с URL в качестве input -- [ ] ✅ Генерация с кастомным именем файла -- [ ] ✅ Генерация с автоматическим именем (из OpenAPI title) -- [ ] ✅ Отображение версии `--version` -- [ ] ✅ Отображение help `--help` - -#### 4.2. tests/unit/cli.test.ts - обработка ошибок -- [ ] ❌ Отсутствие обязательного параметра `--input` -- [ ] ❌ Отсутствие обязательного параметра `--output` -- [ ] ❌ Несуществующий входной файл -- [ ] ❌ Некорректный формат OpenAPI -- [ ] ❌ Недоступный URL (404) -- [ ] ❌ Недоступный URL (network error) -- [ ] ❌ Невозможность записи в output директорию (permissions) -- [ ] ❌ Невалидный JSON в input файле -- [ ] ❌ YAML файл (должен работать или показать понятную ошибку) - ---- - -### Этап 5: Юнит тесты генератора (20 кейсов) - -#### 5.1. tests/unit/generator.test.ts - корректная генерация -- [ ] ✅ Создание выходного файла -- [ ] ✅ Корректная структура сгенерированного кода -- [ ] ✅ Обработка GET запросов -- [ ] ✅ Обработка POST запросов -- [ ] ✅ Обработка PUT запросов -- [ ] ✅ Обработка PATCH запросов -- [ ] ✅ Обработка DELETE запросов -- [ ] ✅ Генерация типов для request parameters -- [ ] ✅ Генерация типов для response -- [ ] ✅ Обработка path параметров -- [ ] ✅ Обработка query параметров -- [ ] ✅ Обработка request body -- [ ] ✅ Генерация enum'ов -- [ ] ✅ Обработка Bearer authentication -- [ ] ✅ Применение хука `onFormatRouteName` (убирание "Controller") -- [ ] ✅ Использование baseUrl из OpenAPI servers - -#### 5.2. tests/unit/generator.test.ts - edge cases -- [ ] ❌ Пустая OpenAPI спецификация -- [ ] ❌ Минимальная спецификация (только paths) -- [ ] ❌ Очень большая спецификация (100+ endpoints) -- [ ] ❌ Unicode символы в именах методов/типов - ---- - -### Этап 6: Юнит тесты утилит (10 кейсов) - -#### 6.1. tests/unit/utils/file.test.ts -- [ ] ✅ `fileExists()` - существующий файл возвращает true -- [ ] ✅ `fileExists()` - несуществующий файл возвращает false -- [ ] ✅ `readJsonFile()` - чтение локального файла -- [ ] ✅ `readJsonFile()` - чтение файла по URL -- [ ] ❌ `readJsonFile()` - невалидный JSON выбрасывает ошибку -- [ ] ❌ `readJsonFile()` - недоступный URL выбрасывает ошибку -- [ ] ✅ `ensureDir()` - создание директории -- [ ] ✅ `ensureDir()` - создание вложенных директорий -- [ ] ✅ `writeFileWithDirs()` - запись файла с автосозданием директорий - -#### 6.2. tests/unit/config.test.ts -- [ ] ✅ Валидация корректной конфигурации успешна -- [ ] ❌ Валидация без inputPath выбрасывает ошибку -- [ ] ❌ Валидация без outputPath выбрасывает ошибку -- [ ] ✅ Опциональное поле fileName работает - ---- - -### Этап 7: Тесты сгенерированного клиента (7 кейсов) - -#### 7.1. tests/integration/generated-client.test.ts - компиляция -- [ ] ✅ TypeScript компиляция без ошибок -- [ ] ✅ Отсутствие type errors -- [ ] ✅ Корректные импорты и экспорты - -#### 7.2. tests/integration/generated-client.test.ts - корректность API -- [ ] ✅ Все endpoints из спецификации присутствуют -- [ ] ✅ Корректные имена методов (без "Controller" префиксов) -- [ ] ✅ HttpClient правильно инициализируется -- [ ] ✅ Метод `setSecurityData` работает - ---- - -### Этап 8: Интеграционные E2E тесты (15 кейсов) - -#### 8.1. tests/integration/e2e-generation.test.ts - полный цикл -- [ ] ✅ CLI генерация → создание файла → импорт → использование -- [ ] ✅ Генерация из локального файла -- [ ] ✅ Генерация из URL -- [ ] ✅ Повторная генерация (перезапись файлов) - -#### 8.2. tests/integration/e2e-generation.test.ts - HTTP запросы с mock -- [ ] ✅ GET запрос без параметров -- [ ] ✅ GET запрос с query параметрами -- [ ] ✅ POST запрос с body -- [ ] ✅ PUT запрос -- [ ] ✅ PATCH запрос -- [ ] ✅ DELETE запрос -- [ ] ✅ Обработка 200 статуса -- [ ] ✅ Обработка 201 статуса -- [ ] ❌ Обработка 400 статуса (Bad Request) -- [ ] ❌ Обработка 401 статуса (Unauthorized) -- [ ] ❌ Обработка 404 статуса (Not Found) -- [ ] ❌ Обработка 500 статуса (Server Error) -- [ ] ❌ Обработка network errors -- [ ] ✅ Bearer token authentication -- [ ] ✅ Custom headers - ---- - -### Этап 9: Тесты производительности (5 кейсов) - -#### 9.1. tests/integration/performance.test.ts -- [ ] ✅ Генерация маленькой спецификации (< 1 секунды) -- [ ] ✅ Генерация средней спецификации (< 3 секунд) -- [ ] ✅ Генерация большой спецификации (< 10 секунд) -- [ ] ✅ Параллельная генерация нескольких проектов -- [ ] ✅ Повторная генерация не замедляется - ---- - -### Этап 10: Настройка CI (опционально) - -#### 10.1. GitHub Actions -- [ ] Создать `.github/workflows/test.yml` -- [ ] Настроить запуск тестов на push -- [ ] Настроить запуск тестов на PR -- [ ] Добавить badge в README.md - -#### 10.2. Pre-commit hooks -- [ ] Установить husky -- [ ] Добавить pre-commit хук для запуска тестов -- [ ] Добавить lint-staged для проверки только измененных файлов - ---- - -### Этап 11: Документация - -#### 11.1. Обновление README.md -- [ ] Добавить секцию "Тестирование" -- [ ] Описать команды запуска тестов -- [ ] Добавить информацию о coverage -- [ ] Добавить примеры запуска конкретных тестов - -#### 11.2. Создание CONTRIBUTING.md -- [ ] Правила написания тестов -- [ ] Структура тестов -- [ ] Как добавить новый тест -- [ ] Требования к coverage - ---- - -## Команды для разработки - -```bash -# Установка зависимостей -bun install - -# Запуск всех тестов -bun test - -# Запуск только юнит тестов -bun test:unit - -# Запуск только интеграционных тестов -bun test:integration - -# Запуск в watch режиме -bun test:watch - -# Запуск с coverage -bun test:coverage - -# Запуск конкретного файла -bun test tests/unit/cli.test.ts - -# Запуск конкретного теста -bun test -t "should generate client with custom name" -``` - ---- - -## Метрики успеха - -### Критерии завершения -- ✅ Все 72 тестовых кейса реализованы -- ✅ Coverage > 80% (желательно > 90%) -- ✅ Все тесты проходят успешно -- ✅ Время выполнения всех тестов < 30 секунд -- ✅ CI настроен и работает -- ✅ Документация обновлена - -### Показатели качества -- 🎯 **Coverage:** > 90% -- 🎯 **Скорость:** < 30 сек для всех тестов -- 🎯 **Стабильность:** 0 flaky тестов -- 🎯 **Читаемость:** Понятные названия и описания -- 🎯 **Поддерживаемость:** Минимум дублирования кода - ---- - -## Следующие шаги - -После завершения всех этапов: - -1. **Переключение в режим Code** для реализации -2. **Пошаговая реализация** согласно чек-листам -3. **Проверка coverage** после каждого этапа -4. **Рефакторинг** при необходимости -5. **Финальная проверка** всех тестов - ---- - -## Примечания - -- Все тесты должны быть изолированными и не зависеть друг от друга -- Использовать temporary directories для всех файловых операций -- Очищать ресурсы после каждого теста (cleanup) -- Следовать принципу AAA (Arrange, Act, Assert) -- Использовать описательные имена тестов -- Группировать связанные тесты с помощью `describe` \ No newline at end of file diff --git a/tests/README.md b/tests/README.md index 4f594ba..9ca46d9 100644 --- a/tests/README.md +++ b/tests/README.md @@ -172,148 +172,6 @@ bun test -t "should generate client with custom name" - ✅ Bearer authentication - ✅ Custom headers -## Написание новых тестов - -### Пример юнит теста - -```typescript -import { describe, test, expect, beforeEach, afterEach } from 'bun:test'; -import { setupTest } from '../helpers/setup.js'; - -describe('My Feature', () => { - let tempDir: string; - let cleanup: () => Promise; - - beforeEach(async () => { - const setup = await setupTest(); - tempDir = setup.tempDir; - cleanup = setup.cleanup; - }); - - afterEach(async () => { - await cleanup(); - }); - - test('should do something', () => { - // Arrange - const input = 'test'; - - // Act - const result = myFunction(input); - - // Assert - expect(result).toBe('expected'); - }); -}); -``` - -### Пример интеграционного теста - -```typescript -import { describe, test, expect, beforeAll, afterAll } from 'bun:test'; -import { createMockServer } from '../helpers/mock-server.js'; - -describe('Integration Test', () => { - let mockServer; - - beforeAll(() => { - mockServer = createMockServer(); - mockServer.start(); - }); - - afterAll(() => { - mockServer.stop(); - }); - - test('should make HTTP request', async () => { - const response = await fetch('https://api.example.com/users'); - const data = await response.json(); - - expect(response.status).toBe(200); - expect(Array.isArray(data)).toBe(true); - }); -}); -``` - -## Лучшие практики - -### 1. Изоляция тестов -- Каждый тест должен быть независимым -- Использовать `beforeEach`/`afterEach` для setup/cleanup -- Не полагаться на порядок выполнения - -### 2. Именование -- Описательные названия: `"должен создать файл при корректных параметрах"` -- Группировать с помощью `describe` -- Использовать принцип AAA (Arrange, Act, Assert) - -### 3. Очистка ресурсов -- Всегда очищать временные файлы -- Закрывать соединения -- Использовать `afterEach` для гарантии очистки - -### 4. Async/Await -- Всегда использовать `async/await` для асинхронных операций -- Не забывать `await` перед промисами -- Устанавливать таймауты для долгих операций - -### 5. Mock данные -- Использовать фикстуры для тестовых данных -- Не хардкодить данные в тестах -- Переиспользовать тестовые данные - -## Troubleshooting - -### Тесты падают с timeout -Увеличьте таймаут для конкретного теста: -```typescript -test('long running test', async () => { - // test code -}, 60000); // 60 секунд -``` - -### Тесты не очищаются -Проверьте что `cleanup()` вызывается в `afterEach`: -```typescript -afterEach(async () => { - await cleanup(); -}); -``` - -### Mock сервер не работает -Убедитесь что: -1. Сервер запущен в `beforeAll` -2. Сервер остановлен в `afterAll` -3. Хендлеры правильно настроены - -### Файлы не находятся -Используйте абсолютные пути или пути относительно `__dirname`: -```typescript -const fixturePath = join(__dirname, '../fixtures/test.json'); -``` - -## CI/CD - -Тесты автоматически запускаются при: -- Push в любую ветку -- Создании Pull Request -- Перед деплоем - -Требования для прохождения CI: -- ✅ Все тесты должны пройти -- ✅ Coverage > 80% -- ✅ Нет TypeScript ошибок -- ✅ Нет lint ошибок - -## Метрики - -### Целевые показатели -- **Coverage:** > 90% -- **Скорость:** < 30 сек для всех тестов -- **Стабильность:** 0 flaky тестов - -### Текущие показатели -Запустите `bun test:coverage` для просмотра актуальных метрик. ## Дополнительная информация