Merge pull request #10713 from keithjgrant/10563-a11y-fixes

Fix multiple accessibility violations
This commit is contained in:
Keith Grant
2021-07-23 10:36:21 -07:00
committed by GitHub
16 changed files with 41 additions and 24 deletions

View File

@@ -17,6 +17,7 @@ import Popover from '../Popover';
function CodeDetail({ value, label, mode, rows, helpText, dataCy }) { function CodeDetail({ value, label, mode, rows, helpText, dataCy }) {
const labelCy = dataCy ? `${dataCy}-label` : null; const labelCy = dataCy ? `${dataCy}-label` : null;
const valueCy = dataCy ? `${dataCy}-value` : null; const valueCy = dataCy ? `${dataCy}-value` : null;
const editorId = dataCy ? `${dataCy}-editor` : 'code-editor';
return ( return (
<> <>
@@ -27,12 +28,13 @@ function CodeDetail({ value, label, mode, rows, helpText, dataCy }) {
data-cy={labelCy} data-cy={labelCy}
> >
<div className="pf-c-form__label"> <div className="pf-c-form__label">
<span <label
htmlFor={editorId}
className="pf-c-form__label-text" className="pf-c-form__label-text"
css="font-weight: var(--pf-global--FontWeight--bold)" css="font-weight: var(--pf-global--FontWeight--bold)"
> >
{label} {label}
</span> </label>
{helpText && ( {helpText && (
<Popover header={label} content={helpText} id={dataCy} /> <Popover header={label} content={helpText} id={dataCy} />
)} )}
@@ -45,6 +47,7 @@ function CodeDetail({ value, label, mode, rows, helpText, dataCy }) {
data-cy={valueCy} data-cy={valueCy}
> >
<CodeEditor <CodeEditor
id={editorId}
mode={mode} mode={mode}
value={value} value={value}
readOnly readOnly

View File

@@ -29,7 +29,7 @@ const DetailValue = styled(
${(props) => ${(props) =>
(props.isEncrypted || props.isNotConfigured) && (props.isEncrypted || props.isNotConfigured) &&
` `
color: var(--pf-global--Color--400); color: var(--pf-global--disabled-color--100);
`} `}
`; `;

View File

@@ -30,6 +30,7 @@ function ExecutionEnvironmentDetail({
virtualEnvironment, virtualEnvironment,
verifyMissingVirtualEnv, verifyMissingVirtualEnv,
helpText, helpText,
dataCy,
}) { }) {
const config = useConfig(); const config = useConfig();
const docsLink = `${getDocsBaseUrl( const docsLink = `${getDocsBaseUrl(
@@ -51,7 +52,7 @@ function ExecutionEnvironmentDetail({
</Link> </Link>
} }
helpText={helpText} helpText={helpText}
dataCy="execution-environment-detail" dataCy={dataCy}
/> />
); );
} }
@@ -89,7 +90,7 @@ function ExecutionEnvironmentDetail({
</span> </span>
</> </>
} }
dataCy="missing-execution-environment-detail" dataCy={`missing-${dataCy}`}
/> />
); );
} }
@@ -113,7 +114,7 @@ function ExecutionEnvironmentDetail({
</span> </span>
</> </>
} }
dataCy="execution-environment-detail" dataCy={dataCy}
/> />
); );
} }
@@ -127,6 +128,7 @@ ExecutionEnvironmentDetail.propTypes = {
virtualEnvironment: string, virtualEnvironment: string,
verifyMissingVirtualEnv: bool, verifyMissingVirtualEnv: bool,
helpText: string, helpText: string,
dataCy: string,
}; };
ExecutionEnvironmentDetail.defaultProps = { ExecutionEnvironmentDetail.defaultProps = {
@@ -135,6 +137,7 @@ ExecutionEnvironmentDetail.defaultProps = {
virtualEnvironment: '', virtualEnvironment: '',
verifyMissingVirtualEnv: true, verifyMissingVirtualEnv: true,
helpText: '', helpText: '',
dataCy: 'execution-environment-detail',
}; };
export default ExecutionEnvironmentDetail; export default ExecutionEnvironmentDetail;

View File

@@ -124,6 +124,7 @@ function JobListItem({
<ReLaunchDropDown <ReLaunchDropDown
handleRelaunch={handleRelaunch} handleRelaunch={handleRelaunch}
isLaunching={isLaunching} isLaunching={isLaunching}
id={`relaunch-job-${job.id}`}
/> />
)} )}
</LaunchButton> </LaunchButton>
@@ -214,6 +215,7 @@ function JobListItem({
<ExecutionEnvironmentDetail <ExecutionEnvironmentDetail
executionEnvironment={execution_environment} executionEnvironment={execution_environment}
verifyMissingVirtualEnv={false} verifyMissingVirtualEnv={false}
dataCy={`execution-environment-detail-${job.id}`}
/> />
)} )}
{credentials && credentials.length > 0 && ( {credentials && credentials.length > 0 && (

View File

@@ -15,7 +15,7 @@ function ReLaunchDropDown({
isPrimary = false, isPrimary = false,
handleRelaunch, handleRelaunch,
isLaunching, isLaunching,
id = 'relaunch-job',
ouiaId, ouiaId,
}) { }) {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
@@ -75,7 +75,7 @@ function ReLaunchDropDown({
toggleIndicator={null} toggleIndicator={null}
onToggle={onToggle} onToggle={onToggle}
aria-label={t`relaunch jobs`} aria-label={t`relaunch jobs`}
id="relaunch_jobs" id={id}
isPrimary isPrimary
> >
{t`Relaunch`} {t`Relaunch`}
@@ -97,7 +97,7 @@ function ReLaunchDropDown({
toggleIndicator={null} toggleIndicator={null}
onToggle={onToggle} onToggle={onToggle}
aria-label={t`relaunch jobs`} aria-label={t`relaunch jobs`}
id="relaunch_jobs" id={id}
> >
<RocketIcon /> <RocketIcon />
</DropdownToggle> </DropdownToggle>

View File

@@ -20,6 +20,7 @@ const QS_CONFIG = getQSConfig('execution_environments', {
}); });
function ExecutionEnvironmentLookup({ function ExecutionEnvironmentLookup({
id,
globallyAvailable, globallyAvailable,
helperTextInvalid, helperTextInvalid,
isDefaultEnvironment, isDefaultEnvironment,
@@ -154,7 +155,7 @@ function ExecutionEnvironmentLookup({
const renderLookup = () => ( const renderLookup = () => (
<> <>
<Lookup <Lookup
id="execution-environments" id={id}
header={t`Execution Environment`} header={t`Execution Environment`}
value={value} value={value}
onBlur={onBlur} onBlur={onBlur}
@@ -213,7 +214,7 @@ function ExecutionEnvironmentLookup({
return ( return (
<FormGroup <FormGroup
fieldId="execution-environment-lookup" fieldId={id}
label={renderLabel(isGlobalDefaultEnvironment, isDefaultEnvironment)} label={renderLabel(isGlobalDefaultEnvironment, isDefaultEnvironment)}
labelIcon={popoverContent && <Popover content={popoverContent} />} labelIcon={popoverContent && <Popover content={popoverContent} />}
helperTextInvalid={helperTextInvalid} helperTextInvalid={helperTextInvalid}
@@ -231,6 +232,7 @@ function ExecutionEnvironmentLookup({
} }
ExecutionEnvironmentLookup.propTypes = { ExecutionEnvironmentLookup.propTypes = {
id: string,
value: ExecutionEnvironment, value: ExecutionEnvironment,
popoverContent: string, popoverContent: string,
onChange: func.isRequired, onChange: func.isRequired,
@@ -243,6 +245,7 @@ ExecutionEnvironmentLookup.propTypes = {
}; };
ExecutionEnvironmentLookup.defaultProps = { ExecutionEnvironmentLookup.defaultProps = {
id: 'execution-environments',
popoverContent: '', popoverContent: '',
isDefaultEnvironment: false, isDefaultEnvironment: false,
isGlobalDefaultEnvironment: false, isGlobalDefaultEnvironment: false,

View File

@@ -236,6 +236,7 @@ function InventoryLookup({
} }
InventoryLookup.propTypes = { InventoryLookup.propTypes = {
fieldId: string,
value: Inventory, value: Inventory,
onChange: func.isRequired, onChange: func.isRequired,
required: bool, required: bool,
@@ -247,6 +248,7 @@ InventoryLookup.propTypes = {
}; };
InventoryLookup.defaultProps = { InventoryLookup.defaultProps = {
fieldId: 'inventory',
value: null, value: null,
required: false, required: false,
isOverrideDisabled: false, isOverrideDisabled: false,

View File

@@ -128,7 +128,7 @@ function Lookup(props) {
<InputGroup onBlur={onBlur}> <InputGroup onBlur={onBlur}>
<Button <Button
aria-label={t`Search`} aria-label={t`Search`}
id={id} id={`${id}-open`}
onClick={() => dispatch({ type: 'TOGGLE_MODAL' })} onClick={() => dispatch({ type: 'TOGGLE_MODAL' })}
variant={ButtonVariant.control} variant={ButtonVariant.control}
isDisabled={isLoading || isDisabled} isDisabled={isLoading || isDisabled}
@@ -149,7 +149,7 @@ function Lookup(props) {
</ChipHolder> </ChipHolder>
) : ( ) : (
<TextInput <TextInput
id={`${id}-input`} id={id}
value={typedText} value={typedText}
onChange={(inputValue) => { onChange={(inputValue) => {
setTypedText(inputValue); setTypedText(inputValue);

View File

@@ -19,6 +19,7 @@ const QS_CONFIG = getQSConfig('organizations', {
}); });
function OrganizationLookup({ function OrganizationLookup({
id,
helperTextInvalid, helperTextInvalid,
isValid, isValid,
onBlur, onBlur,
@@ -94,7 +95,7 @@ function OrganizationLookup({
return ( return (
<FormGroup <FormGroup
fieldId="organization" fieldId={id}
helperTextInvalid={helperTextInvalid} helperTextInvalid={helperTextInvalid}
isRequired={required} isRequired={required}
validated={isValid ? 'default' : 'error'} validated={isValid ? 'default' : 'error'}
@@ -103,7 +104,7 @@ function OrganizationLookup({
> >
<Lookup <Lookup
isDisabled={isDisabled} isDisabled={isDisabled}
id="organization" id={id}
header={t`Organization`} header={t`Organization`}
value={value} value={value}
onBlur={onBlur} onBlur={onBlur}
@@ -158,6 +159,7 @@ function OrganizationLookup({
} }
OrganizationLookup.propTypes = { OrganizationLookup.propTypes = {
id: string,
helperTextInvalid: node, helperTextInvalid: node,
isValid: bool, isValid: bool,
onBlur: func, onBlur: func,
@@ -171,6 +173,7 @@ OrganizationLookup.propTypes = {
}; };
OrganizationLookup.defaultProps = { OrganizationLookup.defaultProps = {
id: 'organization',
helperTextInvalid: '', helperTextInvalid: '',
isValid: true, isValid: true,
onBlur: () => {}, onBlur: () => {},

View File

@@ -98,7 +98,7 @@ describe('<ApplicationAdd/>', () => {
wrapper.update(); wrapper.update();
expect(wrapper.find('input#name').prop('value')).toBe('new foo'); expect(wrapper.find('input#name').prop('value')).toBe('new foo');
expect(wrapper.find('input#description').prop('value')).toBe('new bar'); expect(wrapper.find('input#description').prop('value')).toBe('new bar');
expect(wrapper.find('input#organization-input').prop('value')).toBe( expect(wrapper.find('input#organization').prop('value')).toBe(
'organization' 'organization'
); );
expect( expect(

View File

@@ -88,6 +88,7 @@ describe('<ApplicationEdit/>', () => {
}); });
expect(wrapper.find('ApplicationEdit').length).toBe(1); expect(wrapper.find('ApplicationEdit').length).toBe(1);
}); });
test('should cancel form properly', async () => { test('should cancel form properly', async () => {
const history = createMemoryHistory({ const history = createMemoryHistory({
initialEntries: ['/applications/1/edit'], initialEntries: ['/applications/1/edit'],
@@ -110,6 +111,7 @@ describe('<ApplicationEdit/>', () => {
expect(history.location.pathname).toBe('/applications/1/details'); expect(history.location.pathname).toBe('/applications/1/details');
}); });
}); });
test('should throw error on submit', async () => { test('should throw error on submit', async () => {
const error = { const error = {
response: { response: {
@@ -147,6 +149,7 @@ describe('<ApplicationEdit/>', () => {
wrapper.update(); wrapper.update();
expect(wrapper.find('FormSubmitError').length).toBe(1); expect(wrapper.find('FormSubmitError').length).toBe(1);
}); });
test('expect values to be updated and submitted properly', async () => { test('expect values to be updated and submitted properly', async () => {
const history = createMemoryHistory({ const history = createMemoryHistory({
initialEntries: ['/applications/1/edit'], initialEntries: ['/applications/1/edit'],
@@ -188,7 +191,7 @@ describe('<ApplicationEdit/>', () => {
wrapper.update(); wrapper.update();
expect(wrapper.find('input#name').prop('value')).toBe('new foo'); expect(wrapper.find('input#name').prop('value')).toBe('new foo');
expect(wrapper.find('input#description').prop('value')).toBe('new bar'); expect(wrapper.find('input#description').prop('value')).toBe('new bar');
expect(wrapper.find('input#organization-input').prop('value')).toBe( expect(wrapper.find('input#organization').prop('value')).toBe(
'organization' 'organization'
); );
expect( expect(

View File

@@ -107,7 +107,7 @@ describe('<ApplicationForm', () => {
wrapper.update(); wrapper.update();
expect(wrapper.find('input#name').prop('value')).toBe('new foo'); expect(wrapper.find('input#name').prop('value')).toBe('new foo');
expect(wrapper.find('input#description').prop('value')).toBe('new bar'); expect(wrapper.find('input#description').prop('value')).toBe('new bar');
expect(wrapper.find('input#organization-input').prop('value')).toBe( expect(wrapper.find('input#organization').prop('value')).toBe(
'organization' 'organization'
); );
expect( expect(

View File

@@ -31,7 +31,7 @@ function TeamListItem({ team, isSelected, onSelect, detailUrl, rowIndex }) {
dataLabel={t`Selected`} dataLabel={t`Selected`}
/> />
<Td id={labelId} dataLabel={t`Name`}> <Td id={labelId} dataLabel={t`Name`}>
<Link id={labelId} to={`${detailUrl}`}> <Link to={`${detailUrl}`}>
<b>{team.name}</b> <b>{team.name}</b>
</Link> </Link>
</Td> </Td>

View File

@@ -339,9 +339,7 @@ describe('<JobTemplateEdit />', () => {
name: 'Other Inventory', name: 'Other Inventory',
}); });
wrapper.find('TextInput#execution-environments-input').invoke('onChange')( wrapper.find('TextInput#execution-environments').invoke('onChange')('');
''
);
}); });
wrapper.update(); wrapper.update();

View File

@@ -266,7 +266,7 @@ function JobTemplateForm({
/> />
</FieldWithPrompt> </FieldWithPrompt>
<FormGroup <FormGroup
fieldId="inventory-lookup" fieldId="template-inventory"
validated={ validated={
!(inventoryMeta.touched || askInventoryOnLaunchField.value) || !(inventoryMeta.touched || askInventoryOnLaunchField.value) ||
!inventoryMeta.error !inventoryMeta.error

View File

@@ -68,7 +68,7 @@ describe('<WebhookSubForm />', () => {
.find('TextInputBase[aria-label="workflow job template webhook key"]') .find('TextInputBase[aria-label="workflow job template webhook key"]')
.prop('value') .prop('value')
).toBe('webhook key'); ).toBe('webhook key');
expect(wrapper.find('input#credential-input').prop('value')).toBe( expect(wrapper.find('input#credential').prop('value')).toBe(
'Github credential' 'Github credential'
); );
}); });