CluPilotCloud/tests/Feature/Cancellation/CancelAsksAboutExportTest.php

129 lines
5.2 KiB
PHP

<?php // tests/Feature/Cancellation/CancelAsksAboutExportTest.php
use App\Livewire\ConfirmCancelPackage;
use App\Models\Customer;
use App\Models\Instance;
use App\Models\Order;
use App\Models\User;
use Livewire\Livewire;
/**
* Abweichung vom Zettel: keine der drei Prüfungen unten setzt im Original
* `reason`. Im Bestand verlangt ConfirmCancelPackage::cancelPackage() aber
* schon länger einen gültigen Grund (Subscription::CANCEL_REASONS) und
* bricht sonst VOR jeder Schreibaktion mit einem eigenen Fehler ab — das war
* so, bevor diese Aufgabe begann, und diese Aufgabe ändert daran nichts. Ohne
* `->set('reason', ...)` würde jede der drei Prüfungen an dieser
* vorgelagerten Stelle scheitern, nicht an der Exportfrage, die hier geprüft
* werden soll. Alle drei setzen deshalb zusätzlich einen gültigen Grund.
*/
/**
* Ein aktives Paket, dessen Besitzer den Kündigungsdialog erreichen kann —
* nach dem Muster von settingsSetup() (tests/Feature/SettingsTest.php) und
* cancellablePackage() (tests/Feature/Billing/PackageCancellationTest.php):
* Nutzer, Kunde, Bestellung, aktive Instanz. Bewusst OHNE eigenen
* Subscription-Datensatz: ConfirmCancelPackage::contractFor() findet dann
* keinen Vertrag, und stopBilling(null) gibt ungefragt true zurück (derselbe
* Weg wie bei einem geschenkten Paket) — Stripe bleibt außen vor, weil es in
* dieser Aufgabe ausschließlich um die Exportfrage geht.
*
* @return array{0: User, 1: Instance}
*/
function kuendbareInstanz(): array
{
$user = User::factory()->create(['email' => 'kuendigt@example.test', 'email_verified_at' => now()]);
$customer = Customer::factory()->create([
'email' => 'kuendigt@example.test',
'user_id' => $user->id,
'status' => 'active',
]);
$order = Order::factory()->create(['customer_id' => $customer->id, 'plan' => 'team']);
$instance = Instance::factory()->create([
'customer_id' => $customer->id,
'order_id' => $order->id,
'plan' => 'team',
'status' => 'active',
'subdomain' => 'kuendigt',
]);
return [$user, $instance->refresh()];
}
it('schreibt die Antwort des Kunden an die Instanz', function () {
[$user, $instance] = kuendbareInstanz();
Livewire::actingAs($user)->test(ConfirmCancelPackage::class)
->set('confirmName', $instance->subdomain)
->set('reason', 'no_longer_needed')
->set('exportWish', true)
->call('cancelPackage')
->assertHasNoErrors();
expect($instance->fresh()->export_wish)->toBeTrue();
});
it('nimmt auch ein Nein als Antwort — und nicht als fehlende Antwort', function () {
// Das ist die Zusicherung, um die es geht: wer bewusst nein sagt, soll
// nicht wie jemand behandelt werden, den niemand gefragt hat. Nur das
// erspart ihm die Erinnerungen und uns die Arbeit.
[$user, $instance] = kuendbareInstanz();
Livewire::actingAs($user)->test(ConfirmCancelPackage::class)
->set('confirmName', $instance->subdomain)
->set('reason', 'no_longer_needed')
->set('exportWish', false)
->call('cancelPackage')
->assertHasNoErrors();
expect($instance->fresh()->export_wish)->toBeFalse()
->and($instance->fresh()->export_wish)->not->toBeNull();
});
it('verspricht im Kündigungsdialog keinen Export, den es noch nicht gibt', function (string $sprache, array $verboten) {
// Die Fix-Welle hat drei von vier Stellen zurückgenommen; diese vierte ist
// die wirksamste, weil sie im Moment der Entscheidung steht. Der Kunde las
// hier einen Liefergegenstand („einen Link zum Herunterladen"), klickte
// einmal auf Ja — und die Vertragsseite sagte ihm danach nur noch, sein
// Wunsch sei vermerkt. Geprüft in beiden Sprachen und am gerenderten
// Dialog, nicht an der Sprachdatei: der Widerspruch entstand dadurch, dass
// ein Satz irgendwo stehen blieb, und genau das fällt nur auf, wenn die
// Prüfung dorthin schaut, wo der Kunde liest.
app()->setLocale($sprache);
[$user] = kuendbareInstanz();
$dialog = Livewire::actingAs($user)->test(ConfirmCancelPackage::class);
foreach ($verboten as $versprechen) {
$dialog->assertDontSee($versprechen);
}
// Und der Satz, der stattdessen dort steht, muss auch wirklich ankommen —
// sonst wäre die Prüfung oben schon dadurch grün, dass der Dialog gar
// nichts über den Export sagt.
$dialog->assertSee(__('settings.cancel_export_hint'))
->assertSee(__('settings.cancel_point_export'));
})->with([
['de', ['Link zum Herunterladen', 'erhalten Sie auf Wunsch einen vollständigen Datenexport']],
['en', ['download link', 'you receive a full data export']],
]);
it('kündigt nicht ohne eine Antwort auf die Frage', function () {
// Eine Frage, die man überspringen kann, ist keine Frage — und die
// Kündigung ist der einzige Moment, in dem der Kunde ohnehin über seine
// Daten nachdenkt.
[$user, $instance] = kuendbareInstanz();
Livewire::actingAs($user)->test(ConfirmCancelPackage::class)
->set('confirmName', $instance->subdomain)
->set('reason', 'no_longer_needed')
->call('cancelPackage')
->assertHasErrors('exportWish');
expect($instance->fresh()->status)->toBe('active');
});