Add accessibility improvements (P4.2 partial)
All checks were successful
Deploy / deploy (push) Successful in 1m36s

- Add skip navigation link to root layout
- Add semantic HTML landmarks (main element) to login and settings pages
- Add aria-labels to calendar day buttons with date, cycle day, and phase info
- Add id="main-content" to dashboard main element for skip link target
- Fix pre-existing type error in auth-middleware.test.ts

Tests: 781 passing (11 new accessibility tests)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-11 21:49:26 +00:00
parent 2bfd93589b
commit 649fa29df2
12 changed files with 259 additions and 34 deletions

View File

@@ -70,16 +70,20 @@ describe("MonthView", () => {
it("highlights today's date", () => {
render(<MonthView {...baseProps} />);
// Jan 15 is "today" - find the button containing "15"
const todayCell = screen.getByRole("button", { name: /^15\s*Day 15/i });
// Jan 15 is "today" - aria-label includes date, cycle day, and phase
const todayCell = screen.getByRole("button", {
name: /January 15, 2026 - Cycle day 15 - Ovulation phase \(today\)/i,
});
expect(todayCell).toHaveClass("ring-2", "ring-black");
});
it("does not highlight non-today dates", () => {
render(<MonthView {...baseProps} />);
// Jan 1 is not today
const otherCell = screen.getByRole("button", { name: /^1\s*Day 1/i });
// Jan 1 is not today - aria-label includes date, cycle day, and phase
const otherCell = screen.getByRole("button", {
name: /January 1, 2026 - Cycle day 1 - Menstrual phase$/i,
});
expect(otherCell).not.toHaveClass("ring-2");
});
});
@@ -89,7 +93,9 @@ describe("MonthView", () => {
render(<MonthView {...baseProps} />);
// Days 1-3 are MENSTRUAL (bg-blue-100)
const day1 = screen.getByRole("button", { name: /^1\s*Day 1/i });
const day1 = screen.getByRole("button", {
name: /January 1, 2026 - Cycle day 1 - Menstrual phase/i,
});
expect(day1).toHaveClass("bg-blue-100");
});
@@ -97,7 +103,9 @@ describe("MonthView", () => {
render(<MonthView {...baseProps} />);
// Day 5 is FOLLICULAR (bg-green-100)
const day5 = screen.getByRole("button", { name: /^5\s*Day 5/i });
const day5 = screen.getByRole("button", {
name: /January 5, 2026 - Cycle day 5 - Follicular phase/i,
});
expect(day5).toHaveClass("bg-green-100");
});
@@ -105,7 +113,9 @@ describe("MonthView", () => {
render(<MonthView {...baseProps} />);
// Day 15 is OVULATION (bg-purple-100)
const day15 = screen.getByRole("button", { name: /^15\s*Day 15/i });
const day15 = screen.getByRole("button", {
name: /January 15, 2026 - Cycle day 15 - Ovulation phase/i,
});
expect(day15).toHaveClass("bg-purple-100");
});
@@ -113,7 +123,9 @@ describe("MonthView", () => {
render(<MonthView {...baseProps} />);
// Day 20 is EARLY_LUTEAL (bg-yellow-100)
const day20 = screen.getByRole("button", { name: /^20\s*Day 20/i });
const day20 = screen.getByRole("button", {
name: /January 20, 2026 - Cycle day 20 - Early Luteal phase/i,
});
expect(day20).toHaveClass("bg-yellow-100");
});
@@ -121,7 +133,9 @@ describe("MonthView", () => {
render(<MonthView {...baseProps} />);
// Day 25 is LATE_LUTEAL (bg-red-100)
const day25 = screen.getByRole("button", { name: /^25\s*Day 25/i });
const day25 = screen.getByRole("button", {
name: /January 25, 2026 - Cycle day 25 - Late Luteal phase/i,
});
expect(day25).toHaveClass("bg-red-100");
});
});
@@ -219,11 +233,16 @@ describe("MonthView", () => {
);
// Jan 1 should be day 28 (late luteal)
const jan1 = screen.getByRole("button", { name: /^1\s*Day 28/i });
// Button now has aria-label with full date, cycle day, and phase
const jan1 = screen.getByRole("button", {
name: /January 1, 2026 - Cycle day 28 - Late Luteal phase/i,
});
expect(jan1).toHaveClass("bg-red-100"); // LATE_LUTEAL
// Jan 2 should be day 1 (menstrual)
const jan2 = screen.getByRole("button", { name: /^2\s*Day 1/i });
const jan2 = screen.getByRole("button", {
name: /January 2, 2026 - Cycle day 1 - Menstrual phase/i,
});
expect(jan2).toHaveClass("bg-blue-100"); // MENSTRUAL
});
});