CluPilotCloud/tests/Feature/Admin/MailPacePageTest.php

161 lines
6.4 KiB
PHP

<?php
use App\Livewire\Admin\MailPace;
use App\Mail\InvoiceMail;
use App\Mail\ResetPasswordMail;
use App\Services\Mail\MailLane;
use App\Support\Settings;
use Illuminate\Support\Facades\Lang;
use Livewire\Livewire;
/**
* Die Sicht auf die drei Spuren, und der Notschalter davor.
*
* `mail.manage` ist dieselbe Fähigkeit wie auf admin/mail (App\Livewire\
* Admin\Mail) — dort liegen die anderen Maileinstellungen, und wer die lesen
* und ändern darf, darf auch sehen, was in den Spuren wartet, und die Drossel
* abstellen.
*/
it('zeigt jede Spur mit ihrem Takt und dem, was wartet', function () {
Livewire::actingAs(operator('Owner'), 'operator')
->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('sagt unter jeder Spur, was in ihr faehrt, statt ihren Warteschlangennamen zu wiederholen', function () {
// Vorher stand dort „Ruhig / mail-ruhig" — dieselbe Auskunft zweimal, die
// zweite in Kleinschrift. Der Warteschlangenname gehoert in die
// --queue-Liste des Arbeiters, nicht auf die Seite, auf der jemand
// entscheidet, was wie eilig ist.
$html = Livewire::actingAs(operator('Owner'), 'operator')->test(MailPace::class)->html();
foreach ([MailLane::DIRECT, MailLane::URGENT, MailLane::CALM] as $spur) {
expect(Lang::has('mail_pace.lane_hint.'.$spur))->toBeTrue()
->and($html)->toContain(e(__('mail_pace.lane_hint.'.$spur)));
}
// Der rohe Name steht nur noch dort, wo er etwas bewirkt: im Wert der
// Auswahlfelder der Zuordnung, nicht als sichtbarer Text.
expect($html)->not->toContain('>'.MailLane::CALM.'<');
});