Skip to content

[Testing] Roadmap автоматического покрытия: PHPStan в CI, PHPUnit, интеграционные тесты #429

Closed

Description

@biz87

Описание

Roadmap по автоматическому покрытию MiniShop3. Дополняет уже открытый #395 (PHPUnit-каркас + первые unit-тесты на чистые функции) — здесь общая картина: что покрываем, в каком порядке, с приоритетом по риску.

Контекст. После #394 (CI-гейт: php -l + smoke + ESLint) на PR теперь есть автопроверка, включён branch protection на beta. Но текущее покрытие — 5 standalone smoke-скриптов на чистые функции (charset-нормализация, URL email-verify, CSV option parse, direct-filter-контракт). Реальные баги последних 2 месяцев (repeater save-drop, inline-edit type mismatch, null payload semantics) сидели в stateful-логике с БД, которую smoke-тесты в принципе не достают.

Уровень 0 — PHPStan в CI (highest priority, дешёвый)

PHPStan уже настроен в проекте (phpstan.neon + phpstan-baseline.neon, level 5). Мы гоняем его вручную на каждом ревью — это главный ловец регрессий типов/сигнатур. Он не в CI-гейте из #394 (автор явно оставил follow-up).

  • Добавить job phpstan в .github/workflows/ci.yml рядом с PHP lint + smoke.
  • composer stan скрипт → phpstan analyse -c phpstan.neon --memory-limit=1G.
  • Baseline остаётся — падаем только на новых ошибках, не на исторических 168.
  • После стабилизации — добавить в required checks branch protection.

Почему первым: нулевая инфраструктурная стоимость (всё уже настроено), максимальный ROI — ловит именно тот класс ошибок, что мы вылавливаем руками.

