import { test, expect } from '@playwright/test'; import { RoleAuthHelper } from '../../helpers/helpers'; import { ApiHelper } from '../../helpers/api-helper'; test.describe('RCA Workflow', () => { test.describe.configure({ mode: 'serial' }); let rcaId: string | null = null; test('RCA list page loads', async ({ page }) => { const auth = new RoleAuthHelper(page); await auth.login('hospital_admin'); await page.goto('/rca/'); await page.waitForLoadState('domcontentloaded'); const bodyText = await page.textContent('body'); expect(bodyText).toContain('Root Cause Analysis'); }); test('create RCA', async ({ page }) => { const auth = new RoleAuthHelper(page); await auth.login('hospital_admin'); await page.goto('/rca/create/'); await page.waitForLoadState('domcontentloaded'); await page.waitForTimeout(1000); const titleInput = page.locator('#id_title'); if (!(await titleInput.isVisible().catch(() => false))) { test.skip(); return; } const rcaTitle = `E2E RCA Test ${Date.now()}`; await page.fill('#id_title', rcaTitle); await page.fill('#id_description', 'Test RCA description for E2E workflow testing'); await page.fill('#id_background', 'Background info for test'); await page.fill('#id_root_cause_summary', 'Initial root cause summary'); await page.selectOption('#id_severity', 'high'); await page.selectOption('#id_priority', 'medium'); await page.click('button[type="submit"]'); await page.waitForLoadState('domcontentloaded'); expect(page.url()).toMatch(/\/rca\/[0-9a-f-]+\//); const urlParts = page.url().split('/'); rcaId = urlParts[urlParts.length - 2] || urlParts[urlParts.length - 1].replace('/', ''); const bodyText = await page.textContent('body'); expect(bodyText).toContain(rcaTitle); }); test('add root cause', async ({ page }) => { const auth = new RoleAuthHelper(page); await auth.login('hospital_admin'); await page.goto('/rca/'); await page.waitForLoadState('domcontentloaded'); const listBody = await page.textContent('body'); if (listBody.includes('No Root Cause Analyses')) { test.skip(); return; } const firstLink = page.locator('a[href*="/rca/"]').first(); if (!(await firstLink.isVisible())) { test.skip(); return; } await firstLink.click(); await page.waitForLoadState('domcontentloaded'); const modalBtn = page.locator('button[data-bs-target="#rootCauseModal"]'); if (!(await modalBtn.isVisible().catch(() => false))) { test.skip(); return; } await modalBtn.click(); await page.waitForSelector('#rootCauseModal.show', { timeout: 5000 }).catch(() => {}); await page.waitForTimeout(500); await page.fill('#rootCauseModal textarea[name="description"]', 'E2E test root cause: process gap identified'); await page.selectOption('#rootCauseModal select[name="category"]', 'process'); await page.fill('#rootCauseModal input[name="likelihood"]', '3'); await page.fill('#rootCauseModal input[name="impact"]', '4'); await page.click('#rootCauseModal button[type="submit"]'); await page.waitForLoadState('domcontentloaded'); const bodyText = await page.textContent('body'); expect(bodyText).toContain('process gap identified'); }); test('add corrective action', async ({ page }) => { const auth = new RoleAuthHelper(page); await auth.login('hospital_admin'); await page.goto('/rca/'); await page.waitForLoadState('domcontentloaded'); const listBody = await page.textContent('body'); if (listBody.includes('No Root Cause Analyses')) { test.skip(); return; } const firstLink = page.locator('a[href*="/rca/"]').first(); if (!(await firstLink.isVisible())) { test.skip(); return; } await firstLink.click(); await page.waitForLoadState('domcontentloaded'); const modalBtn = page.locator('button[data-bs-target="#actionModal"]'); if (!(await modalBtn.isVisible().catch(() => false))) { test.skip(); return; } await modalBtn.click(); await page.waitForSelector('#actionModal.show', { timeout: 5000 }).catch(() => {}); await page.waitForTimeout(500); await page.fill('#actionModal textarea[name="description"]', 'E2E corrective action: update SOP'); await page.selectOption('#actionModal select[name="action_type"]', 'corrective'); await page.selectOption('#actionModal select[name="status"]', 'not_started'); await page.click('#actionModal button[type="submit"]'); await page.waitForLoadState('domcontentloaded'); const bodyText = await page.textContent('body'); expect(bodyText).toContain('update SOP'); }); test('status change DRAFT to IN_PROGRESS', async ({ page }) => { const auth = new RoleAuthHelper(page); await auth.login('hospital_admin'); await page.goto('/rca/'); await page.waitForLoadState('domcontentloaded'); const listBody = await page.textContent('body'); if (listBody.includes('No Root Cause Analyses')) { test.skip(); return; } const firstLink = page.locator('a[href*="/rca/"]').first(); if (!(await firstLink.isVisible())) { test.skip(); return; } await firstLink.click(); await page.waitForLoadState('domcontentloaded'); const statusSelect = page.locator('#statusChangeForm select[name="new_status"]'); if (!(await statusSelect.isVisible().catch(() => false))) { test.skip(); return; } await statusSelect.selectOption('in_progress'); await page.click('#statusChangeForm button[type="submit"]'); await page.waitForLoadState('domcontentloaded'); const bodyText = await page.textContent('body'); expect(bodyText).toContain('In Progress'); }); test('cross-hospital RCA isolation via API', async ({ page }) => { const api = new ApiHelper(page); await api.authenticate('hospital_admin'); const resp = await api.get('/api/v1/complaints/'); expect([200, 404]).toContain(resp.status()); }); test('unauthenticated user cannot access RCA', async ({ page }) => { await page.goto('/rca/'); await page.waitForLoadState('domcontentloaded'); expect(page.url()).toContain('/accounts/login/'); }); test('source user cannot access RCA', async ({ page }) => { const auth = new RoleAuthHelper(page); await auth.login('source_user'); await page.goto('/rca/'); await page.waitForLoadState('domcontentloaded'); expect(page.url()).not.toContain('/rca/'); }); });