'CluPilot Cloud e.U.', 'address' => 'Dreherstraße 66/1/8', 'postcode' => '1110', 'city' => 'Wien', 'vat_id' => 'ATU00000000', ]); }); function issuedInvoice(): App\Models\Invoice { $customer = Customer::factory()->create(['name' => 'Muster GmbH']); $orders = collect([Order::factory()->create([ 'customer_id' => $customer->id, 'amount_cents' => 1900, 'currency' => 'EUR', 'status' => 'paid', ])]); return app(IssueInvoice::class)->forOrders($customer, $orders); } it('attaches the invoice as a PDF named after its number', function () { // Filename and type only. The bytes are not asserted here and deliberately // not: TCPDF embeds a creation time and a document id, so two renders of // one invoice differ — a byte comparison would fail for a reason that has // nothing to do with the mail. What the renderer produces is tested where // the renderer is. $invoice = issuedInvoice(); $attachment = (new InvoiceMail($invoice, 'Muster GmbH'))->attachments()[0]; expect($attachment->as)->toBe($invoice->number.'.pdf') ->and($attachment->mime)->toBe('application/pdf'); }); it('renders a real PDF for the attachment to carry', function () { // The attachment is a closure, and a closure that returns nothing still // makes a perfectly valid mail with a nought-byte file on it. This is the // half that would be empty. $bytes = app(App\Services\Billing\InvoiceRenderer::class)->forInvoice(issuedInvoice()); expect(substr($bytes, 0, 5))->toBe('%PDF-') ->and(strlen($bytes))->toBeGreaterThan(10000); }); it('renders it from the frozen document, not from today’s settings', function () { $invoice = issuedInvoice(); CompanyProfile::put(['name' => 'Ein ganz anderer Name GmbH']); // The snapshot is what the renderer reads. The settings moved underneath // it and the document did not. expect($invoice->refresh()->snapshot['issuer']['name'])->toBe('CluPilot Cloud e.U.') ->and(app(App\Services\Billing\InvoiceRenderer::class)->forInvoice($invoice)) ->toBeString()->not->toBeEmpty(); }); it('names the amount and the number where somebody can read them', function () { // The attachment is the document; the mail still has to say what it is // about, because some clients only reveal an attachment once opened. $invoice = issuedInvoice(); $rendered = (new InvoiceMail($invoice, 'Muster GmbH'))->render(); expect($rendered)->toContain($invoice->number) ->toContain('22,80') ->toContain(__('mail.why_you_got_this')); });