Skip to content

Commit 9b321b1

Browse files
committed
e2e improvements
1 parent 98b892d commit 9b321b1

File tree

2 files changed

+344
-441
lines changed

2 files changed

+344
-441
lines changed

.cursor/rules/TESTING_GUIDELINES.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,95 @@ const errorNoty = page.locator('shade-noty').first()
287287
await 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

Comments
 (0)