2590c01477
Восьми файлам рекламной папки поставлен откат после теста. Проверено остатком в базе снаружи: папка оставляла 116 записей арендаторов, теперь 44. Папка целиком зелёная - 351 из 351. Полный прогон после уборки: 4111 тестов, 4107 зелёных, 4 пропущено, ноль падений - значит на эту грязь никто не опирался. Побочно прогон стал БЫСТРЕЕ: 12,9 минуты против 16,5. Один файл намеренно оставлен как был, причина записана прямо в нём: CampaignBannerEndpointsTest нарочно ловит отказ базы, а Postgres после отказа внутри транзакции глушит все следующие команды. С откатом файл падает - чинить надо сам тест, а не обёртку. Датчик пришлось расшифровывать, и это стоит помнить. Числа сперва выходили с минусами: файл, который базы не касается вовсе, «уносил» девять записей. Прямым замером выяснилось, что КАЖДЫЙ прогон начинается с пересборки базы - было 6 записей, стало 0 после теста про расписание. Значит разница «до/после» при переборе файлов = оставил этот минус оставил предыдущий. Расшифровал цепочкой, сумма сошлась со 116 ровно - на этом расшифровка и проверяется. Поимённый расклад по файлам перенесён в промт. Грабля на будущее, тоже в промте: uses() обязан стоять НИЖЕ подключений классов. Подключение действует с места объявления и ниже, поэтому вызов выше падает «класс не найден» - и падает сразу вся папка. Полное имя с ведущей чертой не спасает: pint САМ превращает его в подключение внизу и ломает работавший файл. Остаток долга измерен и НЕ закрыт: ~20 файлов оставляют по одной-две записи, среди них миграционные, которым откат может быть противопоказан по сути. По всей папке Feature без отката 96 файлов из 580 - корень общий, в app/tests/Pest.php строка RefreshDatabase закомментирована. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
110 lines
3.8 KiB
PHP
110 lines
3.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Models\AdCampaign;
|
|
use App\Models\AdCampaignAd;
|
|
use App\Models\Tenant;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
// Откат после теста. Без него записи файла остаются в базе и роняют ЧУЖИЕ тесты:
|
|
// 01.08.2026 девятнадцать чужих проводок уронили денежную проверку приёмника МТС.
|
|
uses(DatabaseTransactions::class);
|
|
|
|
/**
|
|
* T15 — удаление черновика кампании: DELETE /api/advertising/campaigns/{id}.
|
|
*
|
|
* Мирроим auth/tenant setup из AdvertisingCampaignEndpointTest.php — без RefreshDatabase,
|
|
* каждый тест создаёт свой Tenant::factory()->create().
|
|
*/
|
|
beforeEach(function () {
|
|
$this->tenant = Tenant::factory()->create();
|
|
$this->user = User::factory()->create(['tenant_id' => $this->tenant->id]);
|
|
$this->actingAs($this->user);
|
|
});
|
|
|
|
it('deletes a draft campaign of own tenant', function () {
|
|
$campaign = AdCampaign::create([
|
|
'tenant_id' => $this->tenant->id,
|
|
'name' => 'Черновик на удаление',
|
|
'audience_days' => 10,
|
|
'weekly_budget_rub' => '1000.00',
|
|
]);
|
|
|
|
$response = $this->deleteJson("/api/advertising/campaigns/{$campaign->id}");
|
|
|
|
$response->assertStatus(204);
|
|
$this->assertDatabaseMissing('ad_campaigns', ['id' => $campaign->id]);
|
|
});
|
|
|
|
it('refuses to delete a running campaign', function () {
|
|
$campaign = AdCampaign::create([
|
|
'tenant_id' => $this->tenant->id,
|
|
'name' => 'Запущенная кампания',
|
|
'status' => AdCampaign::STATUS_RUNNING,
|
|
'audience_days' => 10,
|
|
'weekly_budget_rub' => '1000.00',
|
|
]);
|
|
|
|
$response = $this->deleteJson("/api/advertising/campaigns/{$campaign->id}");
|
|
|
|
$response->assertStatus(409);
|
|
$this->assertDatabaseHas('ad_campaigns', ['id' => $campaign->id]);
|
|
});
|
|
|
|
it('returns 404 for another tenants campaign and does not delete it', function () {
|
|
$tenantB = Tenant::factory()->create();
|
|
$campaignB = AdCampaign::create([
|
|
'tenant_id' => $tenantB->id,
|
|
'name' => 'Чужой черновик',
|
|
'audience_days' => 10,
|
|
'weekly_budget_rub' => '1000.00',
|
|
]);
|
|
|
|
$response = $this->deleteJson("/api/advertising/campaigns/{$campaignB->id}");
|
|
|
|
$response->assertStatus(404);
|
|
$this->assertDatabaseHas('ad_campaigns', ['id' => $campaignB->id]);
|
|
});
|
|
|
|
it('returns 404 for a non-existent campaign', function () {
|
|
$response = $this->deleteJson('/api/advertising/campaigns/999999999');
|
|
|
|
$response->assertStatus(404);
|
|
});
|
|
|
|
it('cascades delete to related ads and phones', function () {
|
|
$campaign = AdCampaign::create([
|
|
'tenant_id' => $this->tenant->id,
|
|
'name' => 'Черновик с детьми',
|
|
'audience_days' => 10,
|
|
'weekly_budget_rub' => '1000.00',
|
|
]);
|
|
|
|
$ad = AdCampaignAd::create([
|
|
'tenant_id' => $this->tenant->id,
|
|
'campaign_id' => $campaign->id,
|
|
'title' => 'Заголовок',
|
|
'text' => 'Текст объявления',
|
|
'href' => 'https://liderra.ru',
|
|
'moderation_status' => 'draft',
|
|
]);
|
|
|
|
DB::table('ad_campaign_phones')->insert([
|
|
'tenant_id' => $campaign->tenant_id,
|
|
'campaign_id' => $campaign->id,
|
|
'phone' => '79000000001',
|
|
'expires_at' => null,
|
|
'created_at' => now(),
|
|
'updated_at' => now(),
|
|
]);
|
|
|
|
$response = $this->deleteJson("/api/advertising/campaigns/{$campaign->id}");
|
|
|
|
$response->assertStatus(204);
|
|
$this->assertDatabaseMissing('ad_campaign_ads', ['id' => $ad->id]);
|
|
$this->assertDatabaseMissing('ad_campaign_phones', ['campaign_id' => $campaign->id]);
|
|
});
|