Роудмап / План тестирования / Автотесты: апгрейд + флоу
Обновлено: 1 июня

Автотесты и покрытие — апгрейд + флоу

Срез по типам тестов: что покрыто, чего не хватает, в каком порядке делать. Фокус — апгрейд; плюс авторизация, маркет/сделки, кейсы, баланс, поддержка. Вывод (withdrawal) исключён — покрыт отдельно. Это дополнение к ручным клик-сценариям (см. Апгрейд — ручной план).

Статус апгрейда (01.06): P0 и P1 закрыты — честность шанса (Монте-Карло), безопасность входа, API-краевые, E2E-проклик со скринами. Прогон: 367 PHP + 10 E2E зелёные. Осталось только опциональное (P2). Подробности — в блоке «1. Апгрейд» ниже.

🧪 Unit — формулы/логика 🔌 Feature — API+БД (sqlite) 🖱️ E2E — Playwright 🎲 Монте-Карло — честность RNG ⚔️ Конкуренция — гонки/двойная выдача 🔒 Безопасность

Статус: есть частично нет · Приоритет: P0 P1 P2

1. Апгрейд приоритетный блок

Код: UpgradeController (items/store/history/feed), Actions\Upgrade\CreateUpgrade, модели Upgrade/UpgradeItem, фронт UpgradePage.vue. Формула: chance = ставка / цена_цели × (100 − комиссия%), коридор 1%…70%, ставка = предметы + баланс, победа при roll < chance.

Что уже есть

Feature ×15 UpgradeApiTest: авторизация, дубли id, чужие предметы, коридор шанса в items, фильтры каталога, отклонение вне коридора и сверх max_bet, подделка chance/outcome игнорируется, расход предметов + roll_value, повторная ставка использованным, победный предмет с именем/картинкой, ставка балансом, фид только побед.

✅ Реализовано 01.06.2026 (ветка test/upgrade-coverage)

СДЕЛАНОМонте-Карло Честность шанса: вынес сервис UpgradeRng (единый бросок), `UpgradeRngMonteCarloTest` — на 50k прокрутках доля побед = заявленному шансу ±2 п.п. для 1/5/30/50/70%; roll ∈ [0,99.99]; победа строго roll < chance (на границе — проигрыш). Главное — честность — подтверждено.
СДЕЛАНОFeature Краевые (`UpgradeEdgeCasesTest`, 9): границы коридора (ровно 1% и 70% — ок, чуть за — 422), нехватка баланса → 422 + полный откат (предмет не сгорает, записи нет), лимит предметов (4 ок / 5 — 422), невалидная цель (цена 0), пустая ставка.
СДЕЛАНОЛеджер При ставке балансом — списание отражено транзакцией (reference = Upgrade), баланс уменьшается ровно на ставку; баланс нельзя потратить дважды (детерминированная грань конкуренции под lockForUpdate).
СДЕЛАНОE2E `tests-e2e/09-authorized-upgrade.spec.ts`: предмет → цель → шанс посчитан (28.33%) → прокрутка → исход win/lost + предмет списан; «нечем апать» для пустого инвентаря. Со скринами. Находка: welcome-модалка перехватывала клики → пофикшено сидом. Полный E2E-сьют 10/10.
СДЕЛАНОБезопасность Вход без Steam (`/api/v1/test/login`) = 404 в production / при выключенном флаге (`TestAuthSecurityTest`).

Осталось (опционально, P2)

P2Конкуренция Истинный параллелизм (2 апгрейда на 1 предмет одновременно) в sqlite-тестах не воспроизвести — гарантию даёт lockForUpdate + детерминированные тесты на повторную ставку/двойной расход. Реальный параллельный прогон — через нагрузочную команду (как cases:stress-test), если понадобится.
P2Provably-fair Поля server_seed/client_seed есть, но не используются. Решить, вводим ли; если да — тест детерминированного реплея.
P2Фронт-unit Расчёт chance в UI = серверному; пресеты; угол индикатора гейджа.

2. Авторизация (Steam + Sanctum)

СДЕЛАНОБезопасность /api/v1/test/login = 404 в production / при выключенном флаге (middleware EnsureTestAuthEnabled) — закреплено `TestAuthSecurityTest`.
P1Feature Обмен кода (exchange): TTL кэша, повторный обмен невалиден, неверный код; создание/обновление юзера из Socialite (мок).

3. Маркет + Сделки кроме вывода

Feature ~29 Покупка/корзина, отправка/завершение трейда, отмена, settle, опрос Steam, трейд-бан, отчёт расширения, гостевой маркет, инвентарь/листинг.
P1Конкуренция Две покупки одного лота (lockForUpdate на MarketItem) — лот не продаётся дважды; покупка vs снятие с продажи.
P1Идемпотентность Повтор завершения / отчёта расширения не платит продавцу дважды.
P1E2E Полный цикл покупки в браузере (корзина → покупка → состояние сделки). Сейчас E2E только «добавить в корзину».

4. Кейсы самый зрелый блок

богато CaseOpeningApiTest(15), FreeCaseOpeningTest(7), PremiumPricing(3), AntiLuck(6), FundLedger(7), AtomicMultiOpen(3), Concurrent(3), Unit EconomyValidator, Монте-Карло MonteCarloCaseSimulationTest, CLI cases:simulate / cases:stress-test.
P2E2E/граничные E2E мульти-открытия и продажи из инвентаря; граничные конфиги экономики; E2E «скрытый кейс» (пустой уровень).

5. Баланс / транзакции / депозит

Feature LedgerIdempotency (Unit), ShopBalanceService(10), DepositCallbackSecurity(3, подпись вебхука), DepositRequest(3).
P1Конкуренция Параллельные списания с одного баланса — не уходит в минус, нет потерянных обновлений.
P1E2E Полный депозит-флоу (инициировать → вебхук → баланс вырос).

6. Поддержка (тикеты)

Feature SupportTicketApiTest(10), SupportNotification(5), ModeratorStats.
P2E2E/права E2E (создать → ответ → закрытие); права модератора на чужие тикеты.

7. Сквозной happy-path E2E

P1E2E Депозит → открыть кейс → поставить выигранный предмет в апгрейд → выигрыш → новый предмет в инвентаре. Связывает баланс + кейсы + апгрейд, ловит интеграционные стыки.

8. Приоритеты — по порядку

Приор.ЗадачаТипПочему
Монте-Карло честности шанса апгрейдаСтатистикаСделано: win-rate = шансу ±2 п.п.
test-login = 404 в productionБезопасностьСделано: TestAuthSecurityTest
Апгрейд: граничные + леджерFeatureСделано: UpgradeEdgeCasesTest
Апгрейд: E2E-спекE2EСделано: 09-authorized-upgrade + скрины
P1Маркет: конкуренция на лот + E2E покупкиКонкуренция/E2EЛот не продаётся дважды
P1Баланс: конкуренция + депозит-флоу E2EКонкуренция/E2EБаланс не уходит в минус
P2Provably-fair, фронт-unit, E2E кейсов/поддержкиUnit/E2EПолировка

9. Конвенции

Feature-тесты на sqlite :memory: (phpunit форсит) — фабрики, без БД-моков.
Деньги — всегда DB::transaction + lockForUpdate + запись в transactions.
RNG — только через RandomSource; в тестах биндить SeededSource(seed) для детерминизма.
НЕ гонять весь PHPUnit-сьют в app-test (E2E-стенд) — память; полный прогон — make test / CI-job test.
E2E: данные в TestScenariosSeeder; вход — POST /api/v1/test/login (только при TEST_AUTH_ENABLED). После фронт-правок — npm run build.