mirror of
https://github.com/supabase/supabase.git
synced 2026-09-06 18:11:51 +08:00
## What kind of change does this PR introduce? bug fix for accessibility, fixes [docs-1265](https://linear.app/supabase/issue/DOCS-1365/add-aria-label-to-icon-only-buttons-button-name) ## What is the current behavior? some controles in the docs app have no accessible name, so screen readers announce them as an unlabelled "button" ## What is the new behavior? - adds each control a name the way its neighbours already do - adds menu toggle a state-dependent `aria-label` and `aria-expanded` - adds `button-name` to `enforced_rules` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Accessibility** - Added descriptive labels to configuration selectors and mobile menu controls. - Mobile menu controls now announce whether the menu is open or closed. - Expanded accessibility validation to check button names across documentation pages. - **UI Improvements** - Updated the raw throughput table control with a clearer button appearance and expandable chevron indicator. - Replaced a schema-migration tooltip with a direct in-page link. - **Documentation** - Removed the Info Tooltip component guidance from the contributing documentation. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
104 lines
2.5 KiB
TypeScript
104 lines
2.5 KiB
TypeScript
import type { Page, TestInfo } from '@playwright/test'
|
|
import type { Result } from 'axe-core'
|
|
|
|
import { scan } from '../../shared/axe.ts'
|
|
|
|
export const WCAG_TAGS = ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa']
|
|
|
|
export const ENFORCED_RULES = ['heading-order', 'page-has-heading-one', 'button-name']
|
|
|
|
export const EXCLUDED_RULES = [
|
|
'color-contrast',
|
|
'html-has-lang',
|
|
'html-lang-valid',
|
|
'html-xml-lang-mismatch',
|
|
'document-title',
|
|
'aria-hidden-body',
|
|
'meta-viewport',
|
|
'meta-refresh',
|
|
'css-orientation-lock',
|
|
]
|
|
|
|
export interface A11yScanResult {
|
|
surface: string
|
|
url: string
|
|
include: string
|
|
excludedRules: string[]
|
|
loaded: boolean
|
|
status: number | null
|
|
elementCount: number
|
|
violations: Result[]
|
|
}
|
|
|
|
export function shouldEnforceAll(): boolean {
|
|
return !!process.env.A11Y_ENFORCE_ALL
|
|
}
|
|
|
|
export async function scanArticle(
|
|
page: Page,
|
|
surface: string,
|
|
include: string
|
|
): Promise<A11yScanResult> {
|
|
const reported = await scan(page, { tags: WCAG_TAGS, excludeRules: EXCLUDED_RULES, include })
|
|
const enforced = await scan(page, { rules: ENFORCED_RULES })
|
|
|
|
const byRule = new Map([...reported, ...enforced].map((violation) => [violation.id, violation]))
|
|
|
|
const elementCount = await page.evaluate(
|
|
(selector) => document.querySelector(selector)?.querySelectorAll('*').length ?? 0,
|
|
include
|
|
)
|
|
|
|
return {
|
|
surface,
|
|
url: page.url(),
|
|
include,
|
|
excludedRules: EXCLUDED_RULES,
|
|
loaded: true,
|
|
status: null,
|
|
elementCount,
|
|
violations: [...byRule.values()],
|
|
}
|
|
}
|
|
|
|
export function unloadedResult(
|
|
surface: string,
|
|
url: string,
|
|
status: number | null,
|
|
include: string
|
|
): A11yScanResult {
|
|
return {
|
|
surface,
|
|
url,
|
|
include,
|
|
excludedRules: EXCLUDED_RULES,
|
|
loaded: false,
|
|
status,
|
|
elementCount: 0,
|
|
violations: [],
|
|
}
|
|
}
|
|
|
|
export const MIN_MEANINGFUL_ELEMENTS = 20
|
|
|
|
export function scanLooksEmpty(
|
|
result: A11yScanResult,
|
|
minElements: number = MIN_MEANINGFUL_ELEMENTS
|
|
): boolean {
|
|
return result.elementCount < minElements
|
|
}
|
|
|
|
export async function attachScanReport(testInfo: TestInfo, result: A11yScanResult): Promise<void> {
|
|
await testInfo.attach('axe-results.json', {
|
|
body: JSON.stringify(result, null, 2),
|
|
contentType: 'application/json',
|
|
})
|
|
}
|
|
|
|
export function blockingViolations(result: A11yScanResult): Result[] {
|
|
if (shouldEnforceAll()) return result.violations
|
|
return result.violations.filter((violation) => ENFORCED_RULES.includes(violation.id))
|
|
}
|
|
|
|
export { formatViolations, settleForAxe, violationIds } from '../../shared/axe.ts'
|