# 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/inquiry-lifecycle.spec.ts >> Inquiry Lifecycle >> respond modal opens on inquiry detail - Location: e2e/tests/workflows/inquiry-lifecycle.spec.ts:135:7 # Error details ``` Error: locator.click: Error: strict mode violation: locator('button[onclick="showRespondModal()"]') resolved to 2 elements: 1) aka getByRole('button', { name: 'Respond' }) 2) aka getByRole('button', { name: 'Send Response' }) Call log: - waiting for locator('button[onclick="showRespondModal()"]') ``` # 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=e157]: - generic [ref=e158]: - generic [ref=e159]: - link "Inquiries" [ref=e160] [cursor=pointer]: - /url: /inquiries/ - img [ref=e161] - generic [ref=e163]: Detail - generic [ref=e164]: - heading "E2E automated test inquiry 1778178510420" [level=1] [ref=e165] - generic [ref=e166]: Open - generic [ref=e167]: Low - generic [ref=e168]: - generic [ref=e169]: - img [ref=e170] - text: INQ-20260507-2… | - img [ref=e173] - text: 2026-05-07 - button "Respond" [ref=e175] [cursor=pointer]: - img [ref=e176] - text: Respond - generic [ref=e178]: - generic [ref=e179]: - generic [ref=e180]: - generic [ref=e181]: - img [ref=e183] - heading "Inquiry Details" [level=5] [ref=e186] - generic [ref=e188]: - paragraph - paragraph [ref=e189]: E2E automated test inquiry - please ignore - paragraph - generic [ref=e190]: - generic [ref=e191]: - img [ref=e193] - heading "AI Analysis" [level=5] [ref=e196] - generic [ref=e197]: - generic [ref=e198]: - heading "AI Summary (English)" [level=4] [ref=e199] - paragraph [ref=e200]: This is an automated test inquiry. The sender has explicitly requested that the inquiry be ignored. Therefore, no further action is required. - generic [ref=e201]: - heading "AI Summary (Arabic)" [level=4] [ref=e202] - paragraph [ref=e203]: هذا استفسار اختبار آلي. طلب المرسل صراحةً تجاهل الاستفسار. لذلك، لا يلزم اتخاذ أي إجراء إضافي. - generic [ref=e204]: - generic [ref=e205]: - img [ref=e207] - heading "Timeline" [level=5] [ref=e211] - generic [ref=e213]: - generic [ref=e214]: - paragraph [ref=e215]: Inquiry Created - paragraph [ref=e216]: Created by E2E PX Admin - paragraph [ref=e217]: 2026-05-07 21:28 - generic [ref=e218]: - paragraph [ref=e219]: Note - paragraph [ref=e220]: AI analysis complete. Priority and summaries updated. - paragraph [ref=e221]: 2026-05-07 21:28 - generic [ref=e222]: - generic [ref=e223]: - generic [ref=e224]: - img [ref=e226] - heading "Actions" [level=5] [ref=e229] - generic [ref=e230]: - button "Send Response" [ref=e231] [cursor=pointer]: - img [ref=e232] - text: Send Response - button "Assign" [ref=e234] [cursor=pointer]: - img [ref=e235] - text: Assign - generic [ref=e238]: - generic [ref=e239]: - generic [ref=e240]: Update Status - combobox [ref=e241]: - option "Open" [selected] - option "In Progress" - option "Contacted" - option "Contacted, No Response" - option "Resolved" - option "Closed" - button "Change Status" [ref=e242] [cursor=pointer]: - img [ref=e243] - text: Change Status - link "Edit Inquiry" [ref=e248] [cursor=pointer]: - /url: /inquiries/110e0bc6-636b-4dc1-ae52-21b0be9f4748/edit/ - img [ref=e249] - text: Edit Inquiry - link "Initiate RCA" [ref=e252] [cursor=pointer]: - /url: /rca/create/?related_model=inquiry&related_id=110e0bc6-636b-4dc1-ae52-21b0be9f4748 - img [ref=e253] - text: Initiate RCA - link "Create QI Project" [ref=e256] [cursor=pointer]: - /url: /projects/create/?related_model=inquiry&related_id=110e0bc6-636b-4dc1-ae52-21b0be9f4748 - img [ref=e257] - text: Create QI Project - generic [ref=e259]: - paragraph [ref=e260]: Department Actions - button "Send to Department" [ref=e261] [cursor=pointer]: - img [ref=e262] - text: Send to Department - generic [ref=e265]: - generic [ref=e266]: - img [ref=e268] - heading "Contact Information" [level=5] [ref=e271] - generic [ref=e272]: - generic [ref=e273]: - generic [ref=e274]: Name - generic [ref=e275]: E2E Test Contact 1778178510420 - generic [ref=e276]: - generic [ref=e277]: Phone - generic [ref=e278]: "0500000001" - generic [ref=e279]: - generic [ref=e280]: Email - generic [ref=e281]: e2e-test-1778178510420@test.com - generic [ref=e282]: - heading "Status Timeline" [level=3] [ref=e283]: - img [ref=e284] - text: Status Timeline - generic [ref=e288]: - generic [ref=e290]: May 07, 2026 21:28 - generic [ref=e291]: Created - generic [ref=e292]: - generic [ref=e293]: - img [ref=e295] - heading "Organization" [level=5] [ref=e299] - generic [ref=e300]: - generic [ref=e301]: - generic [ref=e302]: Hospital - generic [ref=e303]: NUZHA - generic [ref=e304]: - generic [ref=e305]: Department - generic [ref=e306]: Information Technology - generic [ref=e307]: - generic [ref=e308]: Location - generic [ref=e309]: "-" - generic [ref=e310]: - generic [ref=e311]: Category - generic [ref=e312]: General Information - generic [ref=e313]: - generic [ref=e314]: SHCT Taxonomy - generic [ref=e315]: MANAGEMENT - generic [ref=e316]: - generic [ref=e317]: Priority - generic [ref=e318]: Low - generic [ref=e319]: - generic [ref=e320]: - img [ref=e322] - heading "Notes" [level=5] [ref=e325] - generic [ref=e327]: - generic [ref=e328]: - text: Staff Notes - textbox "Add staff notes..." [ref=e329] - generic [ref=e330]: - text: Supervisor Notes - textbox "Add supervisor notes..." [ref=e331] - button "Save Notes" [ref=e332] [cursor=pointer] - contentinfo [ref=e333]: - paragraph [ref=e334]: - text: Powered by - link "tenhal.sa" [ref=e335] [cursor=pointer]: - /url: https://tenhal.sa ``` # Test source ```ts 61 | await auth.login('hospital_admin'); 62 | 63 | await page.goto('/inquiries/'); 64 | await page.waitForLoadState('domcontentloaded'); 65 | await page.waitForTimeout(2000); 66 | 67 | if (inquiryReference) { 68 | const searchInput = page.locator('input[name="search"]'); 69 | if (await searchInput.count() > 0) { 70 | await searchInput.fill(inquiryReference); 71 | await searchInput.press('Enter'); 72 | await page.waitForLoadState('domcontentloaded'); 73 | await page.waitForTimeout(1000); 74 | } 75 | 76 | const tableText = await page.locator('table').textContent(); 77 | expect(tableText).toContain(inquiryReference); 78 | } else { 79 | const tableText = await page.locator('table').textContent(); 80 | expect(tableText).toBeTruthy(); 81 | } 82 | }); 83 | 84 | test('inquiry list has filter and table', async ({ page }) => { 85 | const auth = new RoleAuthHelper(page); 86 | await auth.login('hospital_admin'); 87 | 88 | await page.goto('/inquiries/'); 89 | await page.waitForLoadState('domcontentloaded'); 90 | await page.waitForTimeout(2000); 91 | 92 | const table = page.locator('table.data-table, table'); 93 | expect(await table.count()).toBeGreaterThan(0); 94 | 95 | const filterForm = page.locator('form[method="get"]'); 96 | expect(await filterForm.count()).toBeGreaterThan(0); 97 | }); 98 | 99 | test('can access inquiry create form (authenticated)', async ({ page }) => { 100 | const auth = new RoleAuthHelper(page); 101 | await auth.login('hospital_admin'); 102 | 103 | await page.goto('/inquiries/new/'); 104 | await page.waitForLoadState('domcontentloaded'); 105 | await page.waitForTimeout(2000); 106 | 107 | const form = page.locator('#inquiryForm, form[action*="inquiry_create"]'); 108 | const hasForm = await form.count().then(c => c > 0); 109 | expect(hasForm).toBeTruthy(); 110 | }); 111 | 112 | test('inquiry detail page loads for open inquiry', async ({ page }) => { 113 | const auth = new RoleAuthHelper(page); 114 | await auth.login('hospital_admin'); 115 | 116 | await page.goto('/inquiries/?status=open'); 117 | await page.waitForLoadState('domcontentloaded'); 118 | await page.waitForTimeout(2000); 119 | 120 | const firstRow = page.locator('table tbody tr').first(); 121 | const hasRows = await firstRow.count().then(c => c > 0); 122 | if (!hasRows) { 123 | test.skip(); 124 | return; 125 | } 126 | 127 | await firstRow.click(); 128 | await page.waitForLoadState('domcontentloaded'); 129 | await page.waitForTimeout(1000); 130 | 131 | const pageText = await page.textContent('body'); 132 | expect(pageText).toContain('INQ-'); 133 | }); 134 | 135 | test('respond modal opens on inquiry detail', async ({ page }) => { 136 | const auth = new RoleAuthHelper(page); 137 | await auth.login('hospital_admin'); 138 | 139 | await page.goto('/inquiries/?status=open'); 140 | await page.waitForLoadState('domcontentloaded'); 141 | await page.waitForTimeout(2000); 142 | 143 | const firstRow = page.locator('table tbody tr').first(); 144 | const hasRows = await firstRow.count().then(c => c > 0); 145 | if (!hasRows) { 146 | test.skip(); 147 | return; 148 | } 149 | 150 | await firstRow.click(); 151 | await page.waitForLoadState('domcontentloaded'); 152 | await page.waitForTimeout(1000); 153 | 154 | const respondBtn = page.locator('button[onclick="showRespondModal()"]'); 155 | const hasRespond = await respondBtn.count().then(c => c > 0); 156 | if (!hasRespond) { 157 | test.skip(); 158 | return; 159 | } 160 | > 161 | await respondBtn.click(); | ^ Error: locator.click: Error: strict mode violation: locator('button[onclick="showRespondModal()"]') resolved to 2 elements: 162 | const modal = page.locator('#respondModal'); 163 | await modal.waitFor({ state: 'visible', timeout: 5000 }); 164 | 165 | const form = modal.locator('form#respondForm, form[action*="respond"]'); 166 | expect(await form.count()).toBeGreaterThan(0); 167 | 168 | const closeBtn = modal.locator('button[onclick="closeRespondModal()"]'); 169 | if (await closeBtn.count() > 0) { 170 | await closeBtn.click(); 171 | } 172 | }); 173 | 174 | test('inquiry list shows status badges', async ({ page }) => { 175 | const auth = new RoleAuthHelper(page); 176 | await auth.login('hospital_admin'); 177 | 178 | await page.goto('/inquiries/'); 179 | await page.waitForLoadState('domcontentloaded'); 180 | await page.waitForTimeout(2000); 181 | 182 | const statusBadges = page.locator('span.rounded-full'); 183 | const badgeCount = await statusBadges.count(); 184 | expect(badgeCount).toBeGreaterThan(0); 185 | }); 186 | }); 187 | ```