/* eslint-disable */ /** * COMPREHENSIVE WORKFLOW TEST — all untested modules. * Drives the key workflow for: Surveys, RCA, PX Actions, Organizations * (staff/dept/patient), Notifications, Physicians, Presentations, Callcenter, * Executive, Standards, References, Social, AI Engine. * * Each module gets a section that creates/lists/interacts with its data. * Issues are observed and recorded; failures don't abort the suite. * * Run headed: * E2E_MAXIMIZED=1 E2E_TIMEOUT=120000 E2E_ACTION_TIMEOUT=12000 \ * npx playwright test --headed --project chromium comprehensive-workflow-audit --workers=1 */ import { test } from '@playwright/test'; import { attachObservers, observe, bodyHasTraceback, loginAndScope, OBS, BASE_URL, selectE2EHospital } from '../../helpers/audit'; import { RoleName } from '../../helpers/helpers'; const M = 'ComprehensiveAudit'; const ADMIN: RoleName = 'hospital_admin'; type Page = import('@playwright/test').Page; async function login(page: Page, role: RoleName = ADMIN) { await page.context().clearCookies(); await loginAndScope(page, role, M); } async function csrfOf(page: Page): Promise { return page.context().cookies().then((c) => c.find((x) => x.name === 'csrftoken')?.value || ''); } async function postForm(page: Page, url: string, data: Record) { const csrf = await csrfOf(page); return page.context().request.post(url, { maxRedirects: 0, headers: { 'X-Requested-With': 'XMLHttpRequest', ...(csrf ? { 'X-CSRFToken': csrf } : {}) }, form: { csrfmiddlewaretoken: csrf, ...data }, }); } async function visit(page: Page, url: string, label: string, role: RoleName = ADMIN) { try { await page.goto(`${BASE_URL}${url}`); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(800); const tb = await bodyHasTraceback(page); const onLogin = page.url().includes('/accounts/login'); const body = (await page.textContent('body')) || ''; const hasData = body.length > 300; observe(M, label, tb ? 'FAIL' : onLogin ? 'WARN' : 'PASS', tb ? `traceback: ${tb}` : onLogin ? 'redirected to login' : `loaded (${body.length} chars)${hasData ? ' +data' : ''}`, { role, url: page.url() }); return !tb && !onLogin; } catch (e) { observe(M, label, 'FAIL', `exception: ${(e as Error).message}`, { role }); return false; } } async function visitAndPost(page: Page, getUrl: string, postUrl: string, data: Record, label: string) { const loaded = await visit(page, getUrl, `${label}-page`, ADMIN); if (!loaded) return; try { const r = await postForm(page, `${BASE_URL}${postUrl}`, data); observe(M, label, r.status() < 400 ? 'PASS' : 'FAIL', `POST HTTP ${r.status()}`, { http: r.status() }); } catch (e) { observe(M, label, 'FAIL', `exception: ${(e as Error).message}`, {}); } } // =========================================================================== test.describe('Comprehensive Workflow Audit', () => { test.describe.configure({ mode: 'serial' }); // ── 1. RCA ────────────────────────────────────────────────────────────── test('RCA: create from complaint + add root cause + status', async ({ page }) => { attachObservers(page, M, ADMIN); await login(page); // seed a complaint first const { execSync } = require('child_process'); const path = require('path'); const root = path.resolve(__dirname, '..', '..', '..'); const seedOut = execSync('uv run manage.py seed_e2e_complaint', { cwd: root }).toString(); const cid = seedOut.match(/complaint_id=([0-9a-f-]+)/)?.[1]; if (!cid) { observe(M, 'rca-seed', 'FAIL', 'no complaint seeded', {}); return; } // create RCA linked to the complaint await visit(page, `/rca/create/?related_model=complaint&related_id=${cid}`, 'rca-create-page'); const csrf = await csrfOf(page); try { const r = await postForm(page, `${BASE_URL}/rca/create/`, { title: 'E2E RCA Test', description: 'E2E automated RCA', severity: 'medium', priority: 'medium', hospital: '', department: '', related_model: 'complaint', related_id: cid, }); observe(M, 'rca-create', r.status() < 400 ? 'PASS' : 'WARN', `create HTTP ${r.status()}`, { http: r.status() }); } catch (e) { observe(M, 'rca-create', 'FAIL', `exception: ${(e as Error).message}`, {}); } // list await visit(page, '/rca/', 'rca-list'); // detail of first RCA const body = (await page.textContent('body')) || ''; const rcaMatch = body.match(/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/); if (rcaMatch) { await visit(page, `/rca/${rcaMatch[0]}/`, 'rca-detail'); } }); // ── 2. PX Actions ─────────────────────────────────────────────────────── test('PX Actions: list + create + detail', async ({ page }) => { attachObservers(page, M, ADMIN); await login(page); await visit(page, '/actions/', 'actions-list'); await visit(page, '/actions/create/', 'actions-create-page'); }); // ── 3. Surveys ────────────────────────────────────────────────────────── test('Surveys: templates + instances + analytics + send', async ({ page }) => { attachObservers(page, M, ADMIN); await login(page); await visit(page, '/surveys/templates/', 'survey-templates'); await visit(page, '/surveys/instances/', 'survey-instances'); await visit(page, '/surveys/analytics/', 'survey-analytics'); await visit(page, '/surveys/send/', 'survey-send'); await visit(page, '/surveys/reports/', 'survey-reports'); }); // ── 4. Organizations ──────────────────────────────────────────────────── test('Organizations: departments + staff + patients + hierarchy', async ({ page }) => { attachObservers(page, M, ADMIN); await login(page); await visit(page, '/organizations/departments/', 'org-departments'); await visit(page, '/organizations/staff/', 'org-staff'); await visit(page, '/organizations/patients/', 'org-patients'); await visit(page, '/organizations/staff/hierarchy/', 'org-hierarchy'); await visit(page, '/organizations/staff/hierarchy/d3/', 'org-hierarchy-d3'); await visit(page, '/organizations/manager-review-questions/', 'org-mgr-review-qs'); await visit(page, '/organizations/sections/', 'org-sections'); }); // ── 5. Notifications ──────────────────────────────────────────────────── test('Notifications: inbox + settings', async ({ page }) => { attachObservers(page, M, ADMIN); await login(page); await visit(page, '/notifications/inbox/', 'notif-inbox'); await visit(page, '/notifications/settings/', 'notif-settings'); }); // ── 6. Physicians ─────────────────────────────────────────────────────── test('Physicians: list + dashboard + leaderboard', async ({ page }) => { attachObservers(page, M, ADMIN); await login(page); await visit(page, '/physicians/', 'phys-list'); await visit(page, '/physicians/dashboard/', 'phys-dashboard'); await visit(page, '/physicians/leaderboard/', 'phys-leaderboard'); await visit(page, '/physicians/ratings/', 'phys-ratings'); }); // ── 7. Presentations ──────────────────────────────────────────────────── test('Presentations: list + create + templates', async ({ page }) => { attachObservers(page, M, ADMIN); await login(page); await visit(page, '/presentations/', 'pres-list'); await visit(page, '/presentations/templates/', 'pres-templates'); }); // ── 8. Executive ──────────────────────────────────────────────────────── test('Executive: dashboard + insights + QA', async ({ page }) => { attachObservers(page, M, ADMIN); await login(page); await visit(page, '/executive/', 'exec-dashboard'); await visit(page, '/executive/insights/', 'exec-insights'); await visit(page, '/executive/qa/', 'exec-qa'); }); // ── 9. Standards ──────────────────────────────────────────────────────── test('Standards: dashboard + categories + sources', async ({ page }) => { attachObservers(page, M, ADMIN); await login(page); await visit(page, '/standards/', 'std-dashboard'); await visit(page, '/standards/categories/', 'std-categories'); await visit(page, '/standards/sources/', 'std-sources'); await visit(page, '/standards/activity-types/', 'std-activity-types'); await visit(page, '/standards/search/', 'std-search'); }); // ── 10. References ────────────────────────────────────────────────────── test('References: dashboard + folders + search', async ({ page }) => { attachObservers(page, M, ADMIN); await login(page); await visit(page, '/references/', 'ref-dashboard'); await visit(page, '/references/search/', 'ref-search'); await visit(page, '/references/folders/new/', 'ref-folder-create'); }); // ── 11. Social ────────────────────────────────────────────────────────── test('Social: dashboard', async ({ page }) => { attachObservers(page, M, ADMIN); await login(page); await visit(page, '/social/', 'social-dashboard'); }); // ── 12. AI Engine ─────────────────────────────────────────────────────── test('AI Engine: sentiment list + dashboard', async ({ page }) => { attachObservers(page, M, ADMIN); await login(page); await visit(page, '/ai-engine/', 'ai-sentiment-list'); await visit(page, '/ai-engine/dashboard/', 'ai-dashboard'); }); // ── 13. Dashboard (command center + my dashboard) ─────────────────────── test('Dashboard: command center + my + performance', async ({ page }) => { attachObservers(page, M, ADMIN); await login(page); await visit(page, '/', 'dash-command-center'); await visit(page, '/my/', 'dash-my'); await visit(page, '/my/performance/', 'dash-performance'); await visit(page, '/admin-evaluation/', 'dash-admin-eval'); await visit(page, '/employee-evaluation/', 'dash-emp-eval'); }); // ── 14. Complaint settings + config ───────────────────────────────────── test('Complaint settings + config pages', async ({ page }) => { attachObservers(page, M, ADMIN); await login(page); await visit(page, '/complaints/analytics/', 'complaint-analytics'); await visit(page, '/complaints/settings/sla-management/', 'complaint-sla'); await visit(page, '/complaints/settings/escalation-rules/', 'complaint-escalation'); await visit(page, '/complaints/settings/thresholds/', 'complaint-thresholds'); await visit(page, '/complaints/trash/', 'complaint-trash'); await visit(page, '/complaints/oncall/', 'complaint-oncall'); await visit(page, '/complaints/templates/', 'complaint-templates'); await visit(page, '/config/', 'config-dashboard'); await visit(page, '/config/sla/', 'config-sla'); await visit(page, '/config/routing/', 'config-routing'); await visit(page, '/config/users/', 'config-users'); }); // ── 15. Callcenter + Census + Reports ─────────────────────────────────── test('Callcenter + Census + report pages', async ({ page }) => { attachObservers(page, M, ADMIN); await login(page); await visit(page, '/callcenter/records/import/', 'callcenter-import'); await visit(page, '/census/', 'census'); await visit(page, '/comments-report/', 'comments-report'); await visit(page, '/complaint-requests/', 'complaint-requests'); await visit(page, '/complaints-monthly/', 'complaints-monthly'); await visit(page, '/complaints-yearly/', 'complaints-yearly'); await visit(page, '/inquiries-report/', 'inquiries-report'); await visit(page, '/observations-report/', 'observations-report'); }); }); test.afterAll(async () => { const counts = OBS.reduce>((a, o) => ((a[o.status] = (a[o.status] || 0) + 1), a), {}); console.log('\n=========== COMPREHENSIVE AUDIT SUMMARY ==========='); console.log('Total observations:', OBS.length, JSON.stringify(counts)); console.log('===================================================\n'); });