Files
portal/app/tests/Feature/Admin/AdminAdCampaignCreativeTest.php
T
Дмитрий 3917fb1344 feat(реклама показы): админ-экран ввода номера креатива Яндекса оператором
Задача 8e. SaaS-оператор видит кампании в статусе queued по всем тенантам и
вписывает номер оформленного в конструкторе Яндекса адаптивного креатива
yandex_creative_id, после чего кампанию можно запускать. Два эндпоинта
AdminAdvertisingController campaignsAwaiting и setCampaignCreative под
saas-admin+admin-db, карточка в AdminAdvertisingView, api-функции и типы.

🔴 Запись строго через сырой DB::table update только колонки yandex_creative_id
Eloquent-билдер добавил бы updated_at, а колоночный GRANT у crm_admin_user
разрешает писать лишь эту колонку тесты идут под суперюзером и это не ловят.
RLS не трогаем ad_campaigns уже покрыт srv_bypass и грантами.

Бэкенд AdminAd 19/19, реклама-модуль 195/195, фронт админки 11/11.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-27 09:55:41 +03:00

119 lines
4.6 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
use App\Models\AdCampaign;
use App\Models\Tenant;
use Illuminate\Foundation\Testing\DatabaseTransactions;
uses(DatabaseTransactions::class);
/**
* 8e: SaaS-admin вписывает номер оформленного в Яндекс.Директе адаптивного креатива
* кампаниям в статусе queued, после чего кампанию можно запускать (CampaignLauncher).
*/
test('GET /api/admin/advertising/campaigns возвращает только queued-кампании', function () {
$tenant = Tenant::factory()->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);
});