Skip to content

Commit 1a5ae39

Browse files
committed
feat: Updated Courseware Search results for SR
1 parent 7ea0bd1 commit 1a5ae39

7 files changed

+584
-422
lines changed

Diff for: src/course-home/courseware-search/CoursewareResultsFilter.jsx

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export const CoursewareSearchResultsFilter = ({ intl }) => {
6363
variant="tabs"
6464
activeKey={activeKey}
6565
onSelect={setFilter}
66+
aria-label={intl.formatMessage(messages.searchResultsFilterDescription)}
6667
>
6768
{filters.filter(({ count }) => (count > 0)).map(({ key, label }) => (
6869
<Tab key={key} eventKey={key} title={label} data-testid={`courseware-search-results-tabs-${key}`}>

Diff for: src/course-home/courseware-search/CoursewareSearch.jsx

+9-3
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,15 @@ const CoursewareSearch = ({ ...sectionProps }) => {
141141
</Button>
142142
</div>
143143
</div>
144-
<div className="courseware-search__results" aria-live="polite" data-testid="courseware-search-results">
144+
<div
145+
key={status}
146+
className="courseware-search__results"
147+
aria-live="assertive"
148+
aria-atomic="true"
149+
aria-busy={status === 'loading'}
150+
data-testid="courseware-search-results"
151+
role={status === 'results' ? 'alert' : 'none'}
152+
>
145153
{status === 'loading' ? (
146154
<div className="courseware-search__spinner" data-testid="courseware-search-spinner">
147155
<Spinner animation="border" variant="light" screenReaderText={formatMessage(messages.loading)} />
@@ -157,8 +165,6 @@ const CoursewareSearch = ({ ...sectionProps }) => {
157165
{total > 0 ? (
158166
<div
159167
className="courseware-search__results-summary"
160-
aria-relevant="all"
161-
aria-atomic="true"
162168
data-testid="courseware-search-summary"
163169
>{formatMessage(messages.searchResultsLabel, { total, keyword: lastSearchKeyword })}
164170
</div>

Diff for: src/course-home/courseware-search/CoursewareSearch.test.jsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ describe('CoursewareSearch', () => {
244244
expect(screen.queryByTestId('courseware-search-summary')).not.toBeInTheDocument();
245245
});
246246

247-
it('should show a summary for the results within a container with aria-live="polite"', () => {
247+
it('should show a wrapper div with proper aria attributes', () => {
248248
mockModels({
249249
searchKeyword: 'fubar',
250250
total: 1,
@@ -253,7 +253,9 @@ describe('CoursewareSearch', () => {
253253

254254
const results = screen.queryByTestId('courseware-search-results');
255255

256-
expect(results).toHaveAttribute('aria-live', 'polite');
256+
expect(results).toHaveAttribute('aria-live', 'assertive');
257+
expect(results).toHaveAttribute('aria-atomic', 'true');
258+
expect(results).toHaveAttribute('role', 'alert');
257259
expect(within(results).queryByTestId('courseware-search-summary').textContent).toBe('Results for "fubar":');
258260
});
259261
});

Diff for: src/course-home/courseware-search/CoursewareSearchResults.jsx

+17-8
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import React from 'react';
1+
import { useIntl } from '@edx/frontend-platform/i18n';
22
import {
33
Folder, TextFields, VideoCamera, Article,
44
} from '@openedx/paragon/icons';
55
import { getConfig } from '@edx/frontend-platform';
66
import { Icon } from '@openedx/paragon';
77
import PropTypes from 'prop-types';
88
import CoursewareSearchEmpty from './CoursewareSearchEmpty';
9+
import messages from './messages';
910

1011
const iconTypeMapping = {
1112
text: TextFields,
@@ -21,6 +22,8 @@ const CoursewareSearchResults = ({ results = [] }) => {
2122
return <CoursewareSearchEmpty />;
2223
}
2324

25+
const { formatMessage } = useIntl();
26+
2427
const baseUrl = `${getConfig().LMS_BASE_URL}`;
2528

2629
return (
@@ -42,24 +45,30 @@ const CoursewareSearchResults = ({ results = [] }) => {
4245
rel: 'nofollow',
4346
} : { href: `${baseUrl}${url}` };
4447

48+
const ariaSeaparator = formatMessage(messages.searchResultsBreadcrumbSeparator);
49+
const ariaLocation = location?.length ? formatMessage(messages.searchResultsBreadcrumb, { path: location.join(ariaSeaparator) }) : '';
50+
4551
return (
4652
<a key={id} className="courseware-search-results__item" {...linkProps}>
4753
<div className="courseware-search-results__icon"><Icon src={icon} /></div>
4854
<div className="courseware-search-results__info">
4955
<div className="courseware-search-results__title">
50-
<span>{title}</span>
51-
{contentHits ? (<em>{contentHits}</em>) : null }
56+
<h3>{title}</h3>
57+
{contentHits ? (<em aria-hidden="true">{contentHits}</em>) : null }
5258
</div>
53-
{location?.length ? (
54-
<ul className="courseware-search-results__breadcrumbs">
55-
{
59+
60+
<div aria-label={ariaLocation}>
61+
{location?.length ? (
62+
<ul className="courseware-search-results__breadcrumbs" aria-hidden="true">
63+
{
5664
// This ignore is necessary because the breadcrumb texts might have duplicates.
5765
// The breadcrumbs are not expected to change.
5866
// eslint-disable-next-line react/no-array-index-key
5967
location.map((breadcrumb, i) => (<li key={`${i}:${breadcrumb}`}><div>{breadcrumb}</div></li>))
6068
}
61-
</ul>
62-
) : null}
69+
</ul>
70+
) : null}
71+
</div>
6372
</div>
6473
</a>
6574
);

0 commit comments

Comments
 (0)