Уровень 1 — PHPUnit каркас + чистые функции (см. #395)

Отслеживается в #395. Кратко: подключить PHPUnit 11, перенести 5 существующих smoke в нормальные тест-кейсы с автодискавери и человеческими assertions. Smoke-раннер остаётся для CI-совместимости, пока не мигрируем полностью.

Кандидаты (чистые функции, без MODX):

Статус: закрыт через #395 / #433; RepeaterFieldService — #493.

Уровень 2 — интеграционные тесты stateful-логики (главная ценность, дорого)

Здесь живут реальные баги. Требует тестовой БД (SQLite in-memory или MySQL service в CI) + bootstrap MODX-lite или мок xPDO. Это большой инфраструктурный трек — отдельные PR по одному домену.

Приоритет по «частоте багов за последние релизы»:

  1. Options sync (OptionService / OptionSyncService / ProductDataService::saveOptions) — При копировании товара через «Дублировать ресурс» теряются значения опций #257, [Bug] Не удаляется опция из товара #199, feat(extra-fields): repeater field type (ms3-repeater) #301, fix(import): split multi-value option columns in CSV import #312 все крутились тут. Save/removeOther-семантика, multi-value, repeater exclusion.
  2. Order flow (OrderService, OrderDraftManager, OrderFinalizeService, clampComputedTotal) — [Feature] Отрицательная стоимость доставки и оплаты #211, [Feature] Пересчет стоимости заказа при смене способа доставки в админке #212, Защита total от ухода в минус + UX-маркер для скидок в настройках доставки/оплаты #265, fix(order): multiply draft weight by product count #403. Расчёт стоимости, веса, negative-clamp, draft → final.
  3. Product data payload (ProductDataPayloadTrait, updateProductData whitelist) — [Feature] кастомные поля msProductData в процессор create product #297, fix(product): сохранение Data и extra fields в процессорах Create/Update #298, feat(extra-fields): repeater field type (ms3-repeater) #301, fix(api): per-field null payload semantics in Manager API (#289) #310. Null-семантика, extra-field whitelist, silent-drop регрессии.
  4. Customer auth / token (AuthManager, TokenService) — [Bug] Не работает авторизация покупателя #285, fix(manager): prevent search autofill after customer edit (#286) #319, fix(customer): stop checkout token takeover via email #391, fix(customer): reject expired API tokens instead of silent renew #396, fix(api): omit customer secrets from profile/add responses #428. Session/token lifecycle, expired-token, takeover-защита.
  5. Cart (Cart facade + services) — базовый флоу add/change/remove, пока почти без покрытия.

Статус: starter + follow-up в #493 (SQLite Fake xPDO / draft store; не полный MySQL service в CI):

  1. Options sync — OptionSyncServiceTest
  2. Order flow — clamp / draft cost / OrderFinalizeServiceTest
  3. Product payload — trait + UpdateProductDataPermissionsTest
  4. Auth/token — ResolveApiTokenTest
  5. Cart — pure helpers + CartFacadeDraftStoreTest

Уровень 3 — Vue/JS (низкий приоритет сейчас)

ESLint уже в CI. Юнит-тесты компонентов (Vitest) — только если появится регрессионная боль во фронте. Composables из #397 (useGridFilterParams, useCategoryProductsInlineEdit) — хорошие кандидаты, они чистые.

Статус: Vitest + happy-dom в #493 (useGridFilterParams, useCategoryProductsInlineEdit, formatLocalDateYmd); CI step в job vueManager lint.

Метрика готовности к stable

Связано с внутренним критерием перехода beta → stable. «Install reliability» и «строгий patch-контракт» частично защищаются уровнями 0-1; но уверенность в отсутствии data-loss даёт только уровень 2. Без интеграционного покрытия горячих путей мы каждый релиз полагаемся на ручное прокликивание на dev.

Что предлагаю по порядку

  1. Сейчас: уровень 0 (PHPStan в CI) — один PR, дёшево, огромный ROI.
  2. Далее: уровень 1 ([Feature] PHPUnit: каркас + 2–3 unit-теста на чистые функции #395) — каркас + перенос smoke + добавить security-критичные чистые функции (OptionColumnSpec, GridEditorReferenceRegistry).
  3. Затем итеративно: уровень 2 по одному домену, начиная с options sync и order flow.
  4. Уровень 3 — по потребности.

Activity

  1. added
    priority: highВажно исправить в ближайшее время
    enhancementNew feature or request
    tech-debtMaintainability / refactor / architecture debt
    on Jul 23, 2026
  2. self-assigned this
    on Jul 23, 2026
  3. Ibochkarev commented on Aug 1, 2026

    @Ibochkarev
    Member

    Прогресс по roadmap (не полное закрытие):

    Уже на beta: Level 0 (job PHPStan + composer stan + baseline), Level 1 каркас PHPUnit (#433 / #395), security-критичные pure helpers.

    PR: #493 — PHPUnit для RepeaterFieldService (пробел Level 1) + clampComputedTotal (starter Level 2).

    Осталось:

    1. Добавить PHPStan в required checks branch protection на beta (сейчас только PHP lint + smoke + vueManager lint).
    2. Level 2 с БД: options sync → order flow → product payload → auth/token → cart (отдельные PR).
    3. Level 3 Vitest — по потребности.

    Refs #493

  4. Ibochkarev commented on Aug 1, 2026

    @Ibochkarev
    Member

    Level 0 — done: PHPStan добавлен в required checks на beta (рядом с PHP lint + smoke и vueManager lint).

  5. Ibochkarev commented on Aug 1, 2026

    @Ibochkarev
    Member

    Level 2 добавлен в #493:

    Домен Покрытие
    Options sync OptionSyncServiceTest (SQLite memory)
    Order flow ClampComputedTotalTest + OrderDraftCostClampTest
    Product payload ProductDataPayloadTraitTest
    Auth/token ResolveApiTokenTest
    Cart CartItemManagerPureTest

    composer test → 93 tests OK. CI green. Follow-up: finalize / cart facade с более глубоким Fake draft.

  6. Ibochkarev commented on Aug 1, 2026

    @Ibochkarev
    Member

    Level 3 в #493:

    • Vitest + happy-dom (npm test)
    • useGridFilterParams, useCategoryProductsInlineEdit, formatLocalDateYmd
    • CI: step Vitest в job vueManager lint (имя job не меняли — branch protection)

    Roadmap 0–3 закрыт в рамках этого PR (Refs #429).

  7. Ibochkarev commented on Aug 1, 2026

    @Ibochkarev
    Member

    Level 2 follow-up в #493:

    • OrderFinalizeServiceTest — nf / already finalized / validation / happy path (skip_validation + costs + status)
    • CartFacadeDraftStoreTest — add → change → remove на in-memory draft store
    • UpdateProductDataPermissionsTest — save_document / policy / 404 / negative price / whitelist drop

    composer test → 104 tests OK.

  8. Ibochkarev commented on Aug 1, 2026

    @Ibochkarev
    Member

    Roadmap 0–3 — выполнено

    Уровень Статус
    0 PHPStan job + composer stan + baseline; required check на beta (PHPStan рядом с PHP lint + smoke и vueManager lint)
    1 PHPUnit pure #395 / #433 + RepeaterFieldService в #493
    2 stateful #493: options sync, order finalize/clamp, product payload/permissions, token resolve, cart draft store (SQLite/Fake; без MySQL service)
    3 Vitest #493: composables + CI

    PR: #493

    Дальнейшее углубление (MySQL service в CI, полный AuthManager lifecycle) — отдельные issues по потребности.

  9. added a commit that references this issue on Aug 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestpriority: highВажно исправить в ближайшее времяtech-debtMaintainability / refactor / architecture debt

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions