Separate scan from approval
A scan should parse the QR payload, reject invalid structure, and resolve merchant details from a trusted source. Approval should happen only after the customer sees the resolved payee and amount. Try duplicate fields, very long fields, invalid encoding, stale references, and unknown versions. The parser should fail safely without freezing the app. Keep the exact synthetic payload and resulting screen as evidence for each case.
Keep the payload and the screen
Make synthetic QR payloads for a valid merchant, changed merchant ID, changed amount, duplicate fields, long fields, and unsupported format. Save payload text, QR image, parser output, resolved payee, displayed payee, and final server decision. A scan result is input, not a trusted merchant record. The approval screen should show details resolved by the server and match the committed payment. Test missing amount under the product’s own policy rather than assuming one rule fits every QR format.
Test cases and proof
| Case | Expected result | Proof to keep |
|---|---|---|
| Payee ID changed | Resolve and display actual payee | Confirmation screen |
| Amount outside limits | Reject or require valid entry | Payment result |
| Unknown optional field | Handle by documented rule | Parser output |
Parse the QR payload before payment
Build four fake QR payloads: valid merchant M1 for 500 NGN, amount changed to 5,000 NGN, unknown merchant M2, and duplicate transaction reference. Scan each and show the exact merchant and amount before approval. Reject invalid structure and unsafe redirects. The server must validate the final merchant and amount again; a safe display alone is not a payment rule. Save raw payload in a restricted test log, parsed fields, validation result, confirmation screen, and provider reference. Use a standard parser only for the QR format your scheme accepts. (EMVCo QR code overview).
Choose one QR format and one amount rule
Label the fixture with its scheme and parser version. For a dynamic quote QR, use merchant M1, reference Q1, and a fixed 500 NGN amount. Change the amount to 5,000 without changing Q1: the server must reject the mismatch against the stored quote. For a static merchant QR that lets the customer enter an amount, a changed amount is valid only after the customer sees and approves it. These are separate rules. A changed merchant ID that resolves to M2 must show M2 before approval or fail under the scheme. Keep an untampered positive case; do not reject every changed field just because the test changed it.
Separate corruption from authenticity
For a scheme that includes a CRC or checksum, alter a field without updating it and expect a checksum failure. Then update the checksum correctly after changing the merchant ID. A valid checksum does not prove that the merchant is genuine; the trusted merchant lookup and confirmation still apply. Use an encoded redirect to an outside host as a separate fixture if the format supports URLs. Follow only the scheme’s allowed host rule. Limit both raw payload length and decoded field lengths so repeated encoding cannot bypass the parser bound. Save the parser version and expected error for malformed and oversize inputs; a frozen scanner is a failed case.