HH/e2e/tests/workflows/observation-scenarios.spec.ts
ismail c5f76b3855
Some checks are pending
Build and Push Docker Image / build (push) Waiting to run
updates
2026-05-11 14:45:30 +03:00

350 lines
13 KiB
TypeScript

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<string> {
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);
});
});
});