# Instructions - Following Playwright test failed. - Explain why, be concise, respect Playwright best practices. - Provide a snippet of code with the fix, if possible. # Test info - Name: workflows/rca-lifecycle.spec.ts >> RCA Workflow >> create RCA - Location: e2e/tests/workflows/rca-lifecycle.spec.ts:21:7 # Error details ``` Test timeout of 60000ms exceeded. ``` ``` Error: page.click: Test timeout of 60000ms exceeded. Call log: - waiting for locator('button[type="submit"]') - locator resolved to 2 elements. Proceeding with the first one: - attempting click action 2 × waiting for element to be visible, enabled and stable - element is not visible - retrying click action - waiting 20ms 2 × waiting for element to be visible, enabled and stable - element is not visible - retrying click action - waiting 100ms 104 × waiting for element to be visible, enabled and stable - element is not visible - retrying click action - waiting 500ms ``` # Page snapshot ```yaml - generic [ref=e2]: - complementary [ref=e3]: - generic [ref=e4]: - img "Al Hammadi" [ref=e6] - img "Al Hammadi" [ref=e8] - navigation [ref=e9]: - link [ref=e10] [cursor=pointer]: - /url: /analytics/dashboard/ - img [ref=e11] - link [ref=e16] [cursor=pointer]: - /url: / - img [ref=e17] - button [ref=e20] [cursor=pointer]: - img [ref=e21] - link [ref=e22] [cursor=pointer]: - /url: /complaints/ - img [ref=e23] - link [ref=e26] [cursor=pointer]: - /url: /inquiries/ - img [ref=e27] - link [ref=e30] [cursor=pointer]: - /url: /observations/ - img [ref=e31] - button [ref=e35] [cursor=pointer]: - img [ref=e36] - link [ref=e40] [cursor=pointer]: - /url: /appreciation/ - img [ref=e41] - link [ref=e43] [cursor=pointer]: - /url: /suggestions/?feedback_type=suggestion - img [ref=e44] - button [ref=e47] [cursor=pointer]: - img [ref=e48] - button [ref=e52] [cursor=pointer]: - img [ref=e53] - link [ref=e58] [cursor=pointer]: - /url: /organizations/departments/ - img [ref=e59] - link [ref=e63] [cursor=pointer]: - /url: /organizations/patients/ - img [ref=e64] - button [ref=e68] [cursor=pointer]: - img [ref=e69] - button [ref=e74] [cursor=pointer]: - img [ref=e75] - button [ref=e82] [cursor=pointer]: - img [ref=e83] - link [ref=e86] [cursor=pointer]: - /url: /notifications/send-sms/ - img [ref=e87] - link [ref=e89] [cursor=pointer]: - /url: /config/ - img [ref=e90] - link [ref=e93] [cursor=pointer]: - /url: /config/deleted/ - img [ref=e94] - link [ref=e97] [cursor=pointer]: - /url: /accounts/acknowledgements/my-acknowledgements/ - img [ref=e98] - button [ref=e104] [cursor=pointer]: - img [ref=e105] - button [ref=e108] [cursor=pointer]: - img [ref=e109] - button [ref=e114] [cursor=pointer]: - img [ref=e115] - generic [ref=e118]: - link "🇬🇧" [ref=e119] [cursor=pointer]: - /url: /core/set-language/?language=en - generic [ref=e120]: 🇬🇧 - link "🇸🇦" [ref=e121] [cursor=pointer]: - /url: /core/set-language/?language=ar - generic [ref=e122]: 🇸🇦 - generic [ref=e123]: - banner [ref=e124]: - generic [ref=e125]: - heading "Good morning, E2E! ☀️" [level=2] [ref=e126] - paragraph [ref=e127]: Welcome to PX360 Patient Experience Management - generic [ref=e128]: - generic [ref=e129]: - img [ref=e130] - textbox "Search..." [ref=e133] - button "10" [ref=e135] [cursor=pointer]: - img [ref=e136] - generic [ref=e139]: "10" - generic [ref=e140]: - link "🇬🇧 English" [ref=e141] [cursor=pointer]: - /url: /core/set-language/?language=en - generic [ref=e142]: 🇬🇧 - generic [ref=e143]: English - link "🇸🇦 Arabic" [ref=e144] [cursor=pointer]: - /url: /core/set-language/?language=ar - generic [ref=e145]: 🇸🇦 - generic [ref=e146]: Arabic - button "E2E Hospital Admin Hospital Admin E" [ref=e148] [cursor=pointer]: - generic [ref=e149]: - generic [ref=e150]: E2E Hospital Admin - generic [ref=e151]: Hospital Admin - generic [ref=e152]: E - img [ref=e153] - main [ref=e155]: - generic [ref=e156]: - generic [ref=e157]: - link "RCA" [ref=e158] [cursor=pointer]: - /url: /rca/ - img [ref=e159] - generic [ref=e161]: New RCA - heading "New Root Cause Analysis" [level=1] [ref=e162]: - img [ref=e164] - text: New Root Cause Analysis - generic [ref=e169]: - generic [ref=e170]: - generic [ref=e171]: - generic [ref=e172]: Title * - textbox "Title *" [ref=e173]: E2E RCA Test 1778178899576 - generic [ref=e174]: - generic [ref=e175]: Description * - textbox "Description *" [ref=e176]: Test RCA description for E2E workflow testing - generic [ref=e177]: - text: Background - textbox "Background" [ref=e178]: Background info for test - generic [ref=e179]: - text: Root Cause Summary - textbox "Root Cause Summary" [active] [ref=e180]: Initial root cause summary - generic [ref=e181]: - generic [ref=e182]: - text: Department - combobox "Department" [ref=e183]: - option "---------" [selected] - option "Academic Education and Training Affairs" - option "Accidents & Emergency" - option "Anesthesia & OR Department" - option "Business Development" - option "Community Engagement" - option "Contact Center Department" - option "Continuous Medical Education Managment" - option "Corporate Administration" - option "Corporate Communication Department" - option "Critical Care Department" - option "Dental Department" - option "Dermatology Department" - option "Emergency Department" - option "Executive Administration" - option "FAMILY MEDICINE DEPARTMENT" - option "Facility Management & Maintenance" - option "Finance Department" - option "Financial Collection & Claims Department" - option "Food Services Department" - option "Housekeeping & Hospitality Department" - option "Human Resource" - option "Infection Control" - option "Information Technology" - option "Innovation Communication Management" - option "Inpatient Department" - option "Internal Audit" - option "Internal Medicine" - option "Laboratory and Blood Bank" - option "Laundry Department" - option "Legal Affairs Department" - option "Marketing Department" - option "Medical Administration" - option "Medical Ancillary Services" - option "Medical Approvals Department" - option "Medical Records Department" - option "Nursing Department" - option "OB/Gyne Department" - option "ONCOLOGY" - option "Ophthalmology Department" - option "Outpatient Department" - option "Patient Affairs Department" - option "Patient Relations & Patient Experience Department" - option "Pediatric Department" - option "Pharmacy Department" - option "Pharmacy Warehouse AlAziziyah" - option "Porter Department" - option "Radiology Department" - option "Security Department" - option "Senior Management Offices" - option "Supply Chain" - option "Support Services" - option "Surgeries Department" - option "TRANSFORMATION AND CHANGE MANAGEMENT" - option "Talent Acquisition Department" - option "Transportation Department" - generic [ref=e184]: - text: Status - combobox "Status" [ref=e185]: - option "Draft" [selected] - option "In Progress" - option "Under Review" - option "Approved" - option "Closed" - generic [ref=e186]: - text: Severity - combobox "Severity" [ref=e187]: - option "Low" - option "Medium" - option "High" [selected] - option "Critical" - generic [ref=e188]: - text: Priority - combobox "Priority" [ref=e189]: - option "Low" - option "Medium" [selected] - option "High" - option "Critical" - generic [ref=e190]: - text: Assigned To - combobox "Assigned To" [ref=e191]: - option "---------" [selected] - option "IBRAHIM ABDELAZEEZ I ALSHUWAIER (IBRAHIM.ABDELAZEEZ@gmail.com)" - option "TURKI ABDULAZIZ M ALKHAMIS (TURKI@hh.med.sa)" - option "ZEENATH ABBONU KUNHIBI (ZEENATH@hh.med.sa)" - option "ABEER MOHAMMED DAWII ALGHAMDI (abber@hh.med.sa)" - option "ابرار الشمري (brr.lshmry@alhammadi.med.sa)" - option "E2E Champion (e2e-champion@px360.test)" - option "E2E Dept Manager (e2e-dept-manager@px360.test)" - option "E2E Hospital Admin (e2e-hospital-admin@px360.test)" - option "E2E PX Admin (e2e-px-admin@px360.test)" - option "E2E PX Employee (e2e-px-employee@px360.test)" - option "E2E Source User (e2e-source-user@px360.test)" - option "E2E Staff (e2e-staff@px360.test)" - option "E2E Viewer (e2e-viewer@px360.test)" - option "هيا الرويلي (hy.lrwyly@alhammadi.med.sa)" - option "ismail mosa (ismail@tenhal.sa)" - option "مها الحنيظل (mh.lhnyzl@alhammadi.med.sa)" - option "امال القحطاني (ml.lqhtny@alhammadi.med.sa)" - option "منتهى الزغيبي (mnth.lzgyby@alhammadi.med.sa)" - option "مرام القحطاني (mrm.lqhtny@alhammadi.med.sa)" - option "مي سليمان الدخيل (my.ldkhyl@alhammadi.med.sa)" - option "PX Admin (pxadmin@dev.local)" - option "رهف علي العنزي (rhf.lnzy@alhammadi.med.sa)" - option "SHAHAD MOSLEH K ALANAZI (sh@gmail.com)" - option "اشواق الحربي (shwq.lhrby@alhammadi.med.sa)" - option "أثير القحطاني (thyr.lqhtny@alhammadi.med.sa)" - generic [ref=e192]: - text: Target Completion - textbox "Target Completion" [ref=e193] - generic [ref=e194]: - button "Save" [ref=e195] [cursor=pointer]: - img [ref=e196] - text: Save - link "Cancel" [ref=e200] [cursor=pointer]: - /url: /rca/ - contentinfo [ref=e201]: - paragraph [ref=e202]: - text: Powered by - link "tenhal.sa" [ref=e203] [cursor=pointer]: - /url: https://tenhal.sa ``` # Test source ```ts 1 | import { test, expect } from '@playwright/test'; 2 | import { RoleAuthHelper } from '../../helpers/helpers'; 3 | import { ApiHelper } from '../../helpers/api-helper'; 4 | 5 | test.describe('RCA Workflow', () => { 6 | test.describe.configure({ mode: 'serial' }); 7 | 8 | let rcaId: string | null = null; 9 | 10 | test('RCA list page loads', async ({ page }) => { 11 | const auth = new RoleAuthHelper(page); 12 | await auth.login('hospital_admin'); 13 | 14 | await page.goto('/rca/'); 15 | await page.waitForLoadState('domcontentloaded'); 16 | 17 | const bodyText = await page.textContent('body'); 18 | expect(bodyText).toContain('Root Cause Analysis'); 19 | }); 20 | 21 | test('create RCA', async ({ page }) => { 22 | const auth = new RoleAuthHelper(page); 23 | await auth.login('hospital_admin'); 24 | 25 | await page.goto('/rca/create/'); 26 | await page.waitForLoadState('domcontentloaded'); 27 | await page.waitForTimeout(1000); 28 | 29 | const titleInput = page.locator('#id_title'); 30 | if (!(await titleInput.isVisible().catch(() => false))) { 31 | test.skip(); 32 | return; 33 | } 34 | 35 | const rcaTitle = `E2E RCA Test ${Date.now()}`; 36 | await page.fill('#id_title', rcaTitle); 37 | await page.fill('#id_description', 'Test RCA description for E2E workflow testing'); 38 | await page.fill('#id_background', 'Background info for test'); 39 | await page.fill('#id_root_cause_summary', 'Initial root cause summary'); 40 | await page.selectOption('#id_severity', 'high'); 41 | await page.selectOption('#id_priority', 'medium'); > 42 | await page.click('button[type="submit"]'); | ^ Error: page.click: Test timeout of 60000ms exceeded. 43 | 44 | await page.waitForLoadState('domcontentloaded'); 45 | expect(page.url()).toMatch(/\/rca\/[0-9a-f-]+\//); 46 | 47 | const urlParts = page.url().split('/'); 48 | rcaId = urlParts[urlParts.length - 2] || urlParts[urlParts.length - 1].replace('/', ''); 49 | 50 | const bodyText = await page.textContent('body'); 51 | expect(bodyText).toContain(rcaTitle); 52 | }); 53 | 54 | test('add root cause', async ({ page }) => { 55 | const auth = new RoleAuthHelper(page); 56 | await auth.login('hospital_admin'); 57 | 58 | await page.goto('/rca/'); 59 | await page.waitForLoadState('domcontentloaded'); 60 | 61 | const listBody = await page.textContent('body'); 62 | if (listBody.includes('No Root Cause Analyses')) { 63 | test.skip(); 64 | return; 65 | } 66 | 67 | const firstLink = page.locator('a[href*="/rca/"]').first(); 68 | if (!(await firstLink.isVisible())) { 69 | test.skip(); 70 | return; 71 | } 72 | await firstLink.click(); 73 | await page.waitForLoadState('domcontentloaded'); 74 | 75 | const modalBtn = page.locator('button[data-bs-target="#rootCauseModal"]'); 76 | if (!(await modalBtn.isVisible().catch(() => false))) { 77 | test.skip(); 78 | return; 79 | } 80 | 81 | await modalBtn.click(); 82 | await page.waitForSelector('#rootCauseModal.show', { timeout: 5000 }).catch(() => {}); 83 | await page.waitForTimeout(500); 84 | 85 | await page.fill('#rootCauseModal textarea[name="description"]', 'E2E test root cause: process gap identified'); 86 | await page.selectOption('#rootCauseModal select[name="category"]', 'process'); 87 | await page.fill('#rootCauseModal input[name="likelihood"]', '3'); 88 | await page.fill('#rootCauseModal input[name="impact"]', '4'); 89 | await page.click('#rootCauseModal button[type="submit"]'); 90 | 91 | await page.waitForLoadState('domcontentloaded'); 92 | const bodyText = await page.textContent('body'); 93 | expect(bodyText).toContain('process gap identified'); 94 | }); 95 | 96 | test('add corrective action', async ({ page }) => { 97 | const auth = new RoleAuthHelper(page); 98 | await auth.login('hospital_admin'); 99 | 100 | await page.goto('/rca/'); 101 | await page.waitForLoadState('domcontentloaded'); 102 | 103 | const listBody = await page.textContent('body'); 104 | if (listBody.includes('No Root Cause Analyses')) { 105 | test.skip(); 106 | return; 107 | } 108 | 109 | const firstLink = page.locator('a[href*="/rca/"]').first(); 110 | if (!(await firstLink.isVisible())) { 111 | test.skip(); 112 | return; 113 | } 114 | await firstLink.click(); 115 | await page.waitForLoadState('domcontentloaded'); 116 | 117 | const modalBtn = page.locator('button[data-bs-target="#actionModal"]'); 118 | if (!(await modalBtn.isVisible().catch(() => false))) { 119 | test.skip(); 120 | return; 121 | } 122 | 123 | await modalBtn.click(); 124 | await page.waitForSelector('#actionModal.show', { timeout: 5000 }).catch(() => {}); 125 | await page.waitForTimeout(500); 126 | 127 | await page.fill('#actionModal textarea[name="description"]', 'E2E corrective action: update SOP'); 128 | await page.selectOption('#actionModal select[name="action_type"]', 'corrective'); 129 | await page.selectOption('#actionModal select[name="status"]', 'not_started'); 130 | await page.click('#actionModal button[type="submit"]'); 131 | 132 | await page.waitForLoadState('domcontentloaded'); 133 | const bodyText = await page.textContent('body'); 134 | expect(bodyText).toContain('update SOP'); 135 | }); 136 | 137 | test('status change DRAFT to IN_PROGRESS', async ({ page }) => { 138 | const auth = new RoleAuthHelper(page); 139 | await auth.login('hospital_admin'); 140 | 141 | await page.goto('/rca/'); 142 | await page.waitForLoadState('domcontentloaded'); ```