HH/e2e/tests/workflows/rca-lifecycle.spec.ts
2026-04-08 17:13:35 +03:00

195 lines
6.5 KiB
TypeScript

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/');
});
});