presseportale/tests/Feature/HasUniqueSlugTest.php
Kevin Adametz 6e84266f90 press-releases: Publish-Rechte, Quota-Races & Slug vereinheitlichen
- Publish/Reject/Archive und changeStatus erzwingen konsistent
  press-releases:publish; changeStatus schloss die Lücke, über die das
  Status-Modal die Prüfung umging (Fix#1/H2).
- publish()/changeStatusFromAdmin sperren PM- und User-Zeile
  transaktional; QuotaExceededException wird in Admin-Publish und im
  Auto-Publish-Job abgefangen (Warnung statt 500 / bleibt in Review, Fix#3/M2).
- Slug-Erzeugung nur noch über HasUniqueSlug (generateUniqueSlug +
  saveWithUniqueSlugRetry), redundanter Controller-Helper entfernt (M3).
- API-/Legacy-Text wird vor der Persistenz sanitisiert (M6);
  Scheduler/Legacy-Tracking ignorieren soft-gelöschte PMs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 13:47:51 +00:00

110 lines
3.4 KiB
PHP

<?php
use App\Enums\Portal;
use App\Models\Company;
use App\Models\PressRelease;
use Tests\TestCase;
test('press release slug is unique within portal and language scope', function () {
/** @var TestCase $this */
$base = (new PressRelease)->generateUniqueSlug('Test Mitteilung', [
'portal' => Portal::Presseecho->value,
'language' => 'de',
]);
expect($base)->toBe('test-mitteilung');
PressRelease::factory()->create([
'portal' => Portal::Presseecho->value,
'language' => 'de',
'slug' => 'test-mitteilung',
]);
$next = (new PressRelease)->generateUniqueSlug('Test Mitteilung', [
'portal' => Portal::Presseecho->value,
'language' => 'de',
]);
expect($next)->toBe('test-mitteilung-2');
// Same slug allowed in another portal
$foreign = (new PressRelease)->generateUniqueSlug('Test Mitteilung', [
'portal' => Portal::Businessportal24->value,
'language' => 'de',
]);
expect($foreign)->toBe('test-mitteilung');
// Same slug allowed in another language
$en = (new PressRelease)->generateUniqueSlug('Test Mitteilung', [
'portal' => Portal::Presseecho->value,
'language' => 'en',
]);
expect($en)->toBe('test-mitteilung');
});
test('press release editing keeps own slug stable', function () {
/** @var TestCase $this */
$pr = PressRelease::factory()->create([
'portal' => Portal::Presseecho->value,
'language' => 'de',
'slug' => 'meine-mitteilung',
]);
$regenerated = $pr->generateUniqueSlug('Meine Mitteilung', [
'portal' => Portal::Presseecho->value,
'language' => 'de',
]);
expect($regenerated)->toBe('meine-mitteilung');
});
test('a stale slug candidate is regenerated after a unique constraint collision', function () {
/** @var TestCase $this */
PressRelease::factory()->create([
'portal' => Portal::Presseecho->value,
'language' => 'de',
'slug' => 'gleichzeitig',
]);
$pressRelease = PressRelease::factory()->make([
'portal' => Portal::Presseecho->value,
'language' => 'de',
'title' => 'Gleichzeitig',
'slug' => 'gleichzeitig',
]);
$pressRelease->saveWithUniqueSlugRetry('Gleichzeitig', [
'portal' => Portal::Presseecho->value,
'language' => 'de',
]);
expect($pressRelease->exists)->toBeTrue()
->and($pressRelease->slug)->toBe('gleichzeitig-2');
});
test('company slug is unique within portal scope', function () {
/** @var TestCase $this */
Company::factory()->create([
'portal' => Portal::Presseecho->value,
'slug' => 'acme-gmbh',
]);
$slug = (new Company)->generateUniqueSlug('Acme GmbH', ['portal' => Portal::Presseecho->value]);
expect($slug)->toBe('acme-gmbh-2');
$other = (new Company)->generateUniqueSlug('Acme GmbH', ['portal' => Portal::Businessportal24->value]);
expect($other)->toBe('acme-gmbh');
});
test('blank source falls back to model defined fallback', function () {
/** @var TestCase $this */
$prSlug = (new PressRelease)->generateUniqueSlug('---', [
'portal' => Portal::Presseecho->value,
'language' => 'de',
]);
expect($prSlug)->toBe('pressemitteilung');
$coSlug = (new Company)->generateUniqueSlug('!!!', ['portal' => Portal::Presseecho->value]);
expect($coSlug)->toBe('company');
});