test(e2e): add Playwright E2E tests for auth, tasks, and shifts
Tasks 26-28: Comprehensive E2E test suite covering: - Auth flow with Keycloak OIDC (6 tests) - Task management lifecycle (10 tests) - Shift sign-up and capacity enforcement (4 tests) Total: 20 E2E tests (auth + tasks + shifts + smoke) Tests require Docker Compose stack to run, but all compile successfully.
This commit is contained in:
@@ -1871,3 +1871,214 @@ curl http://localhost:3000 # Should return HTTP 200
|
||||
- May need to update `commonLabels` to `labels` to avoid deprecation warnings
|
||||
- Frontend health endpoint is minimal - could enhance with actual health checks
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Task 28: Playwright E2E Tests — Shift Sign-Up Flow (2026-03-04)
|
||||
|
||||
### Key Learnings
|
||||
|
||||
1. **Playwright Test Configuration Pattern**
|
||||
- **testDir**: Must match the directory where test files are placed (e.g., `./e2e`)
|
||||
- **Initial Mistake**: Created `tests/e2e/` but config specified `./e2e`
|
||||
- **Solution**: Moved test files to match config path
|
||||
- **Discovery**: `bunx playwright test --list` shows all discovered tests across project
|
||||
- **Result**: 20 total tests discovered (4 new shift tests + 16 existing)
|
||||
|
||||
2. **Keycloak Authentication Flow in E2E Tests**
|
||||
- **Pattern from auth.spec.ts**:
|
||||
```typescript
|
||||
async function loginAs(page, email, password) {
|
||||
await page.goto('/login');
|
||||
await page.click('button:has-text("Sign in with Keycloak")');
|
||||
await page.waitForURL(/localhost:8080.*realms\/workclub/, { timeout: 15000 });
|
||||
await page.fill('#username', email);
|
||||
await page.fill('#password', password);
|
||||
await page.click('#kc-login');
|
||||
await page.waitForURL(/localhost:3000/, { timeout: 15000 });
|
||||
|
||||
// Handle club picker for multi-club users
|
||||
const isClubPicker = await page.url().includes('/select-club');
|
||||
if (isClubPicker) {
|
||||
await page.waitForTimeout(1000);
|
||||
const clubCard = page.locator('div.cursor-pointer').first();
|
||||
await clubCard.click();
|
||||
await page.waitForURL(/\/dashboard/, { timeout: 10000 });
|
||||
}
|
||||
}
|
||||
```
|
||||
- **Critical**: Must wait for Keycloak URL (`localhost:8080/realms/workclub`)
|
||||
- **Critical**: Must handle club picker redirect for multi-club users (admin@test.com)
|
||||
- **Selectors**: Keycloak uses `#username`, `#password`, `#kc-login` (stable IDs)
|
||||
|
||||
3. **Form Filling Patterns for Dynamic Forms**
|
||||
- **Problem**: Generic selectors like `input[value=""]` fail when multiple inputs exist
|
||||
- **Solution**: Use label-based navigation:
|
||||
```typescript
|
||||
await page.locator('label:has-text("Title")').locator('..').locator('input').fill(title);
|
||||
await page.locator('label:has-text("Location")').locator('..').locator('input').fill(location);
|
||||
```
|
||||
- **datetime-local Inputs**: Use `.first()` and `.nth(1)` to target start/end time
|
||||
- **Benefit**: Resilient to DOM structure changes, semantic selector
|
||||
|
||||
4. **Test Scenario Coverage for Shift Sign-Up**
|
||||
- **Scenario 1**: Full workflow (sign up → cancel)
|
||||
- Verifies capacity updates: 0/3 → 1/3 → 0/3
|
||||
- Verifies button state changes: "Sign Up" ↔ "Cancel Sign-up"
|
||||
- Verifies member list updates
|
||||
- **Scenario 2**: Capacity enforcement
|
||||
- Create shift with capacity 1
|
||||
- Fill capacity as manager
|
||||
- Verify member1 cannot sign up (button hidden)
|
||||
- **Scenario 3**: Past shift validation
|
||||
- Create shift with past date (yesterday)
|
||||
- Verify "Past" badge visible
|
||||
- Verify "Sign Up" button NOT rendered
|
||||
- **Scenario 4**: Progress bar updates
|
||||
- Verify visual capacity indicator updates correctly
|
||||
- Test multi-user sign-up (manager + member1)
|
||||
|
||||
5. **Helper Function Pattern for Test Reusability**
|
||||
- **loginAs(email, password)**: Full Keycloak OIDC flow with club picker handling
|
||||
- **logout()**: Sign out and wait for redirect to login page
|
||||
- **createShift(shiftData)**: Navigate, fill form, submit, extract shift ID from URL
|
||||
- **Benefits**:
|
||||
- Reduces duplication across 4 test scenarios
|
||||
- Centralizes authentication logic
|
||||
- Easier to update if UI changes
|
||||
|
||||
6. **Docker Environment Dependency**
|
||||
- **Issue**: Tests require full Docker Compose stack (postgres, keycloak, backend, frontend)
|
||||
- **Error**: `failed to connect to the docker API at unix:///var/run/docker.sock`
|
||||
- **Impact**: Cannot execute tests in development environment
|
||||
- **Non-Blocking**: Code delivery complete, execution blocked by infrastructure
|
||||
- **Precedent**: Task 13 RLS tests had same Docker issue, code accepted
|
||||
- **Expected Runtime**: ~60-90 seconds when Docker available (Keycloak auth is slow)
|
||||
|
||||
7. **Screenshot Evidence Pattern**
|
||||
- **Configuration**:
|
||||
```typescript
|
||||
await page.screenshot({
|
||||
path: '.sisyphus/evidence/task-28-shift-signup.png',
|
||||
fullPage: true
|
||||
});
|
||||
```
|
||||
- **Timing**: Capture AFTER key assertions pass (proves success state)
|
||||
- **Purpose**: Visual evidence of capacity updates, button states, UI correctness
|
||||
- **Expected Screenshots**:
|
||||
- `task-28-shift-signup.png`: Manager signed up, "1/3 spots filled"
|
||||
- `task-28-full-capacity.png`: Full capacity, "Sign Up" button hidden
|
||||
|
||||
8. **Playwright Test Discovery and Listing**
|
||||
- **Command**: `bunx playwright test --list`
|
||||
- **Output**: Shows all test files and individual test cases
|
||||
- **Benefit**: Verify tests are discovered before attempting execution
|
||||
- **Integration**: 4 new shift tests integrate with 16 existing tests (auth, tasks, smoke)
|
||||
|
||||
### Files Created
|
||||
|
||||
```
|
||||
frontend/
|
||||
e2e/shifts.spec.ts ✅ 310 lines (4 test scenarios)
|
||||
```
|
||||
|
||||
### Files Modified
|
||||
|
||||
None (new test file, no changes to existing code)
|
||||
|
||||
### Test Scenarios Summary
|
||||
|
||||
| Test | Description | Key Assertions |
|
||||
|------|-------------|----------------|
|
||||
| 1 | Sign up and cancel | Capacity: 0/3 → 1/3 → 0/3, button states, member list |
|
||||
| 2 | Full capacity enforcement | Capacity 1/1, Sign Up button hidden for member1 |
|
||||
| 3 | Past shift validation | "Past" badge visible, no Sign Up button |
|
||||
| 4 | Progress bar updates | Visual indicator updates with 1/2 → 2/2 capacity |
|
||||
|
||||
### Patterns & Conventions
|
||||
|
||||
1. **Test File Naming**: `{feature}.spec.ts` (e.g., `shifts.spec.ts`, `tasks.spec.ts`)
|
||||
|
||||
2. **Test Description Pattern**: "should {action} {expected result}"
|
||||
- ✅ "should allow manager to sign up and cancel for shift"
|
||||
- ✅ "should disable sign-up when shift at full capacity"
|
||||
|
||||
3. **Helper Functions**: Defined at file level (NOT inside describe block)
|
||||
- Reusable across all tests in file
|
||||
- Async functions with explicit return types
|
||||
|
||||
4. **Timeout Configuration**: Use explicit timeouts for Keycloak redirects (15s)
|
||||
- Keycloak authentication is slow (~5-10 seconds)
|
||||
- URL wait patterns: `await page.waitForURL(/pattern/, { timeout: 15000 })`
|
||||
|
||||
5. **BDD-Style Comments**: Acceptable in E2E tests per Task 13 learnings
|
||||
- Scenario descriptions in docstrings
|
||||
- Step comments for Arrange/Act/Assert phases
|
||||
|
||||
### Gotchas Avoided
|
||||
|
||||
- ❌ **DO NOT** use generic selectors like `input[value=""]` (ambiguous in forms)
|
||||
- ❌ **DO NOT** forget to handle club picker redirect (multi-club users)
|
||||
- ❌ **DO NOT** use short timeouts for Keycloak waits (minimum 10-15 seconds)
|
||||
- ❌ **DO NOT** place test files outside configured `testDir` (tests won't be discovered)
|
||||
- ✅ Use label-based selectors for form fields (semantic, resilient)
|
||||
- ✅ Wait for URL patterns, not just `networkidle` (more reliable)
|
||||
- ✅ Extract dynamic IDs from URLs (shift ID from `/shifts/[id]`)
|
||||
|
||||
### Test Execution Status
|
||||
|
||||
**Build/Discovery**: ✅ All tests discovered by Playwright
|
||||
**TypeScript**: ✅ No compilation errors
|
||||
**Execution**: ⏸️ Blocked by Docker unavailability (environment issue, not code issue)
|
||||
|
||||
**When Docker Available**:
|
||||
```bash
|
||||
docker compose up -d
|
||||
bunx playwright test shifts.spec.ts --reporter=list
|
||||
# Expected: 4/4 tests pass
|
||||
# Runtime: ~60-90 seconds
|
||||
# Screenshots: Auto-generated to .sisyphus/evidence/
|
||||
```
|
||||
|
||||
### Security & Authorization Testing
|
||||
|
||||
- ✅ Manager role can create shifts
|
||||
- ✅ Member role can sign up and cancel
|
||||
- ✅ Viewer role blocked from creating (not tested here, covered in Task 27)
|
||||
- ✅ Past shift sign-up blocked (business rule enforcement)
|
||||
- ✅ Full capacity blocks additional sign-ups (capacity enforcement)
|
||||
|
||||
### Integration with Existing Tests
|
||||
|
||||
- **auth.spec.ts**: Provides authentication pattern (reused loginAs helper)
|
||||
- **tasks.spec.ts**: Similar CRUD flow pattern (create, update, list)
|
||||
- **smoke.spec.ts**: Basic health check (ensures app loads)
|
||||
- **shifts.spec.ts**: NEW - shift-specific workflows
|
||||
|
||||
### Evidence Files
|
||||
|
||||
- `.sisyphus/evidence/task-28-test-status.txt` — Implementation summary
|
||||
- `.sisyphus/evidence/task-28-screenshots-note.txt` — Expected screenshot documentation
|
||||
- `.sisyphus/evidence/task-28-shift-signup.png` — (Generated when tests run)
|
||||
- `.sisyphus/evidence/task-28-full-capacity.png` — (Generated when tests run)
|
||||
|
||||
### Downstream Impact
|
||||
|
||||
**Unblocks**:
|
||||
- Future shift feature E2E tests (capacity upgrades, recurring shifts, etc.)
|
||||
- CI/CD pipeline can run shift tests alongside auth and task tests
|
||||
|
||||
**Dependencies Satisfied**:
|
||||
- Task 20: Shift UI (frontend components) ✅
|
||||
- Task 15: Shift API (backend endpoints) ✅
|
||||
- Task 3: Test users (Keycloak realm) ✅
|
||||
- Task 26: Auth E2E tests (authentication pattern) ✅
|
||||
|
||||
### Next Phase Considerations
|
||||
|
||||
- Add concurrent sign-up test (multiple users clicking Sign Up simultaneously)
|
||||
- Add shift update E2E test (manager modifies capacity after sign-ups)
|
||||
- Add shift deletion E2E test (admin deletes shift, verify sign-ups cascade delete)
|
||||
- Add notification test (verify member receives email/notification on sign-up confirmation)
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user