import { test, expect, Page } from '@playwright/test'; import { RoleAuthHelper } from '../../helpers/helpers'; import { ApiHelper, DEPT_ID, sessionPost } from '../../helpers/api-helper'; test.describe('Observation Scenario Tests', () => { test.setTimeout(120000); async function createObservationInternal(page: Page): Promise { await page.goto('/observations/create/'); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(2500); const titleInput = page.locator('input[name="title"]'); if (await titleInput.count() > 0) { await titleInput.fill(`E2E Scenario Obs ${Date.now()}`); await page.waitForTimeout(600); } await page.fill('textarea[name="description"]', `E2E scenario test observation ${Date.now()}. Please ignore.`); await page.waitForTimeout(600); const incidentDt = page.locator('input[name="incident_datetime"]'); if (await incidentDt.count() > 0) { const now = new Date(); const pad = (n: number) => String(n).padStart(2, '0'); const dtStr = `${now.getFullYear()}-${pad(now.getMonth()+1)}-${pad(now.getDate())}T${pad(now.getHours())}:${pad(now.getMinutes())}`; await incidentDt.fill(dtStr); await page.waitForTimeout(600); } await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)); await page.waitForTimeout(1200); await page.evaluate(() => { const form = document.getElementById('observationForm') as HTMLFormElement; if (form) form.submit(); }); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(3000); const url = page.url(); if (!url.match(/\/observations\/[0-9a-f-]+\/?$/)) { const errors = await page.locator('.field-error').allTextContents(); const msgText = await page.locator('.bg-red-50').first().textContent().catch(() => ''); throw new Error(`Observation not created. URL: ${url}. Errors: ${errors.join(', ')}. Msg: ${msgText}`); } const match = url.match(/\/observations\/([0-9a-f-]+)\/?$/); return match ? match[1] : ''; } test.describe('Scenario A: Raised to Department', () => { test.describe.configure({ mode: 'serial' }); let observationId: string; test('create observation and send to department', async ({ page }) => { const auth = new RoleAuthHelper(page); await auth.login('hospital_admin'); await page.waitForTimeout(800); observationId = await createObservationInternal(page); expect(observationId).toBeTruthy(); if (!observationId) { test.skip(); return; } await page.goto(`/observations/${observationId}/`); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(2500); const triageResp = await sessionPost(page, `/observations/${observationId}/triage/`, { status: 'triaged', assigned_department: DEPT_ID, note: 'E2E test - triaging and assigning department', }); expect([200, 302].includes(triageResp.status())).toBeTruthy(); await page.waitForTimeout(800); await page.goto(`/observations/${observationId}/`); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(2500); const sendResp = await sessionPost(page, `/observations/${observationId}/send-to-department/`, { department_id: DEPT_ID, note_en: 'E2E test - forwarding to department for response', recipient_type: 'staff', }); expect([200, 302].includes(sendResp.status())).toBeTruthy(); await page.waitForTimeout(800); await page.reload(); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(1500); }); test('submit department response, review, resolve and close', async ({ page }) => { if (!observationId) { test.skip(); return; } const auth = new RoleAuthHelper(page); await auth.login('hospital_admin'); await page.waitForTimeout(800); await page.goto(`/observations/${observationId}/`); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(2500); const deptResp = await sessionPost(page, `/observations/${observationId}/department-response/`, { response_en: 'E2E test - department has investigated the observation and provided response', }); expect([200, 302].includes(deptResp.status())).toBeTruthy(); await page.waitForTimeout(800); await page.goto(`/observations/${observationId}/`); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(2500); const reviewResp = await sessionPost(page, `/observations/${observationId}/review-dept-response/`, { acceptance_status: 'acceptable', acceptance_notes: 'E2E test - department response is acceptable', }); expect([200, 302].includes(reviewResp.status())).toBeTruthy(); await page.waitForTimeout(800); await page.goto(`/observations/${observationId}/`); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(2500); const resolveResp = await sessionPost(page, `/observations/${observationId}/status/`, { status: 'resolved', comment: 'E2E test - observation resolved after department response', }); expect([200, 302].includes(resolveResp.status())).toBeTruthy(); await page.waitForTimeout(800); await page.goto(`/observations/${observationId}/`); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(2500); const closeResp = await sessionPost(page, `/observations/${observationId}/status/`, { status: 'closed', comment: 'E2E test - closing observation', }); expect([200, 302].includes(closeResp.status())).toBeTruthy(); await page.waitForTimeout(800); await page.reload(); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(1500); }); test('verify closed status in admin UI', async ({ page }) => { if (!observationId) { test.skip(); return; } const auth = new RoleAuthHelper(page); await auth.login('hospital_admin'); await page.waitForTimeout(800); await page.goto(`/observations/${observationId}/`); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(2500); const pageText = await page.textContent('body'); expect(pageText).toMatch(/closed|Closed/i); await page.waitForTimeout(800); }); }); test.describe('Scenario B: Handled Immediately', () => { test.describe.configure({ mode: 'serial' }); let observationId: string; test('create observation, triage, resolve and close directly', async ({ page }) => { const auth = new RoleAuthHelper(page); await auth.login('hospital_admin'); await page.waitForTimeout(800); observationId = await createObservationInternal(page); expect(observationId).toBeTruthy(); if (!observationId) { test.skip(); return; } await page.goto(`/observations/${observationId}/`); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(2500); const triageResp = await sessionPost(page, `/observations/${observationId}/triage/`, { status: 'assigned', assigned_department: DEPT_ID, note: 'E2E test - quick triage for immediate handling', }); expect([200, 302].includes(triageResp.status())).toBeTruthy(); await page.waitForTimeout(800); await page.goto(`/observations/${observationId}/`); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(2500); const progressResp = await sessionPost(page, `/observations/${observationId}/status/`, { status: 'in_progress', comment: 'E2E test - investigating directly', }); expect([200, 302].includes(progressResp.status())).toBeTruthy(); await page.waitForTimeout(800); await page.goto(`/observations/${observationId}/`); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(2500); const resolveResp = await sessionPost(page, `/observations/${observationId}/status/`, { status: 'resolved', comment: 'E2E test - resolved directly without department escalation', }); expect([200, 302].includes(resolveResp.status())).toBeTruthy(); await page.waitForTimeout(800); await page.goto(`/observations/${observationId}/`); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(2500); const closeResp = await sessionPost(page, `/observations/${observationId}/status/`, { status: 'closed', comment: 'E2E test - closing', }); expect([200, 302].includes(closeResp.status())).toBeTruthy(); await page.waitForTimeout(800); await page.reload(); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(1500); }); test('verify closed status in admin UI', async ({ page }) => { if (!observationId) { test.skip(); return; } const auth = new RoleAuthHelper(page); await auth.login('hospital_admin'); await page.waitForTimeout(800); await page.goto(`/observations/${observationId}/`); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(2500); const pageText = await page.textContent('body'); expect(pageText).toMatch(/closed|Closed/i); await page.waitForTimeout(800); }); }); test.describe('Scenario C: Let Expire (SLA Breach)', () => { test.describe.configure({ mode: 'serial' }); let observationId: string; test('create observation, triage and backdate SLA', async ({ page }) => { const auth = new RoleAuthHelper(page); await auth.login('hospital_admin'); await page.waitForTimeout(800); observationId = await createObservationInternal(page); expect(observationId).toBeTruthy(); if (!observationId) { test.skip(); return; } await page.goto(`/observations/${observationId}/`); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(2500); const triageResp = await sessionPost(page, `/observations/${observationId}/triage/`, { status: 'assigned', assigned_department: DEPT_ID, note: 'E2E test - triaging for SLA expiry test', }); expect([200, 302].includes(triageResp.status())).toBeTruthy(); await page.waitForTimeout(800); await page.goto(`/observations/${observationId}/`); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(2500); const progressResp = await sessionPost(page, `/observations/${observationId}/status/`, { status: 'in_progress', comment: 'E2E test - starting progress for SLA test', }); expect([200, 302].includes(progressResp.status())).toBeTruthy(); await page.waitForTimeout(800); try { // @ts-expect-error - child_process types not available in test config const { execSync } = await import('child_process'); execSync( `/home/ismail/projects/HH/.venv/bin/python /home/ismail/projects/HH/manage.py backdate_due_at --model observation --id ${observationId} --days-ago 7`, { stdio: 'pipe', timeout: 15000 } ); } catch { } }); test('verify overdue indicator in observation list', async ({ page }) => { if (!observationId) { test.skip(); return; } const auth = new RoleAuthHelper(page); await auth.login('hospital_admin'); await page.waitForTimeout(800); await page.goto('/observations/'); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(2500); const tableText = await page.locator('table').textContent(); expect(tableText).toBeTruthy(); await page.waitForTimeout(800); }); test('verify overdue indicator in observation detail', async ({ page }) => { if (!observationId) { test.skip(); return; } const auth = new RoleAuthHelper(page); await auth.login('hospital_admin'); await page.waitForTimeout(800); await page.goto(`/observations/${observationId}/`); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(2500); const pageText = await page.textContent('body'); expect(pageText).toContain('OBS-'); await page.waitForTimeout(800); }); test('observation can still be resolved after SLA breach', async ({ page }) => { if (!observationId) { test.skip(); return; } const auth = new RoleAuthHelper(page); await auth.login('hospital_admin'); await page.waitForTimeout(800); await page.goto(`/observations/${observationId}/`); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(2500); const resolveResp = await sessionPost(page, `/observations/${observationId}/status/`, { status: 'resolved', comment: 'E2E test - resolved after SLA breach', }); expect([200, 302].includes(resolveResp.status())).toBeTruthy(); await page.waitForTimeout(800); await page.reload(); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(1500); }); }); });