You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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-совместимости, пока не мигрируем полностью.
Статус: закрыт через #395 / #433; RepeaterFieldService — #493.
Уровень 2 — интеграционные тесты stateful-логики (главная ценность, дорого)
Здесь живут реальные баги. Требует тестовой БД (SQLite in-memory или MySQL service в CI) + bootstrap MODX-lite или мок xPDO. Это большой инфраструктурный трек — отдельные PR по одному домену.
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.
Что предлагаю по порядку
Сейчас: уровень 0 (PHPStan в CI) — один PR, дёшево, огромный ROI.
Описание
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).phpstanв.github/workflows/ci.ymlрядом сPHP lint + smoke.composer stanскрипт →phpstan analyse -c phpstan.neon --memory-limit=1G.Почему первым: нулевая инфраструктурная стоимость (всё уже настроено), максимальный ROI — ловит именно тот класс ошибок, что мы вылавливаем руками.
Уровень 1 — PHPUnit каркас + чистые функции (см. #395)
Отслеживается в #395. Кратко: подключить PHPUnit 11, перенести 5 существующих smoke в нормальные тест-кейсы с автодискавери и человеческими assertions. Smoke-раннер остаётся для CI-совместимости, пока не мигрируем полностью.
Кандидаты (чистые функции, без MODX):
Utils::parseImportedOptionValue(есть smoke)EmailVerificationService::buildDefaultVerifyRequestUrl(есть smoke)ms3Phinx*charset/collation-функции изphinx.phpOptionColumnSpec::isValidOptionKey/isValidFieldName(feat(grid): add option field type for category products grid #154 — SQL-injection whitelist, критично)RepeaterFieldServicenormalize/validate pipeline (feat(extra-fields): repeater field type (ms3-repeater) #301 — чистая логика без БД)GridEditorReferenceRegistry::isAllowlistedEndpoint(feat(grid): add select/combo editor types for category products inline edit #157 — SSRF-защита, критично для безопасности)Статус: закрыт через #395 / #433;
RepeaterFieldService— #493.Уровень 2 — интеграционные тесты stateful-логики (главная ценность, дорого)
Здесь живут реальные баги. Требует тестовой БД (SQLite in-memory или MySQL service в CI) + bootstrap MODX-lite или мок xPDO. Это большой инфраструктурный трек — отдельные PR по одному домену.
Приоритет по «частоте багов за последние релизы»:
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.OrderService,OrderDraftManager,OrderFinalizeService,clampComputedTotal) — [Feature] Отрицательная стоимость доставки и оплаты #211, [Feature] Пересчет стоимости заказа при смене способа доставки в админке #212, Защита total от ухода в минус + UX-маркер для скидок в настройках доставки/оплаты #265, fix(order): multiply draft weight by product count #403. Расчёт стоимости, веса, negative-clamp, draft → final.ProductDataPayloadTrait,updateProductDatawhitelist) — [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 регрессии.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-защита.Cartfacade + services) — базовый флоу add/change/remove, пока почти без покрытия.Статус: starter + follow-up в #493 (SQLite Fake xPDO / draft store; не полный MySQL service в CI):
OptionSyncServiceTestOrderFinalizeServiceTestUpdateProductDataPermissionsTestResolveApiTokenTestCartFacadeDraftStoreTestУровень 3 — Vue/JS (низкий приоритет сейчас)
ESLint уже в CI. Юнит-тесты компонентов (Vitest) — только если появится регрессионная боль во фронте. Composables из #397 (
useGridFilterParams,useCategoryProductsInlineEdit) — хорошие кандидаты, они чистые.Статус: Vitest + happy-dom в #493 (
useGridFilterParams,useCategoryProductsInlineEdit,formatLocalDateYmd); CI step в jobvueManager lint.Метрика готовности к stable
Связано с внутренним критерием перехода beta → stable. «Install reliability» и «строгий patch-контракт» частично защищаются уровнями 0-1; но уверенность в отсутствии data-loss даёт только уровень 2. Без интеграционного покрытия горячих путей мы каждый релиз полагаемся на ручное прокликивание на dev.
Что предлагаю по порядку