presseportale/tests/Feature/Admin/EndBoostTest.php
Kevin Adametz fce7baea2b admin: Boost vorzeitig beenden, Berechtigungsliste audit:admins
Admin ▸ Pressemitteilung zeigt laufende Boosts; „Boost beenden“ verlangt
einen Grund und billing:manage, beendet laufende und angeschlossene
Zeiträume, verwirft die Seiten-Caches und protokolliert „Boost beendet“.
Credits werden nicht zurückgebucht.

audit:admins listet alle Konten mit Rechten über den Kundenbereich hinaus
(Super-Admin, Rollen außer customer/api-only, direkte Permissions), auch
gesperrte und gelöschte, als Markdown mit 2FA, Passkeys, Tokens und letztem
Sitzungswiderruf. E-Mail standardmäßig nur mit Domain (Nachweis BN-02).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 10:16:21 +00:00

91 lines
3.3 KiB
PHP

<?php
use App\Enums\ActivityType;
use App\Enums\PressReleaseClassification;
use App\Models\ActivityEvent;
use App\Models\Boost;
use App\Models\PressRelease;
use App\Models\User;
use Database\Seeders\RolesAndPermissionsSeeder;
use Livewire\Livewire;
use Tests\TestCase;
/**
* Gebuchte Platzierung vorzeitig beenden (Rechtspaket 10/2026, U10): der
* Admin beendet laufende und angeschlossene Boosts mit Pflichtgrund; die
* Buchung bleibt als Nachweis stehen, der Vorgang landet im Verlauf.
*/
beforeEach(function (): void {
/** @var TestCase $this */
$this->seed(RolesAndPermissionsSeeder::class);
$this->pressRelease = PressRelease::factory()->published()->create([
'classification' => PressReleaseClassification::Green->value,
]);
});
test('an admin ends running and queued boosts with a reason', function () {
/** @var TestCase $this */
$admin = User::factory()->create();
$admin->assignRole('admin');
$running = Boost::factory()->for($this->pressRelease)->create();
$queued = Boost::factory()->for($this->pressRelease)->create([
'starts_at' => now()->addDays(7),
'ends_at' => now()->addDays(14),
]);
$expired = Boost::factory()->for($this->pressRelease)->expired()->create();
$expiredEnd = $expired->ends_at;
$this->actingAs($admin);
Livewire::test('admin.press-releases.show', ['id' => $this->pressRelease->id])
->assertSee('Boost beenden')
->set('boostEndReason', 'Test-Boost für die Screenshots beendet')
->call('endBoost')
->assertHasNoErrors();
expect($this->pressRelease->boosts()->active()->exists())->toBeFalse()
->and($running->fresh()->ends_at->lessThanOrEqualTo(now()))->toBeTrue()
->and($queued->fresh()->starts_at->lessThanOrEqualTo($queued->fresh()->ends_at))->toBeTrue()
->and($expired->fresh()->ends_at->equalTo($expiredEnd))->toBeTrue()
->and(Boost::query()->count())->toBe(3);
$event = ActivityEvent::query()->where('type', ActivityType::BoostEnded->value)->sole();
expect($event->description)->toContain('Test-Boost für die Screenshots beendet')
->and($event->meta['boost_ids'])->toEqualCanonicalizing([$running->id, $queued->id]);
});
test('ending a boost requires a reason', function () {
/** @var TestCase $this */
$admin = User::factory()->create();
$admin->assignRole('admin');
Boost::factory()->for($this->pressRelease)->create();
$this->actingAs($admin);
Livewire::test('admin.press-releases.show', ['id' => $this->pressRelease->id])
->set('boostEndReason', '')
->call('endBoost')
->assertHasErrors(['boostEndReason']);
expect($this->pressRelease->boosts()->active()->exists())->toBeTrue();
});
test('an editor sees the boost but cannot end it', function () {
/** @var TestCase $this */
$editor = User::factory()->create();
$editor->assignRole('editor');
Boost::factory()->for($this->pressRelease)->create();
$this->actingAs($editor);
Livewire::test('admin.press-releases.show', ['id' => $this->pressRelease->id])
->assertSee('Gebuchte Platzierung')
->assertDontSee('Boost beenden')
->set('boostEndReason', 'Versuch ohne Abrechnungsrecht')
->call('endBoost')
->assertForbidden();
expect($this->pressRelease->boosts()->active()->exists())->toBeTrue();
});