e31ea5354a
Заменяет static-снапшот LEAD_STATUSES в коде на live-данные из БД. Custom slug'и (добавленные после deployment'а) теперь видны UI без rebuild'а. Backend: - LeadStatus model (PK=slug string, incrementing=false, timestamps=null). - LeadStatusController::index — GET /api/lead-statuses, ORDER BY sort_order, slug. Таблица глобальная (не tenant-aware), auth не требуется на MVP. Pest +5 (LeadStatusesIndexTest): - 200 + не пустой / все 14 системных slug'ов из seed / все нужные поля / sort_order ASC / кастомный slug после INSERT появляется в endpoint'е. Frontend: - api/leadStatuses.ts::listLeadStatuses — GET helper. - stores/leadStatuses.ts::useLeadStatusesStore — Pinia setup-store: statuses default = LEAD_STATUSES snapshot (UI работает без fetch'а), load(force=false) идемпотентен, bySlug computed Map, findBySlug helper. На fail — snapshot остаётся, fetchError=true. - DealsView/KanbanView/DealDetailDrawer переехали со static-импорта LEAD_STATUSES на store. KanbanView использует safe-access dealsByStatus[slug] || [] (защита от custom slug'а из API без seeded column). load() в onMounted у обоих view'ов. Vitest +7 (leadStatusesStore.spec.ts): - initial snapshot / findBySlug existing & null / load success replace + loaded / load reject — fetchError + snapshot fallback / load идемпотентен / load(force=true) refetch. - 2 spec'а DealDetailDrawer получили setActivePinia(createPinia()) в beforeEach (без этого Pinia store-injection в jsdom падает). PHPStan baseline регенерирован. Регресс: - Lint+type-check+format passed. - Vitest 280/280 за 19.44 сек (+7 от 273). - Vite build 1.17 сек. - Pint + PHPStan passed. - Pest 210/210 за 24.59 сек (+5 от 205, 840 assertions). Реестр v1.63→v1.64 / CLAUDE.md v1.54→v1.55. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
73 lines
2.7 KiB
PHP
73 lines
2.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
/**
|
|
* Тесты GET /api/lead-statuses — глобальный lookup статусов воронки.
|
|
*
|
|
* Таблица lead_statuses не tenant-aware, seeded в schema.sql:2130 (14 системных
|
|
* статусов: new/viewed/worked/base/missed/negotiations/waiting_payment/
|
|
* partnership/paid/closed/test_drive/hot/replacement/final_missed).
|
|
*/
|
|
uses(DatabaseTransactions::class);
|
|
|
|
test('GET /api/lead-statuses возвращает 200 и не пустой список', function () {
|
|
$r = $this->getJson('/api/lead-statuses');
|
|
|
|
$r->assertStatus(200);
|
|
expect($r->json('lead_statuses'))->toBeArray();
|
|
expect(count($r->json('lead_statuses')))->toBeGreaterThanOrEqual(14);
|
|
});
|
|
|
|
test('GET /api/lead-statuses возвращает все 14 системных статусов из seed', function () {
|
|
$r = $this->getJson('/api/lead-statuses');
|
|
|
|
$slugs = collect($r->json('lead_statuses'))->pluck('slug')->all();
|
|
$expected = [
|
|
'new', 'viewed', 'worked', 'base', 'missed', 'negotiations',
|
|
'waiting_payment', 'partnership', 'paid', 'closed',
|
|
'test_drive', 'hot', 'replacement', 'final_missed',
|
|
];
|
|
foreach ($expected as $slug) {
|
|
expect($slugs)->toContain($slug);
|
|
}
|
|
});
|
|
|
|
test('GET /api/lead-statuses возвращает поля slug, name_ru, color_hex, sort_order, is_system', function () {
|
|
$r = $this->getJson('/api/lead-statuses');
|
|
|
|
$first = $r->json('lead_statuses.0');
|
|
expect($first)->toHaveKeys(['slug', 'name_ru', 'is_system', 'sort_order', 'color_hex']);
|
|
expect($first['slug'])->toBeString();
|
|
expect($first['name_ru'])->toBeString();
|
|
expect($first['is_system'])->toBeBool();
|
|
});
|
|
|
|
test('GET /api/lead-statuses сортирует по sort_order', function () {
|
|
$r = $this->getJson('/api/lead-statuses');
|
|
|
|
$sortOrders = collect($r->json('lead_statuses'))->pluck('sort_order')->all();
|
|
$sorted = $sortOrders;
|
|
sort($sorted);
|
|
expect($sortOrders)->toBe($sorted);
|
|
});
|
|
|
|
test('GET /api/lead-statuses включает кастомный slug, добавленный после seed', function () {
|
|
DB::table('lead_statuses')->insert([
|
|
'slug' => 'custom_test_'.bin2hex(random_bytes(3)),
|
|
'name_ru' => 'Кастомный тест',
|
|
'is_system' => false,
|
|
'sort_order' => 999,
|
|
'color_hex' => '#ABCDEF',
|
|
]);
|
|
|
|
$r = $this->getJson('/api/lead-statuses');
|
|
|
|
$slugs = collect($r->json('lead_statuses'))->pluck('slug')->all();
|
|
$custom = collect($slugs)->first(fn ($s) => str_starts_with($s, 'custom_test_'));
|
|
expect($custom)->not->toBeNull();
|
|
});
|