105 lines
3.9 KiB
PHP
105 lines
3.9 KiB
PHP
<?php
|
|
|
|
use App\Livewire\PaymentMethod;
|
|
use App\Models\Customer;
|
|
use App\Models\User;
|
|
use App\Services\Stripe\FakeStripeClient;
|
|
use App\Services\Stripe\StripeClient;
|
|
use App\Support\StripePublishableKey;
|
|
use Livewire\Livewire;
|
|
|
|
/**
|
|
* Bis hierher konnte ein Kunde seine Karte NICHT tauschen — es gab im ganzen
|
|
* Portal keine Zahlungsmittel-Verwaltung. Eine abgelaufene Karte war damit
|
|
* eine Sackgasse: die Abbuchung scheitert, der Vertrag geht auf `past_due`,
|
|
* und der Kunde hat keine Stelle, an der er die Ursache beheben könnte.
|
|
*
|
|
* Deshalb ist das die ERSTE Lieferung und der Mahnlauf die zweite. Ein
|
|
* Mahnlauf über einem Portal ohne Kartenwechsel mahnt jemanden für etwas, das
|
|
* er nicht abstellen kann.
|
|
*/
|
|
function portalUserWithStripe(): User
|
|
{
|
|
$user = User::factory()->create(['email' => 'karte@portal.test', 'is_admin' => false]);
|
|
Customer::factory()->create(['email' => 'karte@portal.test', 'stripe_customer_id' => 'cus_42']);
|
|
|
|
return $user;
|
|
}
|
|
|
|
beforeEach(function () {
|
|
app()->instance(StripeClient::class, new FakeStripeClient);
|
|
StripePublishableKey::set('pk_test_sichtbar');
|
|
});
|
|
|
|
it('hands the browser a client secret and the publishable key', function () {
|
|
// Am übergebenen Wert geprüft, nicht am HTML: der Schlüssel steht in einem
|
|
// `@script`-Block, und den legt Livewire in die Effects-Nutzlast statt in
|
|
// das gerenderte Markup. Ein assertSee darauf prüfte die Testfassung von
|
|
// Livewire, nicht diese Komponente.
|
|
Livewire::actingAs(portalUserWithStripe())
|
|
->test(PaymentMethod::class)
|
|
->assertSet('clientSecret', 'seti_fake_secret_cus_42')
|
|
->assertViewHas('publishableKey', 'pk_test_sichtbar');
|
|
});
|
|
|
|
it('stores the confirmed payment method as the default', function () {
|
|
// Der Kern: eine Karte zu hinterlegen genügt nicht. Ohne diesen Schritt
|
|
// bucht Stripe weiter mit der kaputten ab, und der Kunde steht im nächsten
|
|
// Monat wieder in derselben Mahnung.
|
|
$fake = new FakeStripeClient;
|
|
app()->instance(StripeClient::class, $fake);
|
|
|
|
Livewire::actingAs(portalUserWithStripe())
|
|
->test(PaymentMethod::class)
|
|
->call('confirmed', 'pm_neu123')
|
|
->assertHasNoErrors();
|
|
|
|
expect($fake->defaultPaymentMethods['cus_42'])->toBe('pm_neu123');
|
|
});
|
|
|
|
it('shows which card is on file once one is', function () {
|
|
$fake = new FakeStripeClient;
|
|
$fake->defaultPaymentMethods['cus_42'] = 'pm_vorhanden';
|
|
app()->instance(StripeClient::class, $fake);
|
|
|
|
Livewire::actingAs(portalUserWithStripe())
|
|
->test(PaymentMethod::class)
|
|
->assertSee('4242');
|
|
});
|
|
|
|
it('says so instead of drawing a form that never loads', function () {
|
|
// Ohne Publishable Key lädt Elements nicht. Ein gezeichnetes, aber totes
|
|
// Kartenfeld ist die schlimmste Variante: der Kunde tippt seine Nummer
|
|
// ein, nichts passiert, und er hält seine Karte für abgelehnt.
|
|
StripePublishableKey::set('');
|
|
config()->set('services.stripe.key', '');
|
|
config()->set('services.stripe.key_test', '');
|
|
|
|
Livewire::actingAs(portalUserWithStripe())
|
|
->test(PaymentMethod::class)
|
|
->assertSet('clientSecret', null)
|
|
->assertSee(__('billing.card_unavailable'));
|
|
});
|
|
|
|
it('refuses a payment method id that is not one', function () {
|
|
// `confirmed()` wird aus dem Browser gerufen. Ohne diese Prüfung wäre das
|
|
// ein Weg, einen fremden Bezeichner an das eigene Stripe-Konto zu hängen.
|
|
$fake = new FakeStripeClient;
|
|
app()->instance(StripeClient::class, $fake);
|
|
|
|
Livewire::actingAs(portalUserWithStripe())
|
|
->test(PaymentMethod::class)
|
|
->call('confirmed', 'nicht-eine-pm-id')
|
|
->assertHasErrors();
|
|
|
|
expect($fake->defaultPaymentMethods)->toBe([]);
|
|
});
|
|
|
|
it('is not reachable for a visitor without a customer record', function () {
|
|
$fremder = User::factory()->create(['email' => 'ohne@portal.test', 'is_admin' => false]);
|
|
|
|
Livewire::actingAs($fremder)
|
|
->test(PaymentMethod::class)
|
|
->assertStatus(404);
|
|
});
|