Context
XML template generators depend on a full invoice data array, client data, and line items. Without shared test infrastructure, every developer writing or testing a template builds different fixture data from scratch — tests become inconsistent, hard to maintain, and cover different edge cases.
This issue delivers the foundation that all e-invoice template tests build on. All issues #16 – #21 depend on this scaffolding being in place.
Repository status (develop branch):
application/libraries/XMLtemplates/BaseXml.php already exists as the base class for all XML generators. All generator classes in the e-invoices repo extend it. The scaffolding and any new generators (see #18) must also extend BaseXml. Read BaseXml.php to understand the generator interface (xml() method signature, available helper methods) before building the scaffolding.
Deliverables
1. Invoice fixture builder
tests/helpers/EInvoiceTestFixture.php
class EInvoiceTestFixture
{
// B2B invoice: two line items, configurable tax rate (default 21%)
public static function standardInvoice(array $overrides = []): array;
// Intra-EU supply: one line at 0% VAT, exemption reason set
public static function zeroTaxInvoice(array $overrides = []): array;
// Credit note: negative amounts, reference to original invoice number
public static function creditNote(string $originalInvoiceNumber, array $overrides = []): array;
// B2G invoice: pre-populated with three routing codes
public static function b2gInvoice(array $routingCodes = [], array $overrides = []): array;
// B2C invoice: individual recipient, no company name
public static function b2cInvoice(array $overrides = []): array;
// Invoice with line-level discount
public static function discountedInvoice(array $overrides = []): array;
}
2. Client fixture builder
tests/helpers/EInvoiceClientFixture.php
class EInvoiceClientFixture
{
public static function belgian(array $overrides = []): array; // VAT BE0123456789, Peppol 9925:0123456789
public static function german(array $overrides = []): array; // VAT DE123456789
public static function french(array $overrides = []): array; // VAT FR12345678901
public static function italian(array $overrides = []): array; // VAT IT12345678901, delivery code XJ5ETH7
public static function italianPEC(array $overrides = []): array; // delivery code 0000000, PEC set
public static function italianIndividual(array $overrides = []): array; // no VAT, fiscal code set
public static function spanish(array $overrides = []): array; // VAT ESB12345678
public static function czech(array $overrides = []): array; // VAT CZ12345678, company number 12345678
public static function swedish(array $overrides = []): array; // VAT SE123456789001, GLN endpoint
public static function norwegian(array $overrides = []): array; // VAT NO974761076, endpoint 0192:974761076
}
3. Schema validator wrappers
tests/helpers/EInvoiceAssert.php
class EInvoiceAssert
{
// Validates against UBL 2.1 Invoice schema + OpenPeppol schematron
public static function validPeppol(string $xml, TestCase $test): void;
// Validates against KoSIT XRechnung 3.0 schematron
public static function validXRechnung(string $xml, TestCase $test): void;
// Validates against ISDOC 6.0.1 XSD
public static function validISDOC(string $xml, TestCase $test): void;
// Validates against FatturaPA v1.2 XSD
public static function validFatturaPA(string $xml, TestCase $test): void;
// Validates against Facturae XSD (3.2 or 3.2.1 — match actual config version)
public static function validFacturae(string $xml, TestCase $test): void;
// Validates against Factur-X / ZUGFeRD CII schema
public static function validZUGFeRD(string $xml, TestCase $test): void;
// Asserts that no ds:Signature element is present (Facturae output must be unsigned)
public static function noSignatureBlock(string $xml, TestCase $test): void;
}
Schema and schematron files are stored in tests/schemas/ — one subdirectory per standard. Include a README in that directory explaining where each schema file was sourced from and its version.
4. One complete example test
tests/einvoice/PeppolBISv30Test.php — demonstrates the AAA pattern using the scaffolding:
public function test_standard_b2b_invoice_is_valid_peppol(): void
{
// Arrange
$client = EInvoiceClientFixture::belgian();
$invoice = EInvoiceTestFixture::standardInvoice();
// Act
$generator = new Ublv24Xml(); // the actual generator class
$xml = $generator->xml($invoice, $client, $invoice['items']);
// Assert
EInvoiceAssert::validPeppol($xml, $this);
$this->assertStringContainsString('9925:0123456789', $xml);
}
5. Documentation
tests/TESTING.md — explains:
- How to run the e-invoice test suite
- How to write a new AAA test for an XML template
- Where the schema files come from and how to update them
- The
BaseXml contract: method signature, what the invoice/client/items arrays contain
- Required coverage: every template PR must include tests for standard invoice, credit note, and at least one error/validation scenario
Acceptance criteria
Delivery order
This issue should be completed before any of #16 – #20 are merged. Template PRs without AAA tests using this scaffolding should not be accepted.
Context
XML template generators depend on a full invoice data array, client data, and line items. Without shared test infrastructure, every developer writing or testing a template builds different fixture data from scratch — tests become inconsistent, hard to maintain, and cover different edge cases.
This issue delivers the foundation that all e-invoice template tests build on. All issues #16 – #21 depend on this scaffolding being in place.
Repository status (
developbranch):application/libraries/XMLtemplates/BaseXml.phpalready exists as the base class for all XML generators. All generator classes in the e-invoices repo extend it. The scaffolding and any new generators (see #18) must also extendBaseXml. ReadBaseXml.phpto understand the generator interface (xml()method signature, available helper methods) before building the scaffolding.Deliverables
1. Invoice fixture builder
tests/helpers/EInvoiceTestFixture.php2. Client fixture builder
tests/helpers/EInvoiceClientFixture.php3. Schema validator wrappers
tests/helpers/EInvoiceAssert.phpSchema and schematron files are stored in
tests/schemas/— one subdirectory per standard. Include aREADMEin that directory explaining where each schema file was sourced from and its version.4. One complete example test
tests/einvoice/PeppolBISv30Test.php— demonstrates the AAA pattern using the scaffolding:5. Documentation
tests/TESTING.md— explains:BaseXmlcontract: method signature, what the invoice/client/items arrays containAcceptance criteria
EInvoiceAssertvalidator wrappers implemented for all five in-scope standards plus ZUGFeRDtests/schemas/with a sourcing READMEUblv24Xml(the actual generator class)TESTING.mdwritten and covers all five points listed above, includingBaseXmlcontractDelivery order
This issue should be completed before any of #16 – #20 are merged. Template PRs without AAA tests using this scaffolding should not be accepted.