From b3b0593ab83000bacc0791dacb7d429e9daf76bc Mon Sep 17 00:00:00 2001 From: Fedo Hagge-Kubat Date: Thu, 9 Apr 2026 20:52:48 +0200 Subject: [PATCH 1/4] =?UTF-8?q?fix(a11y):=20WCAG=203.3.1=20=E2=80=94=20add?= =?UTF-8?q?=20error=20identification=20with=20role=3Dalert,=20aria-invalid?= =?UTF-8?q?,=20and=20aria-describedby?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/Alert/Alert.test.tsx | 36 +++++++++++++- .../src/components/Alert/index.tsx | 1 + .../Form/LabeledErrorBoundInput.tsx | 20 +++++++- .../ErrorMessage/BasicErrorAlert.test.tsx | 20 ++++++++ .../ErrorMessage/BasicErrorAlert.tsx | 2 +- .../src/components/Modal/ModalFormField.tsx | 26 ++++++++-- .../src/explore/components/ControlHeader.tsx | 24 ++++++++- .../controls/NumberControl/index.tsx | 18 +++++++ .../components/controls/TextControl/index.tsx | 15 ++++++ .../src/features/alerts/AlertReportModal.tsx | 19 ++++++- .../alerts/components/NumberInput.tsx | 2 + .../databases/DatabaseModal/SSHTunnelForm.tsx | 49 +++++++++++++++++++ .../DatabaseModal/SqlAlchemyForm.tsx | 22 ++++++++- .../src/features/roles/RoleFormItems.tsx | 6 ++- 14 files changed, 248 insertions(+), 12 deletions(-) diff --git a/superset-frontend/packages/superset-core/src/components/Alert/Alert.test.tsx b/superset-frontend/packages/superset-core/src/components/Alert/Alert.test.tsx index cb0e8092f7d7..24f11f10a815 100644 --- a/superset-frontend/packages/superset-core/src/components/Alert/Alert.test.tsx +++ b/superset-frontend/packages/superset-core/src/components/Alert/Alert.test.tsx @@ -17,10 +17,44 @@ * under the License. */ -import { render } from '../../testing'; +import { render, screen } from '../../testing'; import { Alert } from '.'; test('renders Alert with default props', async () => { const { container } = render(); expect(container).toHaveTextContent('Default message'); }); + +// WCAG 3.3.1 - Error Identification accessibility tests +test('renders with role="alert" for screen reader announcement', () => { + render(Error message); + expect(screen.getByRole('alert')).toBeInTheDocument(); +}); + +test('renders with aria-atomic="true" so full content is announced', () => { + render(Error message); + expect(screen.getByRole('alert')).toHaveAttribute('aria-atomic', 'true'); +}); + +test('uses aria-live="assertive" for error alerts', () => { + render(Error message); + expect(screen.getByRole('alert')).toHaveAttribute( + 'aria-live', + 'assertive', + ); +}); + +test('uses aria-live="polite" for warning alerts', () => { + render(Warning message); + expect(screen.getByRole('alert')).toHaveAttribute('aria-live', 'polite'); +}); + +test('uses aria-live="polite" for info alerts', () => { + render(Info message); + expect(screen.getByRole('alert')).toHaveAttribute('aria-live', 'polite'); +}); + +test('uses aria-live="polite" for success alerts', () => { + render(Success message); + expect(screen.getByRole('alert')).toHaveAttribute('aria-live', 'polite'); +}); diff --git a/superset-frontend/packages/superset-core/src/components/Alert/index.tsx b/superset-frontend/packages/superset-core/src/components/Alert/index.tsx index ff593b853a57..bda693a2721e 100644 --- a/superset-frontend/packages/superset-core/src/components/Alert/index.tsx +++ b/superset-frontend/packages/superset-core/src/components/Alert/index.tsx @@ -71,6 +71,7 @@ export const Alert = (props: AlertProps) => { return ( { const hasError = !!errorMessage; + const errorDescriptionId = hasError ? `${id || props.name}-error-description` : undefined; return ( @@ -78,13 +79,23 @@ export const LabeledErrorBoundInput = ({ validateStatus={ isValidating ? 'validating' : hasError ? 'error' : 'success' } - help={errorMessage || helpText} + help={ + hasError ? ( + + {errorMessage} + + ) : ( + helpText + ) + } hasFeedback={!!hasError} > {visibilityToggle || props.name === 'password' ? ( visible ? ( @@ -99,7 +110,12 @@ export const LabeledErrorBoundInput = ({ role="textbox" /> ) : ( - + )} {get_url && description ? (