'CluPilot GmbH', 'address' => 'Musterstraße 1', 'postcode' => '1010', 'city' => 'Wien', 'vat_id' => 'ATU12345678', ]); $this->customer = Customer::factory()->create([ 'name' => 'Beispiel GmbH', 'contact_name' => 'Bea Berger', 'phone' => '+43 1 2345678', 'billing_address' => "Musterstraße 2\n1020 Wien", 'vat_id' => 'ATU99999999', 'customer_type' => Customer::TYPE_BUSINESS, ]); }); it('opens on the details, and keeps that tab out of the address bar', function () { Livewire::actingAs(operator('Owner'), 'operator') ->test(CustomerDetail::class, ['uuid' => $this->customer->uuid]) ->assertSet('tab', 'overview') // The things somebody on the phone needs first. ->assertSee('Bea Berger') ->assertSee('+43 1 2345678') ->assertSee('ATU99999999') ->assertSee('1020 Wien') ->assertSee(__('customer_detail.type_business')); }); it('remembers the tab across a reload, because it is in the URL', function () { Livewire::withQueryParams(['tab' => 'billing']) ->actingAs(operator('Owner'), 'operator') ->test(CustomerDetail::class, ['uuid' => $this->customer->uuid]) ->assertSet('tab', 'billing') ->assertSee(__('customer_detail.invoices')); }); it('falls back to the first tab when the URL names one that does not exist', function () { Livewire::withQueryParams(['tab' => 'wat']) ->actingAs(operator('Owner'), 'operator') ->test(CustomerDetail::class, ['uuid' => $this->customer->uuid]) ->assertSet('tab', 'overview'); }); it('says a customer nobody asked is treated as a consumer', function () { // Not cosmetic: it decides whether a withdrawal right exists at all, and the // page must not let "nobody asked" read as "business". $unknown = Customer::factory()->create(['customer_type' => null]); Livewire::actingAs(operator('Owner'), 'operator') ->test(CustomerDetail::class, ['uuid' => $unknown->uuid]) ->assertSee(__('customer_detail.type_unknown')); }); it('shows the contract the customer is owed, with its own frozen figures', function () { // The contract's own price, not today's catalogue: a price rise does not // reach back into what somebody already bought. Subscription::factory()->plan('team')->create([ 'customer_id' => $this->customer->id, 'status' => 'active', ]); Livewire::withQueryParams(['tab' => 'package']) ->actingAs(operator('Owner'), 'operator') ->test(CustomerDetail::class, ['uuid' => $this->customer->uuid]) ->assertSee(__('billing.plan.team')) ->assertSee('500 GB') // team's quota ->assertSee(__('customer_detail.price')); }); it('shows the machine, and says so plainly when there is none', function () { Livewire::withQueryParams(['tab' => 'package']) ->actingAs(operator('Owner'), 'operator') ->test(CustomerDetail::class, ['uuid' => $this->customer->uuid]) ->assertSee(__('customer_detail.no_contract')); Subscription::factory()->plan('start')->create(['customer_id' => $this->customer->id, 'status' => 'active']); Instance::factory()->create([ 'customer_id' => $this->customer->id, 'subdomain' => 'kanzlei-berger', 'status' => 'active', ]); Livewire::withQueryParams(['tab' => 'package']) ->actingAs(operator('Owner'), 'operator') ->test(CustomerDetail::class, ['uuid' => $this->customer->uuid]) ->assertSee('kanzlei-berger'); }); it('shows what was invoiced and what was bought, which are two questions', function () { // An order is a purchase; an invoice is a document about one. A customer // asking "was das schon verrechnet?" is asking about the second. InvoiceSeries::query()->firstOrCreate( ['kind' => 'invoice'], ['name' => 'Rechnungen', 'prefix' => 'RE', 'active' => true], ); Order::factory()->create([ 'customer_id' => $this->customer->id, 'plan' => 'start', 'amount_cents' => 4900, 'status' => 'paid', ]); Invoice::create([ 'invoice_series_id' => InvoiceSeries::query()->first()->id, 'customer_id' => $this->customer->id, 'number' => 'RE-2026-0007', 'number_year' => 2026, 'number_sequence' => 7, 'issued_on' => now()->toDateString(), 'due_on' => now()->addDays(14)->toDateString(), 'snapshot' => ['meta' => ['number' => 'RE-2026-0007']], 'net_cents' => 4900, 'tax_cents' => 980, 'gross_cents' => 5880, 'currency' => 'EUR', ]); Livewire::withQueryParams(['tab' => 'billing']) ->actingAs(operator('Owner'), 'operator') ->test(CustomerDetail::class, ['uuid' => $this->customer->uuid]) ->assertSee('RE-2026-0007') ->assertSee('58,80') ->assertSee(__('customer_detail.orders')); }); it('offers writing last, because it is what you do after reading', function () { $tabs = CustomerDetail::TABS; expect($tabs[0])->toBe('overview') ->and(end($tabs))->toBe('compose'); // Every tab has a label, or the bar reads "customer_detail.tab.x". foreach ($tabs as $tab) { expect(__('customer_detail.tab.'.$tab))->not->toBe('customer_detail.tab.'.$tab); } }); it('does not print a lang key at anybody', function () { // The badge read "customers.status.active" once. A key with no file behind // it renders as itself and Laravel says nothing about it. $page = Livewire::actingAs(operator('Owner'), 'operator') ->test(CustomerDetail::class, ['uuid' => $this->customer->uuid]); $page->assertDontSee('customers.status.') ->assertDontSee('customer_detail.tab.') ->assertSee(__('admin.status.active')); });