From 4fbda6cd9f9520f0fc0e49353f8da46280eb6f55 Mon Sep 17 00:00:00 2001 From: mstuartf Date: Fri, 1 Jul 2022 17:56:26 +0100 Subject: [PATCH] fix(PPDSC-2164): assistive text (#249) * fix(PPDSC-2164): add tests for bug expected outcome * fix(PPDSC-2164): do not set aria-describedby if no assistive text - Update assistiveTextId context value inside AssistiveText component so that it is only set if this component exists within the parent. * fix(PPDSC-2164): update failing fieldset snapshots --- .../__snapshots__/fieldset.test.tsx.snap | 6 -- src/form/__tests__/form.test.tsx | 60 +++++++++++++++++++ src/form/context.ts | 1 + src/form/form-input.tsx | 24 ++++++-- 4 files changed, 80 insertions(+), 11 deletions(-) diff --git a/src/fieldset/__tests__/__snapshots__/fieldset.test.tsx.snap b/src/fieldset/__tests__/__snapshots__/fieldset.test.tsx.snap index 5a8d46ece0..d9eb2a02a3 100644 --- a/src/fieldset/__tests__/__snapshots__/fieldset.test.tsx.snap +++ b/src/fieldset/__tests__/__snapshots__/fieldset.test.tsx.snap @@ -647,7 +647,6 @@ exports[`Fieldset renders fieldset with large form inputs 1`] = ` class="emotion-2" > { }); expect(await findByTestId('error-icon')).not.toBeNull(); }); + + describe('input.aria-describedby', () => { + const INPUT_ID = 'test-input-1'; + let assistiveTextId; + + test('is set to assistive text id in default state', () => { + const {getByText, getByTestId} = renderWithImplementation(Form, { + onSubmit: () => {}, + children: ( + + Test input + + Assistive Text + + ), + }); + + assistiveTextId = `${INPUT_ID}-assistive-text`; + + const assistiveText = getByText('Assistive Text'); + expect(assistiveText).toHaveAttribute('id', assistiveTextId); + const input = getByTestId('text-field-test-input'); + expect(input).toHaveAttribute('aria-describedby', assistiveTextId); + }); + + test('is not set if no assistive text is provided', () => { + const {getByTestId} = renderWithImplementation(Form, { + onSubmit: () => {}, + children: ( + + Test input + + + ), + }); + + const input = getByTestId('text-field-test-input'); + expect(input).not.toHaveAttribute('aria-describedby'); + }); + + test('is set to assistive text id in invalid state', () => { + const {getByText, getByTestId} = renderWithImplementation(Form, { + onSubmit: () => {}, + children: ( + + Test input + + Assistive Text + + ), + }); + + assistiveTextId = `${INPUT_ID}-error-text`; + + const assistiveText = getByText('Assistive Text'); + expect(assistiveText).toHaveAttribute('id', assistiveTextId); + const input = getByTestId('text-field-test-input'); + expect(input).toHaveAttribute('aria-describedby', assistiveTextId); + }); + }); }); diff --git a/src/form/context.ts b/src/form/context.ts index 59f1bae46f..7db8995ace 100644 --- a/src/form/context.ts +++ b/src/form/context.ts @@ -29,6 +29,7 @@ export const FormInputContext = createContext<{ id?: string; labelId?: string; assistiveTextId?: string; + setAssistiveTextId?: (id: string) => void; statusIcon?: React.ReactNode; isRequired?: boolean; }>({}); diff --git a/src/form/form-input.tsx b/src/form/form-input.tsx index 60c327cee7..0b8251f1ec 100644 --- a/src/form/form-input.tsx +++ b/src/form/form-input.tsx @@ -1,4 +1,4 @@ -import React, {useContext} from 'react'; +import React, {useContext, useEffect, useState} from 'react'; import composeRefs from '@seznam/compose-react-refs'; import {Label, LabelProps} from '../label'; import {TextField} from '../text-field/text-field'; @@ -45,6 +45,7 @@ const ThemelessFormInput = ({ const [autoGeneratedId] = useReactKeys(1); const currentID = id || autoGeneratedId; + const [assistiveTextId, setAssistiveTextId] = useState(); const theme = useTheme(); @@ -61,9 +62,6 @@ const ThemelessFormInput = ({ {({ref, state: stateContext, onChange, onBlur, error}) => { const state = stateProp || stateContext; - const assistiveTextId = - (state === 'invalid' && `${currentID}-error-text`) || - `${currentID}-assistive-text`; const labelId = `${currentID}-label`; const statusIcon = getStatusIcon({state, iconSize: validationIconSize}); @@ -80,6 +78,7 @@ const ThemelessFormInput = ({ ref, id: currentID, assistiveTextId, + setAssistiveTextId, labelId, statusIcon, isRequired, @@ -202,7 +201,22 @@ export const FormInputAssistiveText = ({ overrides, ...props }: AssistiveTextProps & {validationIcon?: boolean}) => { - const {size, state, error, assistiveTextId} = useFormFieldContext(); + const { + size, + state, + error, + assistiveTextId, + setAssistiveTextId, + id, + } = useFormFieldContext(); + + useEffect(() => { + if (setAssistiveTextId) { + setAssistiveTextId( + state === 'invalid' ? `${id}-error-text` : `${id}-assistive-text`, + ); + } + }, [state, id, setAssistiveTextId]); const theme = useTheme();