Files
jayjennings 3e964d1176
CI / Lint, typecheck, test, build (push) Canceled after 0s
CI / End-to-end tests (push) Canceled after 0s
feat(i18n): add internationalization support with English and Spanish translations
feat(kiosk): implement kiosk report submission functionality with offline support

test(outbox): add tests for outbox functionality including report submission and error handling

feat(outbox): create outbox management for queued reports with IndexedDB persistence

feat(uuid): add UUID generation utility for client IDs

feat(qr): implement QR code generation for reporting links by site and area

feat(kiosk): create Kiosk page for reporting incidents without an account
2026-10-06 11:38:40 -07:00

93 lines
4.7 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { expect, test } from '@playwright/test'
import { signIn, unique, users } from './fixtures'
const token = () => process.env.E2E_KIOSK_TOKEN!
const site = () => process.env.E2E_SITE_ID!
const area = () => process.env.E2E_AREA_ID!
test('saves a report offline and sends it when the connection returns', async ({ page, context }) => {
const title = unique('Offline report: frayed sling')
await signIn(page, 'reporter')
await page.goto('/report')
await expect(page.getByLabel('Incident title')).toBeVisible()
await context.setOffline(true)
await page.getByLabel('Incident title').fill(title)
await page.getByRole('button', { name: 'Submit report' }).click()
await expect(page.getByRole('heading', { name: 'Saved on this device' })).toBeVisible()
await expect(page.getByText('1 report waiting to send')).toBeVisible()
await context.setOffline(false)
await expect(page.getByText('1 report waiting to send')).toBeHidden({ timeout: 15_000 })
await page.goto('/incidents')
await expect(page.getByRole('link', { name: title })).toBeVisible()
})
test('kiosk: reports without an account, in Spanish, from a QR code', async ({ browser, page }) => {
const title = unique('Cable suelto en el pasillo')
const kiosk = await (await browser.newContext({ locale: 'es-MX' })).newPage()
await kiosk.goto(`/k/${token()}?site=${site()}&area=${area()}`)
await expect(kiosk.getByRole('heading', { name: 'Reporte un problema de seguridad' })).toBeVisible()
await expect(kiosk.getByLabel('Edificio o área')).toHaveValue(area())
await kiosk.getByText('Peligro', { exact: true }).click()
await kiosk.getByText('Alta', { exact: true }).click()
await kiosk.getByLabel('En pocas palabras, ¿qué vio?').fill(title)
await kiosk.getByLabel('Su nombre').fill('Luis')
await kiosk.getByRole('button', { name: 'Enviar reporte' }).click()
await expect(kiosk.getByRole('heading', { name: 'Gracias' })).toBeVisible()
const reference = (await kiosk.getByText(/Su reporte INC-\d{4}/).textContent())!.match(/INC-\d{4}/)![0]
// Switching language works on the kiosk too
await kiosk.getByRole('button', { name: 'Reportar otra cosa' }).click()
await kiosk.getByRole('button', { name: 'English' }).click()
await expect(kiosk.getByRole('heading', { name: 'Report a safety concern' })).toBeVisible()
// The safety team sees who reported it and through which link
await signIn(page, 'admin')
await page.goto(`/incidents/${Number(reference.slice(4))}`)
await expect(page.getByRole('heading', { level: 1 })).toHaveText(title)
await expect(page.getByText('Reported by Luis via Canteen tablet')).toBeVisible()
await expect(page.getByText('Press Shop').first()).toBeVisible()
})
test('kiosk: a made-up or revoked link explains itself', async ({ page }) => {
await page.goto('/k/not-a-real-token')
await expect(page.getByText('This reporting link isn’t working')).toBeVisible()
})
test('QR codes open the report form with the location filled in', async ({ page, isMobile }) => {
test.skip(isMobile, 'Printing QR sheets is a desktop task')
await signIn(page, 'admin')
await page.goto(`/locations/qr?site=${site()}`)
await expect(page.getByRole('img', { name: /QR code for/ })).toHaveCount(2) // whole site + Press Shop
const url = await page.locator('main').getByText(/\/report\?site=/).nth(1).textContent()
expect(url).toContain(`area=${area()}`)
await page.goto(url!.trim())
await expect(page.getByText('Location filled in from the QR code.')).toBeVisible()
await expect(page.getByLabel('Building or area')).toHaveValue(area())
})
test('the signed-in app speaks Spanish too', async ({ page, isMobile }) => {
await signIn(page, 'reporter')
if (isMobile) await page.getByRole('button', { name: 'Open menu' }).click()
await page.getByRole('button', { name: 'Español' }).click()
if (isMobile) await page.getByRole('button', { name: 'Cerrar menú' }).click()
await page.goto('/report')
await expect(page.getByRole('heading', { name: 'Reportar un incidente' })).toBeVisible()
await expect(page.locator('html')).toHaveAttribute('lang', 'es')
await page.goto('/actions')
await expect(page.getByRole('heading', { name: 'Mis acciones' })).toBeVisible()
expect(users.reporter.email).toBeTruthy()
})
test('is installable: manifest and service worker', async ({ page }) => {
await page.goto('/login')
const manifest = await (await page.request.get('/manifest.webmanifest')).json()
expect(manifest).toMatchObject({ name: 'Open SafetyLog EHS', display: 'standalone' })
expect(manifest.icons.map((icon: { sizes: string }) => icon.sizes)).toEqual(expect.arrayContaining(['192x192', '512x512']))
const scope = await page.evaluate(async () => (await navigator.serviceWorker.ready).scope)
expect(scope).toMatch(/\/$/)
})