test(MailPace::class) ->assertSee(MailLane::DIRECT) ->assertSee(MailLane::URGENT) ->assertSee(MailLane::CALM); }); it('laesst den Betreiber eine Mail verschieben', function () { Livewire::actingAs(operator('Owner'), 'operator') ->test(MailPace::class) ->call('move', InvoiceMail::class, MailLane::URGENT); expect(MailLane::for(InvoiceMail::class))->toBe(MailLane::URGENT); }); it('verschiebt eine gesperrte Mail nicht, auch nicht ueber die Komponente', function () { Livewire::actingAs(operator('Owner'), 'operator') ->test(MailPace::class) ->call('move', ResetPasswordMail::class, MailLane::CALM); expect(MailLane::for(ResetPasswordMail::class))->toBe(MailLane::DIRECT); }); it('zeigt eine gesperrte Klasse als gesperrt statt mit einem Auswahlfeld', function () { // Das Schloss ist nur die Höflichkeit vor der serverseitigen Ablehnung im // Test darüber — aber eine Auswahl, die eine gesperrte Klasse anbietet, // wäre die Einladung zu einem Klick, der ohnehin nichts bewirkt. $html = Livewire::actingAs(operator('Owner'), 'operator') ->test(MailPace::class) ->assertSee(__('mail_pace.class.ResetPasswordMail')) ->html(); expect($html)->not->toContain("move('".ResetPasswordMail::class."'"); }); it('schaltet die Drossel ab und wieder an', function () { $component = Livewire::actingAs(operator('Owner'), 'operator') ->test(MailPace::class) ->call('togglePace'); expect(Settings::bool('mail.pace.enabled', true))->toBeFalse(); $component->call('togglePace'); expect(Settings::bool('mail.pace.enabled', true))->toBeTrue(); }); /** * Die zweite Hälfte der Untergrenze aus MailPaceServiceProvider:: * mindestensEins() — die dortige liest nur ab, was hier gar nicht erst * gespeichert werden darf. Ohne diese Prüfung käme eine eingetippte 0 durch * bis zur Einstellung und würde erst beim nächsten Auftrag an der Lesestelle * abgefangen, nachdem der Betreiber schon „gespeichert" gesehen hat. */ it('verweigert ein Kontingent von null oder weniger', function () { Livewire::actingAs(operator('Owner'), 'operator') ->test(MailPace::class) ->set('urgentCount', 0) ->call('savePace') ->assertHasErrors(['urgentCount' => 'min']); expect(Settings::get('mail.pace.urgent.count'))->toBeNull(); }); it('verweigert ein Fenster von null Minuten', function () { Livewire::actingAs(operator('Owner'), 'operator') ->test(MailPace::class) ->set('calmMinutes', 0) ->call('savePace') ->assertHasErrors(['calmMinutes' => 'min']); expect(Settings::get('mail.pace.calm.minutes'))->toBeNull(); }); it('speichert einen gueltigen Takt fuer beide gedrosselten Spuren', function () { Livewire::actingAs(operator('Owner'), 'operator') ->test(MailPace::class) ->set('urgentCount', 12) ->set('urgentMinutes', 3) ->set('calmCount', 7) ->set('calmMinutes', 9) ->call('savePace') ->assertHasNoErrors(); expect(Settings::get('mail.pace.urgent.count'))->toBe(12) ->and(Settings::get('mail.pace.urgent.minutes'))->toBe(3) ->and(Settings::get('mail.pace.calm.count'))->toBe(7) ->and(Settings::get('mail.pace.calm.minutes'))->toBe(9); }); /** * ── Namen statt Klassennamen ────────────────────────────────────────────── * * Die Seite zeigte `class_basename()`: „DormantAccountWarningMail" stand * dort, wo der Betreiber „Konto ohne Paket wird gelöscht" sucht. Ein * Klassenname ist eine Auskunft über den Bauplan, keine über die Mail. */ it('nennt jede Mailklasse bei ihrem Namen, nicht bei ihrer Klasse', function () { $html = Livewire::actingAs(operator('Owner'), 'operator')->test(MailPace::class)->html(); foreach (array_keys(MailLane::all()) as $class) { $kurz = class_basename($class); expect(Lang::has('mail_pace.class.'.$kurz)) ->toBeTrue("Für {$kurz} fehlt ein Name in lang/de/mail_pace.php."); // Der Klassenname darf auch nicht mehr durchscheinen — er steht nur // noch im wire:key und im Wert des Auswahlfelds, beides mit vollem // Namensraum davor. expect($html)->not->toContain('>'.$kurz.'<'); } }); it('führt für jede Mailklasse denselben Namen in beiden Sprachen', function () { // Eine Sprache ohne den Eintrag zeigte still den Schlüssel selbst — // „mail_pace.class.InvoiceMail" mitten in einer Tabelle. $de = require lang_path('de/mail_pace.php'); $en = require lang_path('en/mail_pace.php'); foreach (array_keys(MailLane::all()) as $class) { expect($de['class'])->toHaveKey(class_basename($class)) ->and($en['class'])->toHaveKey(class_basename($class)); } }); it('stellt den technischen Spurnamen unter die Spur, nicht zwischen die Felder', function () { // Er bleibt sichtbar — der Arbeiter in docker-compose.yml hört genau // diese Zeichenkette ab —, aber als Unterzeile der Beschriftung. $html = Livewire::actingAs(operator('Owner'), 'operator')->test(MailPace::class)->html(); expect($html)->toContain(MailLane::CALM) ->and($html)->not->toContain('font-mono text-xs text-muted">'.MailLane::CALM); });