seed(RolesAndPermissionsSeeder::class); }); function correctionPanelOwner(): User { $owner = User::factory()->create(['is_active' => true]); $owner->assignRole('customer'); return $owner; } test('an owner can apply a minor correction from the panel and it goes live instantly', function () { /** @var TestCase $this */ Queue::fake(); Mail::fake(); $owner = correctionPanelOwner(); $this->actingAs($owner); $pressRelease = PressRelease::factory()->published()->create([ 'user_id' => $owner->id, 'title' => 'Betrieb genomen', ]); Livewire::test('customer.press-releases.show', ['id' => $pressRelease->id]) ->call('startCorrection') ->set('correctionValues.title', 'Betrieb genommen') ->call('previewCorrection') ->assertHasNoErrors() ->call('applyCorrection') ->assertHasNoErrors(); $pressRelease->refresh(); expect($pressRelease->title)->toBe('Betrieb genommen') ->and($pressRelease->isSyncLocked())->toBeTrue() ->and(LegalRequest::query()->where('type', LegalRequestType::Correction->value)->count())->toBe(1); // Bestätigungsmail an den Auftraggeber (abbestellbar über die Präferenzen). Mail::assertQueued(PressReleaseChangeApplied::class, function (PressReleaseChangeApplied $mail) use ($owner) { return $mail->hasTo($owner->email) && ! $mail->isPaidChange; }); }); test('a major change passes the green precheck and unlocks the payment step', function () { /** @var TestCase $this */ config()->set('scoring.classification.provider', 'deterministic'); config()->set('blacklist.words', []); app()->forgetInstance(BlacklistService::class); $owner = correctionPanelOwner(); $this->actingAs($owner); $pressRelease = PressRelease::factory()->published()->create([ 'user_id' => $owner->id, 'title' => 'Solaranlage in Hamburg eroeffnet und in Betrieb', ]); Livewire::test('customer.press-releases.show', ['id' => $pressRelease->id]) ->call('startCorrection') ->set('correctionValues.title', 'Solaranlage in Muenchen eroeffnet und in Vollbetrieb') ->call('previewCorrection') ->assertHasNoErrors() ->call('openPaidChangeModal') ->assertHasNoErrors() ->call('runPaidChangePrecheck') ->assertHasNoErrors() ->assertSet('paidChangePrecheck.classification', 'green') ->assertSee('Prüfung bestanden'); $request = LegalRequest::query()->where('type', LegalRequestType::Change->value)->sole(); expect($request->status)->toBe(LegalRequestStatus::Open) ->and($request->payload['ki_check']['classification'])->toBe('green') ->and($request->payload['new_values']['title'])->toContain('Muenchen') ->and($request->executed_at)->toBeNull() ->and($pressRelease->fresh()->title)->toBe('Solaranlage in Hamburg eroeffnet und in Betrieb'); }); test('a red precheck rejects the change before payment and the process is one-time', function () { /** @var TestCase $this */ config()->set('scoring.classification.provider', 'deterministic'); config()->set('blacklist.words', ['skandalwort']); app()->forgetInstance(BlacklistService::class); $owner = correctionPanelOwner(); $this->actingAs($owner); $pressRelease = PressRelease::factory()->published()->create([ 'user_id' => $owner->id, 'title' => 'Solaranlage in Hamburg eroeffnet und in Betrieb', ]); Livewire::test('customer.press-releases.show', ['id' => $pressRelease->id]) ->call('startCorrection') ->set('correctionValues.title', 'Solaranlage in Hamburg eroeffnet mit Skandalwort dabei') ->call('previewCorrection') ->call('openPaidChangeModal') ->assertHasNoErrors() ->call('runPaidChangePrecheck') ->assertSet('paidChangePrecheck.classification', 'red') ->assertSee('Prüfung nicht bestanden'); $request = LegalRequest::query()->where('type', LegalRequestType::Change->value)->sole(); expect($request->status)->toBe(LegalRequestStatus::Rejected) ->and($request->payload['ki_check']['classification'])->toBe('red') ->and($pressRelease->fresh()->title)->toBe('Solaranlage in Hamburg eroeffnet und in Betrieb'); // Nur einmal möglich: nach der Ablehnung gibt es keinen zweiten Anlauf. Livewire::test('customer.press-releases.show', ['id' => $pressRelease->id]) ->call('startCorrection') ->set('correctionValues.title', 'Solaranlage in Muenchen eroeffnet und in Vollbetrieb') ->call('previewCorrection') ->call('openPaidChangeModal') ->assertHasErrors('correction'); expect(LegalRequest::query()->where('type', LegalRequestType::Change->value)->count())->toBe(1); }); test('a change above the paid distance limit cannot be booked at all', function () { /** @var TestCase $this */ $owner = correctionPanelOwner(); $this->actingAs($owner); $pressRelease = PressRelease::factory()->published()->create([ 'user_id' => $owner->id, 'title' => 'Kurzer Titel der Mitteilung', ]); Livewire::test('customer.press-releases.show', ['id' => $pressRelease->id]) ->call('startCorrection') ->set('correctionValues.title', 'Ein voellig anderer, deutlich laengerer und inhaltlich komplett neuer Titel') ->call('previewCorrection') ->assertSee('Zu umfangreich') ->call('openPaidChangeModal') ->assertHasErrors('correction'); expect(LegalRequest::query()->count())->toBe(0); }); test('a legacy plain-text release is prefilled as paragraphs and counts as unchanged', function () { /** @var TestCase $this */ $owner = correctionPanelOwner(); $this->actingAs($owner); $pressRelease = PressRelease::factory()->published()->create([ 'user_id' => $owner->id, 'text' => "Erster Absatz.\r\n\r\nZweiter Absatz mit Inhalt.", ]); $component = Livewire::test('customer.press-releases.show', ['id' => $pressRelease->id]) ->call('startCorrection'); expect($component->get('correctionValues')['text'])->toContain('

Erster Absatz.

'); // Unverändert abschicken: die Plaintext→HTML-Wandlung darf nicht als // inhaltliche Änderung zählen. $component->call('previewCorrection') ->assertHasErrors('correction'); expect($pressRelease->fresh()->text)->toContain("Erster Absatz.\r\n"); }); test('the panel names the weekly limit and the brake message states it too', function () { /** @var TestCase $this */ Queue::fake(); config()->set('legal.corrections_per_week', 1); $owner = correctionPanelOwner(); $this->actingAs($owner); $pressRelease = PressRelease::factory()->published()->create([ 'user_id' => $owner->id, 'title' => 'Titel B1', ]); $component = Livewire::test('customer.press-releases.show', ['id' => $pressRelease->id]) ->assertSee('höchstens eine kostenlose Korrektur pro Woche') ->call('startCorrection') ->set('correctionValues.title', 'Titel B2') ->call('previewCorrection') ->call('applyCorrection') ->assertHasNoErrors(); $component ->call('startCorrection') ->set('correctionValues.title', 'Titel B3') ->call('previewCorrection') ->call('applyCorrection') ->assertHasErrors('correction') ->assertSee('das Limit ist bereits erreicht'); expect($pressRelease->fresh()->title)->toBe('Titel B2'); }); test('apply without preview is refused', function () { /** @var TestCase $this */ $owner = correctionPanelOwner(); $this->actingAs($owner); $pressRelease = PressRelease::factory()->published()->create([ 'user_id' => $owner->id, 'title' => 'Original', ]); Livewire::test('customer.press-releases.show', ['id' => $pressRelease->id]) ->call('startCorrection') ->set('correctionValues.title', 'Origina') ->call('applyCorrection') ->assertHasErrors('correction'); expect($pressRelease->fresh()->title)->toBe('Original'); });