Files
pchelpmaster/docs/testing.md
T

5.4 KiB
Raw Blame History

Тестирование

Разработка ведётся по TDD: тесты пишутся до реализации.

Уровни тестов

Уровень Что проверяет Где лежит Команда
API (e2e бэкенда) схема, миграции, правила доступа, изоляция пользователей, хуки PocketBase tests/api/**/*.api.spec.ts pnpm test:api
Unit доменные функции, компоненты и сервисы с фейками вместо PocketBase рядом с кодом, src/**/*.spec.ts pnpm test
Integration PocketBase-реализации репозиториев и сервисов против настоящего PocketBase рядом с кодом, src/**/*.integration.spec.ts pnpm test:integration
E2E пользовательские сценарии в браузере, SSR, доступность (axe) tests/e2e/**/*.e2e.ts pnpm e2e
E2E prod сценарии на production-сборке, включая изоляцию данных при SSR tests/e2e/ (проект ssr-prod) pnpm e2e:prod

Команды появляются по мере того, как настраиваются соответствующие стенды.

Контрактные тесты репозиториев

У каждого репозитория две реализации: PocketBase (data/) и фейк в памяти (testing/). Чтобы фейк не расходился с реальностью, поведение описывается один раз:

// tags/testing/tag-repository.contract.ts
export function describeTagRepositoryContract(
    setup: () => Promise<{ repoA: TagRepository; repoB: TagRepository }>,
) {
    describe('контракт TagRepository', () => {
        it('не показывает пользователю B метки пользователя A', async () => { /* ... */ });
    });
}

и вызывается дважды: в in-memory-tag-repository.spec.ts (быстро, в pnpm test) и в pocketbase-tag-repository.integration.spec.ts (на тестовом PocketBase, в pnpm test:integration).

Тестовый PocketBase

API-, integration- и e2e-тесты работают с отдельным временным экземпляром PocketBase, а не с pocketbase/pb_data:

  1. Создаётся временная папка данных.
  2. Создаётся суперпользователь (pocketbase superuser upsert) с данными из .env (PB_SUPERUSER_EMAIL, PB_SUPERUSER_PASSWORD).
  3. Запускается pocketbase serve на свободном порту с --dir <временная папка> --migrationsDir pocketbase/pb_migrations --hooksDir pocketbase/pb_hooks; миграции применяются при старте.
  4. Ожидание готовности по GET /api/health.
  5. После прогона процесс останавливается, папка удаляется.

Код запуска один на все уровни: tests/support/pocketbase-server.ts.

Правила написания тестов

  • Каждый тест создаёт своих пользователей с уникальными email (user-<случайная строка>@test.local). Тесты не зависят друг от друга и от порядка, поэтому могут идти параллельно и не нуждаются в очистке.
  • Хелперы (tests/support/): createUser(), asUser(user), asGuest(), asSuperuser() возвращают готовый экземпляр PocketBase SDK.
  • Изоляцию проверяем всегда двумя пользователями: A создаёт данные, B пытается их прочитать, найти через list/filter, изменить, удалить, сослаться на них. Плюс гость.
  • Тест проверяет поведение, а не реализацию: статус ответа, тело, состояние после операции (перечитать суперпользователем).
  • Unit-тесты компонентов используют фейки из <feature>/testing/ и не обращаются к сети.
  • Компонентные тесты ищут элементы по ролям и подписям (как пользователь и скринридер), а не по CSS-классам.
  • E2E-тесты: каждый сценарий регистрирует своего пользователя через UI или API; на ключевых страницах выполняется проверка axe (@axe-core/playwright) без нарушений.
  • Названия тестов на русском и описывают поведение: it('не отдаёт гостю чужую метку').
  • Пока реализации нет, тесты должны компилироваться: для этого создаются минимальные заглушки контрактов (типы, абстрактные классы, методы с throw new Error('Not implemented')). Новые тесты падают из-за невыполненных ожиданий, а не из-за ошибок импорта или стенда.