203 lines
6.6 KiB
Markdown
203 lines
6.6 KiB
Markdown
# 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/complaint-lifecycle.spec.ts >> Complaint Lifecycle >> activate (self-assign) open complaint changes status to in_progress
|
|
- Location: e2e/tests/workflows/complaint-lifecycle.spec.ts:96:7
|
|
|
|
# Error details
|
|
|
|
```
|
|
TypeError: Cannot read properties of undefined (reading 'email')
|
|
```
|
|
|
|
# Page snapshot
|
|
|
|
```yaml
|
|
- generic [ref=e3]:
|
|
- generic [ref=e4]:
|
|
- img "HH Logo" [ref=e6]
|
|
- heading "Welcome to PX360" [level=1] [ref=e7]
|
|
- paragraph [ref=e8]: Patient Experience Management System
|
|
- generic [ref=e10]:
|
|
- generic [ref=e11]:
|
|
- generic [ref=e12]:
|
|
- img [ref=e13]
|
|
- text: Email Address
|
|
- generic [ref=e16]:
|
|
- img [ref=e17]
|
|
- textbox "Email Address" [active] [ref=e20]:
|
|
- /placeholder: Enter your email
|
|
- generic [ref=e21]:
|
|
- generic [ref=e22]:
|
|
- img [ref=e23]
|
|
- text: Password
|
|
- generic [ref=e26]:
|
|
- img [ref=e27]
|
|
- textbox "Password" [ref=e31]:
|
|
- /placeholder: Enter your password
|
|
- button [ref=e32] [cursor=pointer]:
|
|
- img [ref=e33]
|
|
- generic [ref=e36]:
|
|
- generic [ref=e37] [cursor=pointer]:
|
|
- checkbox "Remember me" [ref=e38]
|
|
- generic [ref=e39]: Remember me
|
|
- link "Forgot password?" [ref=e40] [cursor=pointer]:
|
|
- /url: /accounts/password/reset/
|
|
- button "Sign In" [ref=e41] [cursor=pointer]:
|
|
- img [ref=e42]
|
|
- text: Sign In
|
|
- generic [ref=e45]:
|
|
- paragraph [ref=e46]:
|
|
- text: Secure login powered by
|
|
- link "tenhal.sa" [ref=e47] [cursor=pointer]:
|
|
- /url: https://tenhal.sa
|
|
- paragraph [ref=e48]: © 2026 Al Hammadi Hospital
|
|
```
|
|
|
|
# Test source
|
|
|
|
```ts
|
|
150 | export const ROLES: Record<RoleName, RoleConfig> = {
|
|
151 | px_admin: {
|
|
152 | email: 'e2e-px-admin@px360.test',
|
|
153 | password: E2E_PASSWORD,
|
|
154 | groupName: 'PX Admin',
|
|
155 | hasHospital: false,
|
|
156 | canAccessConfig: true,
|
|
157 | canAccessAdmin: false,
|
|
158 | isSourceUser: false,
|
|
159 | },
|
|
160 | hospital_admin: {
|
|
161 | email: 'e2e-hospital-admin@px360.test',
|
|
162 | password: E2E_PASSWORD,
|
|
163 | groupName: 'Hospital Admin',
|
|
164 | hasHospital: true,
|
|
165 | canAccessConfig: false,
|
|
166 | canAccessAdmin: false,
|
|
167 | isSourceUser: false,
|
|
168 | },
|
|
169 | dept_manager: {
|
|
170 | email: 'e2e-dept-manager@px360.test',
|
|
171 | password: E2E_PASSWORD,
|
|
172 | groupName: 'Department Manager',
|
|
173 | hasHospital: true,
|
|
174 | canAccessConfig: false,
|
|
175 | canAccessAdmin: false,
|
|
176 | isSourceUser: false,
|
|
177 | },
|
|
178 | px_employee: {
|
|
179 | email: 'e2e-px-employee@px360.test',
|
|
180 | password: E2E_PASSWORD,
|
|
181 | groupName: 'PX Employee',
|
|
182 | hasHospital: true,
|
|
183 | canAccessConfig: false,
|
|
184 | canAccessAdmin: false,
|
|
185 | isSourceUser: false,
|
|
186 | },
|
|
187 | physician: {
|
|
188 | email: 'e2e-physician@px360.test',
|
|
189 | password: E2E_PASSWORD,
|
|
190 | groupName: 'Physician',
|
|
191 | hasHospital: true,
|
|
192 | canAccessConfig: false,
|
|
193 | canAccessAdmin: false,
|
|
194 | isSourceUser: false,
|
|
195 | },
|
|
196 | nurse: {
|
|
197 | email: 'e2e-nurse@px360.test',
|
|
198 | password: E2E_PASSWORD,
|
|
199 | groupName: 'Nurse',
|
|
200 | hasHospital: true,
|
|
201 | canAccessConfig: false,
|
|
202 | canAccessAdmin: false,
|
|
203 | isSourceUser: false,
|
|
204 | },
|
|
205 | staff: {
|
|
206 | email: 'e2e-staff@px360.test',
|
|
207 | password: E2E_PASSWORD,
|
|
208 | groupName: 'Staff',
|
|
209 | hasHospital: true,
|
|
210 | canAccessConfig: false,
|
|
211 | canAccessAdmin: false,
|
|
212 | isSourceUser: false,
|
|
213 | },
|
|
214 | viewer: {
|
|
215 | email: 'e2e-viewer@px360.test',
|
|
216 | password: E2E_PASSWORD,
|
|
217 | groupName: 'Viewer',
|
|
218 | hasHospital: true,
|
|
219 | canAccessConfig: false,
|
|
220 | canAccessAdmin: false,
|
|
221 | isSourceUser: false,
|
|
222 | },
|
|
223 | source_user: {
|
|
224 | email: 'e2e-source-user@px360.test',
|
|
225 | password: E2E_PASSWORD,
|
|
226 | groupName: 'PX Source User',
|
|
227 | hasHospital: true,
|
|
228 | canAccessConfig: false,
|
|
229 | canAccessAdmin: false,
|
|
230 | isSourceUser: true,
|
|
231 | },
|
|
232 | champion: {
|
|
233 | email: 'e2e-champion@px360.test',
|
|
234 | password: E2E_PASSWORD,
|
|
235 | groupName: 'Champion',
|
|
236 | hasHospital: true,
|
|
237 | canAccessConfig: false,
|
|
238 | canAccessAdmin: false,
|
|
239 | isSourceUser: false,
|
|
240 | },
|
|
241 | };
|
|
242 |
|
|
243 | export class RoleAuthHelper {
|
|
244 | constructor(private page: Page) {}
|
|
245 |
|
|
246 | async login(role: RoleName) {
|
|
247 | const config = ROLES[role];
|
|
248 | await this.page.goto('/accounts/login/');
|
|
249 | await this.page.waitForSelector('#email');
|
|
> 250 | await this.page.fill('#email', config.email);
|
|
| ^ TypeError: Cannot read properties of undefined (reading 'email')
|
|
251 | await this.page.fill('#password', config.password);
|
|
252 | await this.page.click('button[type="submit"]');
|
|
253 | await this.page.waitForURL(/\/(?!accounts\/login)/, { timeout: 15000 });
|
|
254 | await this.page.waitForLoadState('domcontentloaded');
|
|
255 | }
|
|
256 |
|
|
257 | async loginAs(role: RoleName) {
|
|
258 | return this.login(role);
|
|
259 | }
|
|
260 |
|
|
261 | async logout() {
|
|
262 | await this.page.goto('/accounts/logout/');
|
|
263 | await this.page.waitForURL(/\/accounts\/login\/?/, { timeout: 10000 });
|
|
264 | }
|
|
265 |
|
|
266 | static config(role: RoleName): RoleConfig {
|
|
267 | return ROLES[role];
|
|
268 | }
|
|
269 | }
|
|
270 |
|
|
271 | export async function submitContentForm(page: Page) {
|
|
272 | await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
|
|
273 | await page.waitForTimeout(800);
|
|
274 | const formSelector = 'form:not([action*="logout"]):not([action*="login"])';
|
|
275 | const formEl = page.locator(formSelector).first();
|
|
276 | const count = await formEl.count();
|
|
277 | if (count === 0) {
|
|
278 | const fallback = page.locator('form').last();
|
|
279 | await fallback.evaluate((f: HTMLFormElement) => f.submit());
|
|
280 | } else {
|
|
281 | await formEl.evaluate((f: HTMLFormElement) => f.submit());
|
|
282 | }
|
|
283 | await page.waitForLoadState('domcontentloaded');
|
|
284 | await page.waitForTimeout(3000);
|
|
285 | }
|
|
286 |
|
|
``` |