fix(a11y): improve challenge test suite results accessibility (#45802)
Co-authored-by: moT01 <20648924+moT01@users.noreply.github.com>pull/46483/head
parent
0e6e103d32
commit
46450b802c
|
@ -457,7 +457,9 @@
|
|||
"donate": "Donate with PayPal",
|
||||
"fail": "Test Failed",
|
||||
"not-passed": "Not Passed",
|
||||
"waiting": "Waiting",
|
||||
"passed": "Passed",
|
||||
"failed": "Failed",
|
||||
"hint": "Hint",
|
||||
"heart": "Heart",
|
||||
"initial": "Initial",
|
||||
|
|
|
@ -3,6 +3,12 @@
|
|||
justify-content: flex-start;
|
||||
flex-direction: column;
|
||||
margin: 15px 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.challenge-test-suite-heading {
|
||||
font-size: 0.9em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.challenge-test-suite code {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import Fail from '../../../assets/icons/fail';
|
||||
import GreenPass from '../../../assets/icons/green-pass';
|
||||
|
@ -6,7 +7,6 @@ import Initial from '../../../assets/icons/initial';
|
|||
|
||||
import './test-suite.css';
|
||||
import { ChallengeTest, Test } from '../../../redux/prop-types';
|
||||
|
||||
type TestSuiteTest = {
|
||||
err?: string;
|
||||
pass?: boolean;
|
||||
|
@ -20,47 +20,39 @@ interface TestSuiteProps {
|
|||
tests: Test[];
|
||||
}
|
||||
|
||||
function getAccessibleText(text: string, err?: string, pass?: boolean) {
|
||||
let accessibleText = 'Waiting';
|
||||
const cleanText = text.replace(/<\/?code>/g, '');
|
||||
|
||||
// Determine test status (i.e. icon)
|
||||
if (err) {
|
||||
accessibleText = 'Error';
|
||||
} else if (pass) {
|
||||
accessibleText = 'Pass';
|
||||
}
|
||||
|
||||
// Append the text itself
|
||||
return accessibleText + ' - ' + cleanText;
|
||||
}
|
||||
|
||||
function TestSuite({ tests }: TestSuiteProps): JSX.Element {
|
||||
const { t } = useTranslation();
|
||||
const testSuiteTests = tests.filter(isTestSuiteTest);
|
||||
|
||||
return (
|
||||
<div className='challenge-test-suite'>
|
||||
{testSuiteTests.map(({ err, pass = false, text = '' }, index) => {
|
||||
const isInitial = !pass && !err;
|
||||
const statusIcon = pass && !err ? <GreenPass /> : <Fail />;
|
||||
return (
|
||||
<div
|
||||
aria-label={getAccessibleText(text, err, pass)}
|
||||
className='test-result'
|
||||
key={text.slice(-6) + String(index)}
|
||||
>
|
||||
<div className='test-status-icon'>
|
||||
{isInitial ? <Initial /> : statusIcon}
|
||||
</div>
|
||||
<div
|
||||
aria-hidden='true'
|
||||
className='test-output'
|
||||
dangerouslySetInnerHTML={{ __html: text }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<>
|
||||
<h2 className='challenge-test-suite-heading'>Tests</h2>
|
||||
<ul className='challenge-test-suite'>
|
||||
{testSuiteTests.map(({ err, pass = false, text = '' }, index) => {
|
||||
const isInitial = !pass && !err;
|
||||
const statusIcon = pass && !err ? <GreenPass /> : <Fail />;
|
||||
const initialText = t('icons.waiting');
|
||||
const statusText =
|
||||
pass && !err ? t('icons.passed') : t('icons.failed');
|
||||
// Remove opening/closing <p> so screen reader will read both
|
||||
// status message and test text as one block.
|
||||
text = text.replace(/^<p>|<\/p>$/g, '');
|
||||
return (
|
||||
<li className='test-result' key={text.slice(-6) + String(index)}>
|
||||
<div className='test-status-icon' aria-hidden='true'>
|
||||
{isInitial ? <Initial /> : statusIcon}
|
||||
</div>
|
||||
<div className='test-output'>
|
||||
<span className='sr-only'>
|
||||
{isInitial ? initialText : statusText}:{' '}
|
||||
</span>
|
||||
<span dangerouslySetInnerHTML={{ __html: text }} />
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,11 +8,13 @@ describe('Help Button', () => {
|
|||
|
||||
it('should toggle the dropdown menu', () => {
|
||||
cy.get('#get-help-dropdown').scrollIntoView().click();
|
||||
cy.get('ul[role="menu"]').should('be.visible');
|
||||
cy.get('.tool-panel-group ul[role="menu"]')
|
||||
.scrollIntoView()
|
||||
.should('be.visible');
|
||||
});
|
||||
|
||||
it('should render three links when video is available', () => {
|
||||
cy.get('ul[role="menu"]').within(() => {
|
||||
cy.get('.tool-panel-group ul[role="menu"]').within(() => {
|
||||
cy.get('a').should('have.length', 3);
|
||||
cy.get('a').eq(0).contains('Get a Hint');
|
||||
cy.get('a').eq(1).contains('Watch a Video');
|
||||
|
@ -25,7 +27,7 @@ describe('Help Button', () => {
|
|||
'/learn/front-end-development-libraries/bootstrap/apply-the-default-bootstrap-button-style'
|
||||
);
|
||||
cy.get('#get-help-dropdown').scrollIntoView().click();
|
||||
cy.get('ul[role="menu"]').within(() => {
|
||||
cy.get('.tool-panel-group ul[role="menu"]').within(() => {
|
||||
cy.get('a').should('have.length', 2);
|
||||
cy.get('a').eq(0).contains('Get a Hint');
|
||||
cy.get('a').eq(1).contains('Ask for Help');
|
||||
|
|
Loading…
Reference in New Issue