diff --git a/app/api/og/route.accessibility.test.tsx b/app/api/og/route.accessibility.test.tsx new file mode 100644 index 000000000..aa76cd001 --- /dev/null +++ b/app/api/og/route.accessibility.test.tsx @@ -0,0 +1,86 @@ +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { describe, it, expect } from 'vitest'; +// 1.Import Next.js Link component at the top +import Link from 'next/link'; + +// 2. Swap out the tag inside your local Mock component +const OGRouteLayoutMock = () => ( +
+

CommitPulse Image

+

Open Graph Generation

+ + {/* Changed from
Home to Home */} + Home + + + + + + Information Icon +
Additional metadata
+
+); + +describe('ApiOgRoute Accessibility Standards & ARIA Compliance', () => { + it('should have correct ARIA roles and accessible labels assigned', () => { + render(); + + const bannerSection = screen.getByRole('region', { name: /commitpulse image/i }); + expect(bannerSection).toBeInTheDocument(); + expect(bannerSection).toHaveAttribute('aria-labelledby'); + }); + + it('should maintain visible outline classes/styles on interactive nodes upon focus', async () => { + render(); + const user = userEvent.setup(); + const actionButton = screen.getByRole('button', { name: /interact/i }); + + expect(actionButton).not.toHaveFocus(); + + await user.tab(); // Navigates onto the link + await user.tab(); // Navigates onto the interact button + expect(actionButton).toHaveFocus(); + + expect(actionButton.className).toMatch(/focus:/); + }); + + it('should announce tooltips using valid aria-describedby associations', () => { + render(); + + const infoIcon = screen.getByRole('img', { name: /information icon/i }); + const tooltipId = infoIcon.getAttribute('aria-describedby'); + + expect(tooltipId).toBeDefined(); + const tooltipElement = document.getElementById(tooltipId!); + expect(tooltipElement).toBeInTheDocument(); + expect(tooltipElement).toHaveTextContent(/additional metadata/i); + }); + + it('should follow a predictable and sequential logical tab order path', async () => { + render(); + const user = userEvent.setup(); + + const firstElement = screen.getByRole('link', { name: /home/i }); + const secondElement = screen.getByRole('button', { name: /interact/i }); + + await user.tab(); + expect(firstElement).toHaveFocus(); + + await user.tab(); + expect(secondElement).toHaveFocus(); + }); + + it('should render standard headings in a strict logical hierarchical structure', () => { + render(); + + const mainHeading = screen.getByRole('heading', { level: 1 }); + const subHeading = screen.getByRole('heading', { level: 2 }); + + expect(mainHeading).toBeInTheDocument(); + expect(subHeading).toBeInTheDocument(); + + const compareOrder = mainHeading.compareDocumentPosition(subHeading); + expect(compareOrder & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy(); + }); +});