|
| 1 | +/* |
| 2 | + * Copyright (C) 2026 Curity AB. All rights reserved. |
| 3 | + * |
| 4 | + * The contents of this file are the property of Curity AB. |
| 5 | + * You may not copy or use this file, in either source code |
| 6 | + * or executable form, except in compliance with terms |
| 7 | + * set by Curity AB. |
| 8 | + * |
| 9 | + * For further information, please contact Curity AB. |
| 10 | + */ |
| 11 | + |
| 12 | +import { describe, expect, it } from 'vitest'; |
| 13 | + |
| 14 | +import { getQrCodeAccessibility } from './qr-code-accessibility'; |
| 15 | + |
| 16 | +const PREFIX = 'authenticator.bankid.launch.view.qr.'; |
| 17 | +const key = (suffix: string) => `${PREFIX}${suffix}`; |
| 18 | + |
| 19 | +const INSTRUCTION_MESSAGES: Record<string, string> = { |
| 20 | + [key('instruction.heading')]: 'Help with scanning the QR code', |
| 21 | + [key('instruction.step1')]: 'Open the BankID app', |
| 22 | + [key('instruction.step2')]: 'Press the Scan QR code button', |
| 23 | + [key('instruction.step3')]: "Point your phone's camera at the QR code", |
| 24 | + [key('instruction.step4')]: 'Follow the instructions in the app', |
| 25 | + [key('instruction.outro')]: 'The QR code is displayed for a configurable period.', |
| 26 | +}; |
| 27 | + |
| 28 | +const SCREEN_READER_MESSAGES: Record<string, string> = { |
| 29 | + [key('screen-reader.heading')]: 'If you are using a screen reader', |
| 30 | + [key('screen-reader.intro')]: 'The most common error is that the full QR code is not visible. Try to:', |
| 31 | + [key('screen-reader.step1')]: 'Ensure the screen is on', |
| 32 | + [key('screen-reader.step2')]: 'Zoom out in the browser', |
| 33 | + [key('screen-reader.step3')]: 'Zoom out using magnification tools', |
| 34 | + [key('screen-reader.step4')]: 'Make sure the browser window is maximized by:', |
| 35 | + [key('screen-reader.step4.1')]: 'Clicking on the QR code above or', |
| 36 | + [key('screen-reader.step4.2')]: 'Using keyboard shortcuts', |
| 37 | + [key('screen-reader.step4.2.1')]: 'Windows: Ctrl+Arrow up', |
| 38 | + [key('screen-reader.step4.2.2')]: 'Mac: Ctrl+Cmd+F', |
| 39 | + [key('screen-reader.outro')]: 'Hold the phone in portrait mode about 40 cm away from the screen.', |
| 40 | +}; |
| 41 | + |
| 42 | +describe('getQrCodeAccessibility', () => { |
| 43 | + it('builds both sections from a complete message set', () => { |
| 44 | + const result = getQrCodeAccessibility({ ...INSTRUCTION_MESSAGES, ...SCREEN_READER_MESSAGES }); |
| 45 | + |
| 46 | + expect(result).toEqual({ |
| 47 | + instruction: { |
| 48 | + heading: 'Help with scanning the QR code', |
| 49 | + items: [ |
| 50 | + { text: 'Open the BankID app' }, |
| 51 | + { text: 'Press the Scan QR code button' }, |
| 52 | + { text: "Point your phone's camera at the QR code" }, |
| 53 | + { text: 'Follow the instructions in the app' }, |
| 54 | + ], |
| 55 | + outro: 'The QR code is displayed for a configurable period.', |
| 56 | + }, |
| 57 | + screenReader: { |
| 58 | + heading: 'If you are using a screen reader', |
| 59 | + intro: 'The most common error is that the full QR code is not visible. Try to:', |
| 60 | + items: [ |
| 61 | + { text: 'Ensure the screen is on' }, |
| 62 | + { text: 'Zoom out in the browser' }, |
| 63 | + { text: 'Zoom out using magnification tools' }, |
| 64 | + { |
| 65 | + text: 'Make sure the browser window is maximized by:', |
| 66 | + items: [ |
| 67 | + { text: 'Clicking on the QR code above or' }, |
| 68 | + { |
| 69 | + text: 'Using keyboard shortcuts', |
| 70 | + items: [{ text: 'Windows: Ctrl+Arrow up' }, { text: 'Mac: Ctrl+Cmd+F' }], |
| 71 | + }, |
| 72 | + ], |
| 73 | + }, |
| 74 | + ], |
| 75 | + outro: 'Hold the phone in portrait mode about 40 cm away from the screen.', |
| 76 | + }, |
| 77 | + }); |
| 78 | + }); |
| 79 | + |
| 80 | + it('returns undefined when there are no messages', () => { |
| 81 | + expect(getQrCodeAccessibility(undefined)).toBeUndefined(); |
| 82 | + }); |
| 83 | + |
| 84 | + it('builds only the section whose messages are present', () => { |
| 85 | + const result = getQrCodeAccessibility(INSTRUCTION_MESSAGES); |
| 86 | + |
| 87 | + expect(result?.instruction).toBeDefined(); |
| 88 | + expect(result?.screenReader).toBeUndefined(); |
| 89 | + }); |
| 90 | + |
| 91 | + it('omits a section whose message set is incomplete', () => { |
| 92 | + const incompleteInstructions = Object.fromEntries( |
| 93 | + Object.entries(INSTRUCTION_MESSAGES).filter(([messageKey]) => messageKey !== key('instruction.outro')) |
| 94 | + ); |
| 95 | + |
| 96 | + expect(getQrCodeAccessibility(incompleteInstructions)).toBeUndefined(); |
| 97 | + }); |
| 98 | + |
| 99 | + it('resolves messages by the ".view.qr." suffix regardless of the key prefix', () => { |
| 100 | + const waitPrefixed = Object.fromEntries( |
| 101 | + Object.entries(INSTRUCTION_MESSAGES).map(([messageKey, value]) => [ |
| 102 | + messageKey.replace('.launch.view.qr.', '.wait.view.qr.'), |
| 103 | + value, |
| 104 | + ]) |
| 105 | + ); |
| 106 | + |
| 107 | + expect(getQrCodeAccessibility(waitPrefixed)?.instruction?.heading).toBe('Help with scanning the QR code'); |
| 108 | + }); |
| 109 | + |
| 110 | + it('ignores keys without the ".view.qr." marker', () => { |
| 111 | + const result = getQrCodeAccessibility({ |
| 112 | + ...INSTRUCTION_MESSAGES, |
| 113 | + 'authenticator.bankid.launch.page.title': 'Login with BankID', |
| 114 | + }); |
| 115 | + |
| 116 | + expect(result?.instruction).toBeDefined(); |
| 117 | + expect(JSON.stringify(result)).not.toContain('Login with BankID'); |
| 118 | + }); |
| 119 | +}); |
0 commit comments