Add 8 new E2E tests for accessibility and error recovery
All checks were successful
Deploy / deploy (push) Successful in 1m40s
All checks were successful
Deploy / deploy (push) Successful in 1m40s
- calendar.spec.ts: +4 accessibility tests (ARIA role, aria-labels, keyboard navigation, accessible nav buttons) - settings.spec.ts: +1 error recovery test (retry after failed save) - mobile.spec.ts: +3 calendar mobile tests (rendering, touch targets, navigation) Total E2E tests: 190 → 198 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -651,4 +651,109 @@ test.describe("settings", () => {
|
||||
await page.waitForTimeout(500);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("error recovery", () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
const email = process.env.TEST_USER_EMAIL;
|
||||
const password = process.env.TEST_USER_PASSWORD;
|
||||
|
||||
if (!email || !password) {
|
||||
test.skip();
|
||||
return;
|
||||
}
|
||||
|
||||
await page.goto("/login");
|
||||
await page.waitForLoadState("networkidle");
|
||||
|
||||
const emailInput = page.getByLabel(/email/i);
|
||||
const hasEmailForm = await emailInput.isVisible().catch(() => false);
|
||||
|
||||
if (!hasEmailForm) {
|
||||
test.skip();
|
||||
return;
|
||||
}
|
||||
|
||||
await emailInput.fill(email);
|
||||
await page.getByLabel(/password/i).fill(password);
|
||||
await page.getByRole("button", { name: /sign in/i }).click();
|
||||
|
||||
await page.waitForURL("/", { timeout: 10000 });
|
||||
await page.goto("/settings");
|
||||
await page.waitForLoadState("networkidle");
|
||||
});
|
||||
|
||||
test("shows error message and allows retry when save fails", async ({
|
||||
page,
|
||||
}) => {
|
||||
const cycleLengthInput = page.getByLabel(/cycle length/i);
|
||||
const isVisible = await cycleLengthInput.isVisible().catch(() => false);
|
||||
|
||||
if (!isVisible) {
|
||||
test.skip();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get original value for restoration
|
||||
const originalValue = await cycleLengthInput.inputValue();
|
||||
|
||||
// Intercept the save request and make it fail once, then succeed
|
||||
let failureCount = 0;
|
||||
await page.route("**/api/user", async (route) => {
|
||||
if (route.request().method() === "PATCH") {
|
||||
if (failureCount === 0) {
|
||||
failureCount++;
|
||||
// First request fails with server error
|
||||
await route.fulfill({
|
||||
status: 500,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ error: "Server error" }),
|
||||
});
|
||||
} else {
|
||||
// Subsequent requests succeed - let them through
|
||||
await route.continue();
|
||||
}
|
||||
} else {
|
||||
await route.continue();
|
||||
}
|
||||
});
|
||||
|
||||
// Change the cycle length
|
||||
const newValue = originalValue === "28" ? "32" : "28";
|
||||
await cycleLengthInput.fill(newValue);
|
||||
|
||||
// Click save - should fail
|
||||
const saveButton = page.getByRole("button", { name: /save/i });
|
||||
await saveButton.click();
|
||||
|
||||
// Wait for error handling to complete
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// The key test is that the form remains usable after a failed save
|
||||
// Error handling may show a toast or just keep the form editable
|
||||
|
||||
// Verify form is still editable (not stuck in loading state)
|
||||
const isEditable = await cycleLengthInput.isEditable();
|
||||
expect(isEditable).toBe(true);
|
||||
|
||||
// Verify save button is enabled for retry
|
||||
const isButtonEnabled = !(await saveButton.isDisabled());
|
||||
expect(isButtonEnabled).toBe(true);
|
||||
|
||||
// Try saving again - should succeed this time
|
||||
await saveButton.click();
|
||||
await page.waitForTimeout(1500);
|
||||
|
||||
// Form should still be functional
|
||||
const isEditableAfterRetry = await cycleLengthInput.isEditable();
|
||||
expect(isEditableAfterRetry).toBe(true);
|
||||
|
||||
// Clean up route interception
|
||||
await page.unroute("**/api/user");
|
||||
|
||||
// Restore original value
|
||||
await cycleLengthInput.fill(originalValue);
|
||||
await saveButton.click();
|
||||
await page.waitForTimeout(500);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user