@@ -287,6 +287,95 @@ const errorNoty = page.locator('shade-noty').first()
287287await expect (errorNoty ).toBeVisible ()
288288```
289289
290+ ### User Journey Test Pattern
291+
292+ E2E tests should follow user journeys, not component isolation. Each test should simulate a complete user workflow from start to finish.
293+
294+ ** Structure:**
295+
296+ - One test per complete user workflow
297+ - Test from login to logical endpoint
298+ - Clean up any created/modified data at the end
299+ - Use helper functions for reusable steps within the test file
300+
301+ ** Good Example - User Journey:**
302+
303+ ``` typescript
304+ test (' Admin can navigate to users, edit roles, and verify persistence' , async ({ page }) => {
305+ // 1. Login as admin
306+ await login (page )
307+
308+ // 2. Navigate to app settings, verify Users menu
309+ await navigateToAppSettings (page )
310+ await expect (page .getByText (' Users' )).toBeVisible ()
311+
312+ // 3. Click Users, verify table structure
313+ await page .getByText (' Users' ).click ()
314+ await verifyUsersTableStructure (page )
315+
316+ // 4. Open user, record initial state
317+ const initialRoleCount = await page .locator (' role-tag' ).count ()
318+
319+ // 5. Make changes (add a role)
320+ await addRoleToUser (page )
321+ await page .getByRole (' button' , { name: ' Save' }).click ()
322+
323+ // 6. Reload and verify persistence
324+ await page .reload ()
325+ await expect (page .locator (' role-tag' )).toHaveCount (initialRoleCount + 1 )
326+
327+ // 7. Cleanup - restore original state
328+ await removeRoleFromUser (page )
329+ await page .getByRole (' button' , { name: ' Save' }).click ()
330+ await expect (page .locator (' role-tag' )).toHaveCount (initialRoleCount )
331+ })
332+ ```
333+
334+ ** Bad Example - Fragmented Tests:**
335+
336+ ``` typescript
337+ // ❌ Don't split into many small tests - causes repeated setup and state issues
338+ test .describe (' User Management' , () => {
339+ test (' should display Users menu' , ... )
340+ test (' should navigate to users list' , ... )
341+ test (' should display table headers' , ... )
342+ test (' should display at least one user' , ... )
343+ test (' should open user details' , ... )
344+ test (' should add a role' , ... )
345+ test (' should save changes' , ... )
346+ })
347+ ```
348+
349+ ** Cleanup Pattern:**
350+
351+ ``` typescript
352+ test (' User can create, customize, and delete a resource' , async ({ page }) => {
353+ await login (page )
354+
355+ // Record initial state if needed
356+ const initialCount = await page .locator (' .resource' ).count ()
357+
358+ // Create resource (use unique identifier)
359+ const resourceName = ` test-${Date .now ()} `
360+ await createResource (page , resourceName )
361+
362+ // Perform actions and verifications
363+ await customizeResource (page , resourceName )
364+ await verifyResource (page , resourceName )
365+
366+ // Cleanup - restore original state
367+ await deleteResource (page , resourceName )
368+ await expect (page .locator (' .resource' )).toHaveCount (initialCount )
369+ })
370+ ```
371+
372+ ** Key Principles:**
373+
374+ - Tests are self-contained and don't depend on other tests
375+ - Tests clean up after themselves to avoid state accumulation
376+ - Use unique identifiers (timestamps, UUIDs) for test data
377+ - Helper functions should be local to the test file unless truly reusable across multiple test files
378+
290379## Unit Testing Best Practices
291380
292381### Component Testing
0 commit comments