test(capacity): Add E2E test for availability save
Add comprehensive E2E test for capacity calendar functionality: - Login and navigate to capacity page - Create test team member - Select team member and wait for calendar - Change availability from Full day to Half day - Verify save completes without errors - Verify change persists via API Test Results: - Backend: 76 passed ✅ - Frontend Unit: 10 passed ✅ - E2E: 132 passed, 24 skipped ✅ - New test: 2 passed (chromium + firefox) ✅ Refs: openspec/changes/headroom-foundation
This commit is contained in:
97
frontend/tests/e2e/capacity-calendar.spec.ts
Normal file
97
frontend/tests/e2e/capacity-calendar.spec.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import { test, expect, type Page } from '@playwright/test';
|
||||
|
||||
const API_BASE = 'http://localhost:3000';
|
||||
|
||||
async function login(page: Page) {
|
||||
await page.goto('/login');
|
||||
await page.fill('input[type="email"]', 'superuser@headroom.test');
|
||||
await page.fill('input[type="password"]', 'password');
|
||||
await page.click('button[type="submit"]');
|
||||
await page.waitForURL('/dashboard');
|
||||
}
|
||||
|
||||
async function createTeamMember(page: Page, token: string) {
|
||||
const response = await page.request.post(`${API_BASE}/api/team-members`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
data: {
|
||||
name: `Capacity Calendar Tester ${Date.now()}`,
|
||||
role_id: 1,
|
||||
hourly_rate: 150,
|
||||
active: true
|
||||
}
|
||||
});
|
||||
|
||||
const body = await response.json();
|
||||
return body.id as string;
|
||||
}
|
||||
|
||||
test.describe('Capacity Calendar', () => {
|
||||
let authToken: string;
|
||||
let memberId: string | null = null;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await login(page);
|
||||
const token = (await page.evaluate(() => localStorage.getItem('headroom_access_token'))) ?? '';
|
||||
authToken = token;
|
||||
memberId = await createTeamMember(page, authToken);
|
||||
|
||||
await page.goto('/capacity');
|
||||
await page.waitForURL('/capacity');
|
||||
await page.waitForResponse((response) => response.url().includes('/api/team-members') && response.status() === 200);
|
||||
});
|
||||
|
||||
test.afterEach(async ({ page }) => {
|
||||
if (memberId) {
|
||||
await page.request.delete(`${API_BASE}/api/team-members/${memberId}`, {
|
||||
headers: { Authorization: `Bearer ${authToken}` }
|
||||
}).catch(() => null);
|
||||
memberId = null;
|
||||
}
|
||||
});
|
||||
|
||||
test('should save availability change with success message', async ({ page }) => {
|
||||
await expect(page.locator('select[aria-label="Select team member"]')).toBeVisible({ timeout: 10000 });
|
||||
|
||||
const teamMemberSelect = page.locator('select[aria-label="Select team member"]');
|
||||
if (memberId) {
|
||||
await teamMemberSelect.selectOption({ value: memberId });
|
||||
}
|
||||
|
||||
await expect(page.locator('[data-testid="capacity-calendar"]')).toBeVisible({ timeout: 10000 });
|
||||
|
||||
const availabilitySelects = page
|
||||
.locator('select[aria-label^="Availability for"]')
|
||||
.filter({ has: page.locator('option[value="1"]') });
|
||||
|
||||
await expect(availabilitySelects.first()).toBeVisible({ timeout: 5000 });
|
||||
|
||||
const firstSelect = availabilitySelects.first();
|
||||
const ariaLabel = await firstSelect.getAttribute('aria-label');
|
||||
const targetDate = ariaLabel?.replace('Availability for ', '') ?? '';
|
||||
expect(targetDate).toBeTruthy();
|
||||
|
||||
await firstSelect.selectOption('0.5');
|
||||
|
||||
await expect(page.locator('text=Saving availability...')).toBeVisible({ timeout: 5000 });
|
||||
await expect(page.locator('text=Saving availability...')).not.toBeVisible({ timeout: 10000 });
|
||||
|
||||
await expect(page.locator('[data-testid="capacity-calendar"] .alert.alert-error')).toHaveCount(0);
|
||||
|
||||
if (memberId) {
|
||||
const period =
|
||||
(await page.evaluate(() => localStorage.getItem('headroom_selected_period'))) ?? '2026-02';
|
||||
const response = await page.request.get(
|
||||
`${API_BASE}/api/capacity?month=${period}&team_member_id=${memberId}`
|
||||
);
|
||||
const body = await response.json();
|
||||
const changedDetail = (body.details as Array<{ date: string; availability: number }>).find(
|
||||
(detail) => detail.date === targetDate
|
||||
);
|
||||
expect(changedDetail).toBeDefined();
|
||||
expect(changedDetail?.availability).toBe(0.5);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user