diff --git a/frontend/src/__tests__/GuestPaymentRedirect.spec.ts b/frontend/src/__tests__/GuestPaymentRedirect.spec.ts index 7e31b4b..81a606f 100644 --- a/frontend/src/__tests__/GuestPaymentRedirect.spec.ts +++ b/frontend/src/__tests__/GuestPaymentRedirect.spec.ts @@ -124,12 +124,16 @@ describe('GuestPaymentRedirect', () => { }) }) - it('renders QR code after loading swish info', async () => { + it('renders QR code with spec-compliant settings', async () => { const { wrapper } = await mountPage() await vi.waitFor(() => { expect(wrapper.find('.payment__qr-img').exists()).toBe(true) }) expect(mockToDataURL).toHaveBeenCalledTimes(1) + const options = mockToDataURL.mock.calls[0][1] + expect(options.margin).toBe(4) + expect(options.width).toBe(288) + expect(options.color).toEqual({ dark: '#000000', light: '#ffffff' }) }) it('renders Swish payment link', async () => { diff --git a/frontend/src/pages/GuestPaymentRedirect.vue b/frontend/src/pages/GuestPaymentRedirect.vue index f3261b2..a4c8e67 100644 --- a/frontend/src/pages/GuestPaymentRedirect.vue +++ b/frontend/src/pages/GuestPaymentRedirect.vue @@ -52,9 +52,15 @@ onMounted(async () => { if (swishPaymentUrl.value) { qrDataUrl.value = await QRCode.toDataURL(swishPaymentUrl.value, { - width: 224, - margin: 2, - color: { dark: '#111827', light: '#ffffff' }, + // Swish requires a reliably scannable black-on-white QR. The previous + // settings (margin 2, #111827, 224px) produced a 2-module quiet zone + // — half the QR spec minimum — which the Swish app's scanner fails to + // read when scanning off a screen. Use the spec-compliant 4-module + // quiet zone, pure black, and larger modules. + width: 288, + margin: 4, + errorCorrectionLevel: 'M', + color: { dark: '#000000', light: '#ffffff' }, }) } } catch { @@ -269,8 +275,8 @@ async function confirmPayment() { } .payment__qr-img { - width: 224px; - height: 224px; + width: 288px; + height: 288px; border-radius: var(--radius-md); margin: 0 auto var(--space-sm); }