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('a cross-portal company blocks its slug on every portal and needs it free everywhere', function () { /** @var TestCase $this */ // Seit der Zusammenführung (Roadmap 1a.3) gibt es Firmen mit `both`; die // öffentliche Auflösung fragt `portal IN (eigenes, both)`. Ein neuer // PE-Slug darf deshalb nicht mit einer both-Firma zusammenfallen — sonst // fände die Newsroom-URL zwei Firmen. Company::factory()->create(['portal' => Portal::Both->value, 'slug' => 'acme-gmbh']); Company::factory()->create(['portal' => Portal::Presseecho->value, 'slug' => 'beta-gmbh']); expect((new Company)->generateUniqueSlug('Acme GmbH', ['portal' => Portal::Presseecho->value]))->toBe('acme-gmbh-2') ->and((new Company)->generateUniqueSlug('Acme GmbH', ['portal' => Portal::Businessportal24->value]))->toBe('acme-gmbh-2') ->and((new Company)->generateUniqueSlug('Beta GmbH', ['portal' => Portal::Both->value]))->toBe('beta-gmbh-2') ->and((new Company)->generateUniqueSlug('Beta GmbH', ['portal' => Portal::Businessportal24->value]))->toBe('beta-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'); });