create(['organization_name' => 'Окна Москва']); $queued = AdCampaign::create([ 'tenant_id' => $tenant->id, 'name' => 'Кампания в очереди', 'status' => AdCampaign::STATUS_QUEUED, 'audience_days' => 10, 'budget_rub' => '500.00', 'landing_url' => 'https://example.ru/landing', 'estimated_impressions' => 12000, ]); AdCampaign::create([ 'tenant_id' => $tenant->id, 'name' => 'Черновик', 'status' => AdCampaign::STATUS_DRAFT, 'audience_days' => 10, 'budget_rub' => '500.00', ]); $r = $this->getJson('/api/admin/advertising/campaigns'); $r->assertStatus(200); $data = $r->json('data'); expect($data)->toHaveCount(1); expect($data[0]['id'])->toBe($queued->id); expect($data[0]['tenant_id'])->toBe($tenant->id); expect($data[0]['tenant_name'])->toBe('Окна Москва'); expect($data[0]['name'])->toBe('Кампания в очереди'); expect($data[0]['status'])->toBe(AdCampaign::STATUS_QUEUED); expect($data[0]['yandex_creative_id'])->toBeNull(); expect($data[0]['landing_url'])->toBe('https://example.ru/landing'); expect($data[0]['estimated_impressions'])->toBe(12000); }); test('GET /api/admin/advertising/campaigns сортирует по id desc', function () { $tenant = Tenant::factory()->create(); $first = AdCampaign::create([ 'tenant_id' => $tenant->id, 'name' => 'A', 'status' => AdCampaign::STATUS_QUEUED, 'audience_days' => 10, 'budget_rub' => '500.00', ]); $second = AdCampaign::create([ 'tenant_id' => $tenant->id, 'name' => 'B', 'status' => AdCampaign::STATUS_QUEUED, 'audience_days' => 10, 'budget_rub' => '500.00', ]); $r = $this->getJson('/api/admin/advertising/campaigns'); expect($r->json('data.0.id'))->toBe($second->id); expect($r->json('data.1.id'))->toBe($first->id); }); test('PATCH .../creative с валидным номером сохраняет yandex_creative_id', function () { $tenant = Tenant::factory()->create(); $campaign = AdCampaign::create([ 'tenant_id' => $tenant->id, 'name' => 'X', 'status' => AdCampaign::STATUS_QUEUED, 'audience_days' => 10, 'budget_rub' => '500.00', ]); $r = $this->patchJson("/api/admin/advertising/campaigns/{$campaign->id}/creative", [ 'yandex_creative_id' => 987654321, ]); $r->assertStatus(200); expect($r->json('id'))->toBe($campaign->id); expect($r->json('yandex_creative_id'))->toBe(987654321); expect(AdCampaign::find($campaign->id)->yandex_creative_id)->toBe(987654321); }); test('PATCH .../creative с невалидным номером (0/строка/пусто) → 422', function () { $tenant = Tenant::factory()->create(); $campaign = AdCampaign::create([ 'tenant_id' => $tenant->id, 'name' => 'X', 'status' => AdCampaign::STATUS_QUEUED, 'audience_days' => 10, 'budget_rub' => '500.00', ]); $this->patchJson("/api/admin/advertising/campaigns/{$campaign->id}/creative", ['yandex_creative_id' => 0]) ->assertStatus(422); $this->patchJson("/api/admin/advertising/campaigns/{$campaign->id}/creative", ['yandex_creative_id' => 'abc']) ->assertStatus(422); $this->patchJson("/api/admin/advertising/campaigns/{$campaign->id}/creative", []) ->assertStatus(422); }); test('PATCH .../creative на несуществующий id → 404', function () { $r = $this->patchJson('/api/admin/advertising/campaigns/999999999/creative', [ 'yandex_creative_id' => 123, ]); $r->assertStatus(404); expect($r->json('message'))->toBe('Кампания не найдена.'); }); test('GET /api/admin/advertising/campaigns — гейт: включён + нет REMOTE_USER → 403', function () { config(['admin.basic_auth_gate' => true]); config(['admin.basic_auth_allowlist' => ['admin']]); $this->getJson('/api/admin/advertising/campaigns')->assertStatus(403); });