nns
17a454cce5
test(e2e): scenario documents-edge — критичные edge-кейсы посту
...
10 шагов покрывают самую опасную зону системы (потеря денег/остатков):
1. Bootstrap: орг + admin + product + supply (10 шт по 100 KZT).
2. Supply.Post → stock=10 invariant.
3. RetailSale qty=15 (>stock 10) → POST /post → 409 «Недостаточно».
4. После заблокированного post: stock=10 + Stock == Σ StockMovement.
5. RetailSale PaidCash+PaidCard < Total → 4xx (валидация платежа).
6. PUT проведённой Supply → 409.
7. DELETE проведённой Supply → 409.
8. После Sale qty=5: unpost Supply qty=10 → 409 (stock уйдёт в минус).
9. Дубль штрихкода в одной орге → 4xx.
10. Тот же штрихкод в другой орге → 201 (per-tenant unique).
Запуск: `bash tests/e2e/run.sh documents-edge --api-only`.
Все 10 шагов зелёные после фиксов RetailSale.Post + Supply.Unpost.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 12:33:51 +05:00
nns
ae88a16fd2
test(e2e): scenario multi-tenant-isolation — 12 шагов проверки изоляции
...
Новый E2E-сценарий покрывает критичную для multi-tenant SaaS поверхность:
1. Создание двух независимых организаций (Alpha и Beta) через SuperAdmin.
2. Логин под admin'ами Alpha и Beta, проверка разных org_id в JWT.
3. Alpha seed'ит counterparty + product.
4. Beta GET по прямым ID Alpha → 404 (не 200, не 403, не 500).
5. Beta GET листинги — Alpha-записей нет.
6. Beta PUT/DELETE по ID Alpha с валидным телом → 404.
7. Beta POST product со ссылкой на supplier Alpha → 4xx.
8. Beta-admin подделывает X-Org-Override:{alphaId} → запрос
игнорирует заголовок (только SuperAdmin может override).
9. SuperAdmin без override видит обе организации.
10. SuperAdmin + X-Org-Override без reason → read-only (PUT 403).
11. SuperAdmin + X-Org-Override + Reason ≥10 → PUT 200, audit_log растёт.
12. Stock + StockMovements Alpha не видны Beta.
Применение: `bash tests/e2e/run.sh multi-tenant-isolation --api-only`.
Использует ту же runner-инфраструктуру что и full-cycle.yml.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 12:25:05 +05:00
nns
37cd9aa94b
test(e2e): починка контрактов supply/sale + EAN-13 + bug-hunt + full-pass отчёт
...
Контракты до фикса не совпадали с реальными:
- Product: unitId/groupId/retailPrice → unitOfMeasureId/productGroupId/prices[],
плюс обязательный barcodes[] (генерим валидный EAN-13).
- Supply: counterpartyId/docDate/lines.price → supplierId/date/lines.unitPrice,
плюс обязательный currencyId.
- RetailSale: путь /api/sales/retail-sales 404 → /api/sales/retail; payload
обновлён под RetailSaleInput (storeId, currencyId, payment, paidCash и т.п.).
Шаги 9-12 теперь полностью проходят (не skip). Добавлены deep-bug-hunt'ы:
- Supply без supplierId / с пустым lines[]
- двойной post Supply / RetailSale → 409
- stock_movements vs Stocks.Quantity консистентность
- RetailPoint с несуществующим storeId
- продажа qty>остатка (выявил блокирующий баг — продаёт)
- discount на line, отрицательные qty/price
- stock_movements.Type = RetailSale (2)
Отчёт: tests/e2e/reports/full-cycle-2026-05-08-full-pass.md
Финальный счёт 10 ✓ / 2 ✗ / 0 ⚠ / 0 ◯ — две ✗ это РЕАЛЬНЫЕ баги:
[HIGH] step11 oversell проходит /post (нужна валидация qty≤stock)
[MEDIUM] step08 Supply без supplierId → 500 вместо 400
2026-05-08 11:01:56 +05:00
nns
ee127b2785
fix(migrations): добавить [Migration] атрибут для Phase5c — без него Migrate() не находит миграцию
...
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 55s
CI / Web (React + Vite) (push) Successful in 42s
Docker API / Build + push API (push) Successful in 1m17s
Docker API / Deploy API on stage (push) Successful in 18s
stage api зашёл в crash-loop после деплоя phase5c: DevDataSeeder упал
с «column IsActive does not exist», потому что миграция Phase5c не
была подхвачена db.Database.Migrate(). EF Core ищет миграции по
[MigrationAttribute] на классе (или Designer-файле, который этот
атрибут содержит). Без него миграция в сборке есть, но не известна
runtime-механизму.
Также чиню e2e: URL единиц был /api/catalog/units (404), правильный —
/api/catalog/units-of-measure.
2026-05-08 01:29:51 +05:00
nns
7bb941259a
feat(e2e): infrastructure + first full-cycle scenario + baseline report
...
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 1m20s
CI / Web (React + Vite) (push) Successful in 42s
Декларативные end-to-end сценарии в tests/e2e/. YAML описывает шаги,
TypeScript-handler — конкретные API/UI/DB-проверки. Отчёт в Markdown.
Структура:
- runner.ts : entry, парсит YAML, прогоняет steps, пишет report
- run.sh : pnpm install + tsx
- lib/api.ts : axios + login() (через /connect/token + /api/me)
- lib/db.ts : docker exec psql, resetTenantData(), countRows()
- lib/report.ts : Markdown-аккумулятор (steps + bugs + ux + gap + perf)
- scenarios/full-cycle.yml : 12 шагов
- scenarios/full-cycle.steps.ts : handlers (один на шаг)
- README.md : как добавить новый сценарий
reset_db в preconditions:
- TRUNCATE tenant-таблиц CASCADE
- AspNet*/users — оставляем только admin@food-market.local
- OpenIddict tokens — все valid → revoked
- Реестр products + системные справочники + миграции + platform_settings — НЕ трогаем
Запуск: tests/e2e/run.sh full-cycle [--api-only]
Первый прогон (--api-only, baseline в reports/full-cycle-2026-05-07-baseline.md):
- 8 ✓ / 1 ✗ / 3 ◯ из 12.
- Critical bug: Cashier видит /api/organization/employees через API
(нет [Authorize(Roles="Admin")] на List endpoint).
- High: при CreateOrg через SuperAdmin не сидируются tenant-units —
пустой каталог измерений у новой org (DevDataSeeder.SeedTenantReferencesAsync
должен вызываться, но не вызывается).
- Logic gaps: реестр products tenant-scoped и новая org стартует с
пустым каталогом; SuperAdmin /organizations не валидирует ФЛК
телефона; Cashier не получает Identity-роль "Cashier" при создании
через /employees.
UI-шаги (Playwright) в этом коммите не покрыты — runner работает в
--api-only режиме. UI-extension добавим следующим коммитом, не блокирует
получение полезного отчёта.
2026-05-08 00:05:52 +05:00