passerelle/tests/js/qrcode.test.js

206 lines
7.1 KiB
JavaScript

import 'qrcode/qrcode-reader.js'
import { expect, test, vi} from 'vitest'
import ZXingBrowser from 'qrcode/zxing-browser.min.js'
import nacl from 'qrcode/nacl.min.js'
const okCodeData =
'SVF.WB899RLB0%7NFKM.IWSBLTVZ65OQKD59REJ+ I/IDL960%HL%F 5EVVK397HQGIUK3OAPOP0RF/X' +
'L1FIKJG08J5 LE.G9%EPEDUF7M.C%47SW64DC4W5NF6$CC1S64VCBW53ECQZCGPCSG6C%6YZC:DC-96N' +
'E1AECPED-EDLFF QEGEC9VE634L%6 47%47C%6446D36K/EXVDAVCRWEV2C0/DUF7:967461R67:6OA7' +
'Y$5DE1HEC1WE..DF$DUF7/B8-ED:JCSTDR.C4LE1WE..DF$DUF771904E93DKOEXVDKPCF/DV CP9EIE' +
'C*ZCT34ZA8.Q6$Q6HB8A0'
const invalidCodeData = 'https://georges-abitbol.fr'
const invalidSignatureData =
'ELT7PRQKJ097ZM1TA5$EJC%NOMVL5D5QNEZUR.Q5JESA5D+GO*I16IAYJO:D4ZGU GTVIM%DHI88%CGD' +
'0W6LBKOWSKLRC$ R9%EPEDUF7OB7GPC 57Y47BX5-A6+/61S6$57CW5/Q6+TCRW6GA7 57QF6H*6C56N' +
'E1AECPED-EDLFF QEGEC9VE634L%6 47%47C%6446D36K/EXVDAVCRWEV2C0/DUF7:96646L%6946OA7' +
'Y$5DE1HEC1WE..DF$DUF70A8R.C4LE1WE..DF$DUF7VF8XVDKPCF/DV CP9EIEC*ZCO34A0'
const qrcodeReaderTest = test.extend({
mock: async ({ task }, use) => {
let resolveResult = undefined
let resultPromise = new Promise((resolve) => resolveResult = resolve)
let resolveResultHandled = undefined
const terminate = Symbol()
class MockBrowserQRCodeReader {
async decodeFromVideoDevice(device, element, callback) {
while(true) {
const result = await resultPromise
if(result === terminate) {
return
}
resultPromise = new Promise((resolve) => resolveResult = resolve)
callback({ text: result })
resolveResultHandled()
}
}
}
window.nacl = nacl
navigator.mediaDevices = true
const savedZXingBrowser = window.ZXingBrowser
window.ZXingBrowser = { BrowserQRCodeReader : MockBrowserQRCodeReader }
const reader = document.createElement('qrcode-reader')
reader.setAttribute('verify-key', 'f81af42f9f9422d2393859d40994a42cdb2ef68507f056292ac96d1de1f1af83')
document.append(reader)
await use({
reader,
scan: async (text) => {
const resultHandled = new Promise((resolve) => resolveResultHandled = resolve)
resolveResult(text)
await resultHandled
}
})
vi.useFakeTimers()
reader.remove()
vi.useRealTimers ()
resolveResult(terminate)
window.ZXingBrowser = savedZXingBrowser
navigator.mediaDevices = undefined
window.nacl = undefined
}
})
test('qrcode reader shows a warning message if not supported on platform', async ({mock}) => {
const reader = document.createElement('qrcode-reader')
reader.setAttribute('verify-key', 'f81af42f9f9422d2393859d40994a42cdb2ef68507f056292ac96d1de1f1af83')
document.append(reader)
expect(reader.innerText).toBe('not_supported')
})
qrcodeReaderTest('qrcode reader shows valid qrcode informations', async ({mock}) => {
const { reader, scan } = mock
vi.setSystemTime(new Date(2023, 11, 1))
await scan(okCodeData)
const popup = reader.querySelector('.qrcode-reader--popup')
const title = popup.querySelector('.qrcode-reader--popup-title')
expect(popup.classList.contains('closed')).toBe(false)
expect(popup.classList.contains('error')).toBe(false)
expect(title.innerText).toBe('valid')
const validity = popup.querySelector('.qrcode-reader--validity')
expect(validity.innerText).toMatch(/from :\s*31\/10\/2023 23:00:00\s*to :\s*01\/12\/2023 22:59:59/)
const labels = popup.querySelectorAll('.qrcode-reader--data-item-label')
expect(labels.length).toBe(3)
expect(labels[0].innerText).toMatch('last_name')
expect(labels[1].innerText).toMatch('first_name')
expect(labels[2].innerText).toMatch('license_plate')
const values = popup.querySelectorAll('.qrcode-reader--data-item-value')
expect(values.length).toBe(3)
expect(values[0].innerText).toMatch('Abitbol')
expect(values[1].innerText).toMatch('Georges')
expect(values[2].innerText).toMatch('HA-424-AH')
const closeButton = reader.querySelector('.qrcode-reader--close-popup-button')
closeButton.dispatchEvent(new Event('click'))
expect(popup.classList.contains('closed')).toBe(true)
})
qrcodeReaderTest('qrcode reader shows error on not yet valid or expired qrcodes', async ({mock}) => {
const { reader, scan } = mock
vi.setSystemTime(new Date(2023, 9, 31)) // monthes start at 0 index, wtf javascript
await scan(okCodeData)
const popup = reader.querySelector('.qrcode-reader--popup')
const title = popup.querySelector('.qrcode-reader--popup-title')
expect(popup.classList.contains('closed')).toBe(false)
expect(popup.classList.contains('error')).toBe(true)
expect(title.innerText).toBe('not_yet_valid')
vi.setSystemTime(new Date(2023, 11, 2)) // monthes start at 0 index, wtf javascript
await scan(okCodeData)
expect(popup.classList.contains('closed')).toBe(false)
expect(popup.classList.contains('error')).toBe(true)
expect(title.innerText).toBe('expired')
})
qrcodeReaderTest('qrcode reader shows error on invalid qrcode', async ({mock}) => {
const { reader, scan } = mock
await scan(invalidCodeData)
const popup = reader.querySelector('.qrcode-reader--popup')
const title = reader.querySelector('.qrcode-reader--popup-title')
const content = reader.querySelector('.qrcode-reader--popup-content')
expect(popup.classList.contains('closed')).toBe(false)
expect(popup.classList.contains('error')).toBe(true)
expect(title.innerText).toBe('invalid_title')
expect(content.innerText).toBe('invalid_qrcode')
const closeButton = reader.querySelector('.qrcode-reader--close-popup-button')
closeButton.dispatchEvent(new Event('click'))
expect(popup.classList.contains('closed')).toBe(true)
})
qrcodeReaderTest('qrcode reader shows error on invalid signature', async ({mock}) => {
const { reader, scan } = mock
await scan(invalidSignatureData)
const popup = reader.querySelector('.qrcode-reader--popup')
const title = reader.querySelector('.qrcode-reader--popup-title')
const content = reader.querySelector('.qrcode-reader--popup-content')
expect(popup.classList.contains('closed')).toBe(false)
expect(popup.classList.contains('error')).toBe(true)
expect(title.innerText).toBe('invalid_title')
expect(content.innerText).toBe('invalid_signature')
const closeButton = reader.querySelector('.qrcode-reader--close-popup-button')
closeButton.dispatchEvent(new Event('click'))
expect(popup.classList.contains('closed')).toBe(true)
})
qrcodeReaderTest('qrcode reader can toggle fullscreen', async ({mock}) => {
const { reader } = mock
const fullscreenButton = reader.querySelector('.qrcode-reader--fullscreen-button')
reader.requestFullscreen = vi.fn()
document.exitFullscreen = vi.fn()
fullscreenButton.dispatchEvent(new Event('click'))
expect(reader.requestFullscreen).toHaveBeenCalled()
expect(document.exitFullscreen).not.toHaveBeenCalled()
expect(reader.classList.contains('fullscreen')).toBe(true)
vi.clearAllMocks()
document.fullscreenElement = reader
fullscreenButton.dispatchEvent(new Event('click'))
expect(reader.requestFullscreen).not.toHaveBeenCalled()
expect(document.exitFullscreen).toHaveBeenCalled()
expect(reader.classList.contains('fullscreen')).toBe(false)
})