- 83 Komponenten: Livewire\Volt\Component → Livewire\Component
- 73 Routen (admin, auth, customer): Volt::route() → Route::livewire()
- 88 Testdateien: Volt::test/actingAs → Livewire::test/actingAs
- VoltServiceProvider gelöscht; composer remove livewire/volt
- config/livewire.php auf v4-Schlüssel (component_layout, component_placeholder,
component_locations, make_command: SFC ohne ⚡). Der alte Schlüssel layout war
wirkungslos; alle gerouteten Komponenten setzen ihr Layout selbst.
- CLAUDE.md, AGENTS.md, boost.json, .cursorrules, Skill volt-development
- Roadmap: erledigt; Larastan erfasst SFCs weiterhin nicht (Blade-Dateien)
Suite 2.325 grün, einer übersprungen; Larastan und Pint ohne Meldung;
route:cache und view:cache laufen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
118 lines
4.3 KiB
PHP
118 lines
4.3 KiB
PHP
<?php
|
||
|
||
use App\Models\Company;
|
||
use App\Models\Contact;
|
||
use App\Models\User;
|
||
use App\Rules\NoPromotionalText;
|
||
use Illuminate\Support\Facades\Validator;
|
||
use Livewire\Livewire;
|
||
use Tests\TestCase;
|
||
|
||
/**
|
||
* Öffentliche Kurzfelder des Newsrooms (Firmenname, Adresse, Pressekontakt)
|
||
* sind keine Werbefläche — deterministische Regel, ohne KI (17.09.2026).
|
||
*/
|
||
function promotionalReason(string $value): ?string
|
||
{
|
||
$validator = Validator::make(['field' => $value], ['field' => ['nullable', 'string', app(NoPromotionalText::class)]]);
|
||
|
||
return $validator->fails() ? $validator->errors()->first('field') : null;
|
||
}
|
||
|
||
beforeEach(function (): void {
|
||
config()->set('blacklist.words', ['spam-keyword', 'casino royale']);
|
||
config()->set('scoring.classification.provider', 'deterministic');
|
||
});
|
||
|
||
test('ordinary company names, addresses and roles pass', function (string $value) {
|
||
expect(promotionalReason($value))->toBeNull();
|
||
})->with([
|
||
'Muster GmbH & Co. KG',
|
||
'meinshop.de GmbH',
|
||
'Hörwelt Basel e.V.',
|
||
'Musterstraße 12, 12345 Musterstadt',
|
||
'Leiterin Unternehmenskommunikation',
|
||
'Pressesprecher (Region Süd) – erreichbar Mo–Fr!',
|
||
'SAP SE',
|
||
'',
|
||
]);
|
||
|
||
test('links, addresses, noise and blacklist hits are rejected with a specific reason', function (string $value, string $expected) {
|
||
expect(promotionalReason($value))->toContain($expected);
|
||
})->with([
|
||
['Casino Bonus https://spam.example/bonus', 'Links'],
|
||
['Gewinne jetzt www.spam.example', 'Links'],
|
||
['Angebote auf spam.example/deal', 'Links'],
|
||
['Bestellen unter kontakt@spam.example', 'E-Mail-Adressen'],
|
||
['JETZT KAUFEN!!!', 'Sonderzeichen'],
|
||
['Gratis 🎰🎰🎰 Bonus', 'Sonderzeichen'],
|
||
['Ein spam-keyword Anbieter', 'unzulässigen Begriff'],
|
||
['Willkommen im Casino Royale', 'unzulässigen Begriff'],
|
||
]);
|
||
|
||
function newsroomEditor(TestCase $test): Company
|
||
{
|
||
$customer = User::factory()->create(['is_active' => true]);
|
||
$company = Company::factory()->businessportal24()->create(['name' => 'Muster GmbH', 'slug' => 'muster-gmbh', 'boilerplate' => null, 'address' => null]);
|
||
$customer->companies()->attach($company->id, ['role' => 'responsible']);
|
||
$test->actingAs($customer);
|
||
|
||
return $company;
|
||
}
|
||
|
||
test('a company name or address with a link is not saved', function () {
|
||
/** @var TestCase $this */
|
||
$company = newsroomEditor($this);
|
||
|
||
Livewire::test('customer.press-kits.show', ['id' => $company->id])
|
||
->call('startEditCompany')
|
||
->set('companyName', 'Muster GmbH – https://spam.example')
|
||
->set('companyAddress', "Musterstraße 1\nwww.spam.example")
|
||
->call('saveCompany')
|
||
->assertHasErrors(['companyName', 'companyAddress']);
|
||
|
||
expect($company->fresh()->name)->toBe('Muster GmbH')
|
||
->and($company->fresh()->address)->toBeNull();
|
||
});
|
||
|
||
test('an address that hits the red level of the release check is not saved', function () {
|
||
/** @var TestCase $this */
|
||
$company = newsroomEditor($this);
|
||
|
||
Livewire::test('customer.press-kits.show', ['id' => $company->id])
|
||
->call('startEditCompany')
|
||
->set('companyAddress', 'Musterstraße 1, spam-keyword Musterstadt')
|
||
->call('saveCompany')
|
||
->assertHasErrors(['companyAddress']);
|
||
|
||
expect($company->fresh()->address)->toBeNull();
|
||
});
|
||
|
||
test('a press contact with a link in the role is not saved', function () {
|
||
/** @var TestCase $this */
|
||
$company = newsroomEditor($this);
|
||
|
||
Livewire::test('customer.press-kits.show', ['id' => $company->id])
|
||
->call('startCreateContact')
|
||
->set('contactLastName', 'Muster')
|
||
->set('contactResponsibility', 'Pressesprecher – Angebote unter https://spam.example')
|
||
->set('contactEmail', 'presse@muster.example')
|
||
->call('saveContact')
|
||
->assertHasErrors(['contactResponsibility']);
|
||
|
||
expect(Contact::query()->where('company_id', $company->id)->count())->toBe(0);
|
||
});
|
||
|
||
test('creating a company with a promotional name is refused', function () {
|
||
/** @var TestCase $this */
|
||
$customer = User::factory()->create(['is_active' => true]);
|
||
$this->actingAs($customer);
|
||
|
||
Livewire::test('customer.press-kits.create')
|
||
->set('name', 'Casino Royale Bonus')
|
||
->set('portal', 'businessportal24')
|
||
->call('save')
|
||
->assertHasErrors(['name']);
|
||
|
||
expect(Company::query()->where('name', 'Casino Royale Bonus')->exists())->toBeFalse();
|
||
});
|