'CluPilot Cloud e.U.', 'address' => 'Dreherstraße 66/1/8', 'postcode' => '1110', 'city' => 'Wien', 'vat_id' => 'ATU00000000', ]); }); function invoiceFor(string $customerName): App\Models\Invoice { $customer = Customer::factory()->create(['name' => $customerName]); return app(IssueInvoice::class)->forOrders($customer, collect([ Order::factory()->create(['customer_id' => $customer->id, 'amount_cents' => 1900, 'currency' => 'EUR', 'status' => 'paid']), ])); } it('lists issued invoices with no way to edit or delete one', function () { // The absence is the feature. A wrong invoice is corrected by cancelling it // and issuing another, which is the only lawful way to correct one — so // there is no button here whose absence needs explaining. $invoice = invoiceFor('Muster GmbH'); Livewire::actingAs(operator('Owner'), 'operator') ->test(Invoices::class) ->assertSee($invoice->number) ->assertSee('Muster GmbH') ->assertDontSee(__('datacenters.edit')) ->assertDontSee(__('datacenters.delete')); }); it('finds an invoice by its number and by the customer on it', function () { invoiceFor('Muster GmbH'); $other = invoiceFor('Andere AG'); Livewire::actingAs(operator('Owner'), 'operator') ->test(Invoices::class) ->set('search', 'Andere') ->assertSee($other->number) ->assertDontSee('Muster GmbH'); }); it('serves the PDF from the frozen document', function () { $invoice = invoiceFor('Muster GmbH'); $response = $this->actingAs(operator('Owner'), 'operator') ->get(route('admin.invoices.pdf', $invoice->uuid)); $response->assertOk() ->assertHeader('content-type', 'application/pdf'); expect(substr($response->streamedContent(), 0, 5))->toBe('%PDF-'); }); it('does not hand the PDF to an operator without the capability', function () { $invoice = invoiceFor('Muster GmbH'); $this->actingAs(operator('Support'), 'operator') ->get(route('admin.invoices.pdf', $invoice->uuid)) ->assertForbidden(); }); it('does not hand the PDF to a customer', function () { // Its own test, and the guard named explicitly. Both matter: actingAs() // calls Auth::shouldUse(), so a second actingAs() in the same test with no // guard lands on whichever guard the FIRST one named — putting a User on // the operator guard, where EnsureAdmin calls isActive() on it and the // 403 becomes a 500. The trap is written up in CLAUDE.md and I walked into // it anyway. $invoice = invoiceFor('Muster GmbH'); $this->actingAs(User::factory()->create(), 'web') ->get(route('admin.invoices.pdf', $invoice->uuid)) ->assertForbidden(); });