Skip to content
This repository has been archived by the owner on May 24, 2024. It is now read-only.

Commit

Permalink
[terra-table] Fixed screenreader issue due to space in headers attrib…
Browse files Browse the repository at this point in the history
…ute (#1889)
  • Loading branch information
cm9361 authored Nov 15, 2023
1 parent 464dfb3 commit e9979bd
Show file tree
Hide file tree
Showing 9 changed files with 1,674 additions and 18,101 deletions.
2 changes: 1 addition & 1 deletion packages/terra-data-grid/tests/jest/DataGrid.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ describe('DataGrid', () => {
expect(rowComponent.key).toEqual(data.id);
expect(rowComponent.props.onCellSelect).toBeDefined();
expect(rowComponent.props.rowHeaderIndex).toEqual(0);
expect(rowComponent.props.rowIndex).toEqual(rowIndex + 1);
expect(rowComponent.props.rowIndex).toEqual(rowIndex + 2);
expect(rowComponent.props.cells).toEqual(data.cells);
};

Expand Down
490 changes: 245 additions & 245 deletions packages/terra-data-grid/tests/jest/__snapshots__/DataGrid.test.jsx.snap

Large diffs are not rendered by default.

2,270 changes: 1,135 additions & 1,135 deletions packages/terra-data-grid/tests/jest/__snapshots__/WorklistDataGrid.test.jsx.snap

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/terra-table/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

* Fixed
* Fixed tab index issues in the column header cells.
* Fixed screenreader issue due to space in the headers attribute.

## 5.1.1-alpha.1 - (November 9, 2023)

Expand Down
2 changes: 1 addition & 1 deletion packages/terra-table/src/Table.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ function Table(props) {
}

// eslint-disable-next-line no-param-reassign
currentSection.sectionRowIndex = 0;
currentSection.sectionRowIndex = rowCount;
return rowCount + currentSection.rows.length;
};
const tableRowCount = tableSections.reduce(tableSectionReducer, 1);
Expand Down
10 changes: 5 additions & 5 deletions packages/terra-table/src/subcomponents/Cell.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ function Cell(props) {
const onMouseDown = ((event) => {
if (!isFocusTrapEnabled) {
onCellSelect({
sectionId, rowId, rowIndex, columnId, columnIndex, isShiftPressed: event.shiftKey, isCellSelectable: (!isMasked && isSelectable),
sectionId, rowId, rowIndex: (rowIndex - 1), columnId, columnIndex, isShiftPressed: event.shiftKey, isCellSelectable: (!isMasked && isSelectable),
});
}
});
Expand Down Expand Up @@ -234,7 +234,7 @@ function Cell(props) {
case KeyCode.KEY_SPACE:
if (onCellSelect) {
onCellSelect({
sectionId, rowId, rowIndex, columnId, columnIndex, isShiftPressed: event.shiftKey, isCellSelectable: (!isMasked && isSelectable),
sectionId, rowId, rowIndex: (rowIndex - 1), columnId, columnIndex, isShiftPressed: event.shiftKey, isCellSelectable: (!isMasked && isSelectable),
});
}

Expand Down Expand Up @@ -296,8 +296,8 @@ function Cell(props) {
}

// Determine table cell header attribute values
const sectionHeaderId = sectionId ? `${tableId}-${sectionId}` : '';
const rowHeaderId = !isRowHeader ? `${tableId}-rowheader-${rowId}` : '';
const sectionHeaderId = sectionId ? `${tableId}-${sectionId} ` : '';
const rowHeaderId = !isRowHeader ? `${tableId}-rowheader-${rowId} ` : '';
const columnHeaderId = `${tableId}-${columnId}`;

return (
Expand All @@ -306,7 +306,7 @@ function Cell(props) {
ref={isGridContext ? cellRef : undefined}
aria-selected={isSelected || undefined}
aria-label={ariaLabel}
headers={`${sectionHeaderId} ${rowHeaderId} ${columnHeaderId}`}
headers={`${sectionHeaderId}${rowHeaderId}${columnHeaderId}`}
tabIndex={isGridContext ? -1 : undefined}
className={className}
{...(isRowHeader && { scope: 'row', role: 'rowheader' })}
Expand Down
229 changes: 209 additions & 20 deletions packages/terra-table/tests/jest/Table.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { v4 as uuidv4 } from 'uuid';

import ColumnHeader from '../../src/subcomponents/ColumnHeader';
import ColumnHeaderCell from '../../src/subcomponents/ColumnHeaderCell';
import Section from '../../src/subcomponents/Section';
import GridContext, { GridConstants } from '../../src/utils/GridContext';
import ERRORS from '../../src/utils/constants';
import Row from '../../src/subcomponents/Row';
Expand Down Expand Up @@ -56,6 +57,78 @@ const tableData = {
],
};

const tableSectionData = {
cols: [
{
id: 'Column-0', displayName: 'Patient', sortIndicator: 'ascending', isSelectable: true,
},
{
id: 'Column-1', displayName: 'Location', isSelectable: true,
},
{ id: 'Column-2', displayName: 'Illness Severity', isSelectable: true },
{ id: 'Column-3', displayName: 'Visit' },
{ id: 'Column-4', displayName: 'Allergy' },
{ id: 'Column-5', displayName: 'Primary Contact' },

],
sections: [{
id: 'section-0',
text: 'Test Section',
rows: [
{
id: '1',
cells: [
{ content: 'Fleck, Arthur' },
{ content: '1007-MTN' },
{ content: 'Unstable' },
{ content: 'Inpatient, 2 months' },
{ content: '' },
{ content: 'Quinzell, Harleen' },
],
},
{
id: '2',
cells: [
{ content: 'Wayne, Bruce' },
{ content: '1007-MTN-DR' },
{ content: 'Stable' },
{ content: 'Outpatient, 2 days' },
{ content: 'Phytochemicals' },
{ content: 'Grayson, Richard' },
],
},
],
},
{
id: 'section-1',
text: 'Test Section #2',
rows: [
{
id: '3',
cells: [
{ content: 'Parker, Peter' },
{ content: '1007-MTN' },
{ content: 'Unstable' },
{ content: 'Inpatient, 2 months' },
{ content: '' },
{ content: 'Octopus, Doctor' },
],
},
{
id: '4',
cells: [
{ content: 'Stark, Tony' },
{ content: '1007-MTN-DR' },
{ content: 'Stable' },
{ content: 'Outpatient, 2 days' },
{ content: 'Phytochemicals' },
{ content: 'America, Captain' },
],
},
],
}],
};

let mockSpyUuid;
beforeAll(() => {
jest.spyOn(console, 'error').mockImplementation();
Expand Down Expand Up @@ -107,17 +180,151 @@ describe('Table', () => {
);

// Find column headers
const columnHeader = wrapper.find(ColumnHeaderCell);
const columnHeaderCell = wrapper.find(ColumnHeaderCell).at(0);
expect(columnHeaderCell.props().id).toBe('table-rowSelectionColumn');

// Simulate onMouseDown event on row selection column header
columnHeader.at(0).simulate('mouseDown');
columnHeaderCell.simulate('mouseDown');

// Validate mock function was called from simulated click event
expect(mockColumnSelect).not.toHaveBeenCalled();

expect(wrapper).toMatchSnapshot();
});

it('verifies ARIA attributes for a table with sections', () => {
const wrapper = mountWithIntl(
<Table
id="test-terra-table"
overflowColumns={tableSectionData.cols}
sections={tableSectionData.sections}
/>,
);

// Validate table properties
const table = wrapper.find('table');
expect(table.props().id).toBe('test-terra-table');
expect(table.props().role).toBe('table');
expect(table.props()['aria-rowcount']).toBe(7);

// Validate column header id attribute
const columnHeaderCell = wrapper.find('.column-header').at(0);
expect(columnHeaderCell.props().id).toBe('test-terra-table-Column-0');

// Retrieve first section
const tableSections = wrapper.find(Section);
const section1 = tableSections.at(0);

// Validate section header row of the first section
const section1HeaderRow = section1.find('.header');
expect(section1HeaderRow.props()['aria-rowindex']).toBe(2);

// Validate table header element of the first section
const sectionHeader1 = section1HeaderRow.find('th');
expect(sectionHeader1.props().id).toBe('test-terra-table-section-0');
expect(sectionHeader1.props().colSpan).toBe(tableSectionData.cols.length);
expect(sectionHeader1.props().scope).toBe('col');

// Validate rows of the first section
const section1Row1 = section1.find('.row').at(0);
expect(section1Row1.props()['aria-rowindex']).toBe(3);
expect(section1Row1.props()['data-row-id']).toBe('1');
const section1Row2 = section1.find('.row').at(1);
expect(section1Row2.props()['aria-rowindex']).toBe(4);
expect(section1Row2.props()['data-row-id']).toBe('2');

// Validate cells of the first row
const row1Cell1 = section1Row1.find('.cell').at(0);
expect(row1Cell1.props().headers).toBe('test-terra-table-section-0 test-terra-table-Column-0');
expect(row1Cell1.props().id).toBe('test-terra-table-rowheader-1');
const row1Cell2 = section1Row1.find('.cell').at(1);
expect(row1Cell2.props().headers).toBe('test-terra-table-section-0 test-terra-table-rowheader-1 test-terra-table-Column-1');

// Retrieve second section
const section2 = tableSections.at(1);

// Validate section header row of the second section
const section2HeaderRow = section2.find('.header');
expect(section2HeaderRow.props()['aria-rowindex']).toBe(5);

// Validate table header element of the second section
const sectionHeader2 = section2HeaderRow.find('th');
expect(sectionHeader2.props().id).toBe('test-terra-table-section-1');
expect(sectionHeader2.props().colSpan).toBe(tableSectionData.cols.length);
expect(sectionHeader2.props().scope).toBe('col');

// Validate rows of the second section
const section2Row1 = section2.find('.row').at(0);
expect(section2Row1.props()['aria-rowindex']).toBe(6);
expect(section2Row1.props()['data-row-id']).toBe('3');
const section2Row2 = section2.find('.row').at(1);
expect(section2Row2.props()['aria-rowindex']).toBe(7);
expect(section2Row2.props()['data-row-id']).toBe('4');

// Validate cells of the first row
const section2Row1Cell1 = section2Row1.find('.cell').at(0);
expect(section2Row1Cell1.props().headers).toBe('test-terra-table-section-1 test-terra-table-Column-0');
expect(section2Row1Cell1.props().id).toBe('test-terra-table-rowheader-3');
const section2Row1Cell2 = section2Row1.find('.cell').at(1);
expect(section2Row1Cell2.props().headers).toBe('test-terra-table-section-1 test-terra-table-rowheader-3 test-terra-table-Column-1');
});

it('verifies ARIA attributes for a table without sections', () => {
const wrapper = mountWithIntl(
<Table
id="test-terra-table"
overflowColumns={tableSectionData.cols}
rows={tableData.rows}
/>,
);

// Validate table properties
const table = wrapper.find('table');
expect(table.props().id).toBe('test-terra-table');
expect(table.props().role).toBe('table');
expect(table.props()['aria-rowcount']).toBe(5);

// Validate column header id attribute
const columnHeaderCell = wrapper.find('.column-header').at(0);
expect(columnHeaderCell.props().id).toBe('test-terra-table-Column-0');

// Retrieve first section
const tableSections = wrapper.find(Section);
const section1 = tableSections.at(0);

// Validate section header row of the first section
const section1HeaderRow = section1.find('.header');
expect(section1HeaderRow).toHaveLength(0);

// Validate rows of the first section
const row1 = section1.find('.row').at(0);
expect(row1.props()['aria-rowindex']).toBe(2);
expect(row1.props()['data-row-id']).toBe('1');
const row2 = section1.find('.row').at(1);
expect(row2.props()['aria-rowindex']).toBe(3);
expect(row2.props()['data-row-id']).toBe('2');
const row3 = section1.find('.row').at(2);
expect(row3.props()['aria-rowindex']).toBe(4);
expect(row3.props()['data-row-id']).toBe('3');
const row4 = section1.find('.row').at(3);
expect(row4.props()['aria-rowindex']).toBe(5);
expect(row4.props()['data-row-id']).toBe('4');

// Validate cells of the first row
const row1Cell1 = row1.find('.cell').at(0);
expect(row1Cell1.props().headers).toBe('test-terra-table-Column-0');
expect(row1Cell1.props().id).toBe('test-terra-table-rowheader-1');
const row1Cell2 = row1.find('.cell').at(1);
expect(row1Cell2.props().headers).toBe('test-terra-table-rowheader-1 test-terra-table-Column-1');

// Validate cells of the second row
const row2Cell1 = row2.find('.cell').at(0);
expect(row2Cell1.props().headers).toBe('test-terra-table-Column-0');
expect(row2Cell1.props().id).toBe('test-terra-table-rowheader-2');
const row2Cell2 = row2.find('.cell').at(1);
expect(row2Cell2.props().headers).toBe('test-terra-table-rowheader-2 test-terra-table-Column-1');
});

it('verifies row selection column header not selectable without callback', () => {
const mockColumnSelect = jest.fn();

Expand All @@ -140,8 +347,6 @@ describe('Table', () => {

// Validate mock function was called from simulated click event
expect(mockColumnSelect).toHaveBeenCalled();

expect(wrapper).toMatchSnapshot();
});

it('verifies onCellSelect callback is triggered when space is pressed on a masked cell', () => {
Expand All @@ -168,8 +373,6 @@ describe('Table', () => {

// Validate mock function was called from simulated click event
expect(mockCellSelect).toHaveBeenCalled();

expect(wrapper).toMatchSnapshot();
});

it('verifies onCellSelect callback is triggered when space is pressed on a non-selectable cell', () => {
Expand All @@ -196,8 +399,6 @@ describe('Table', () => {

// Validate mock function was called from simulated click event
expect(mockCellSelect).toHaveBeenCalled();

expect(wrapper).toMatchSnapshot();
});

it('verifies that the column widths are set properly in the colgroup', () => {
Expand All @@ -215,8 +416,6 @@ describe('Table', () => {
// Verify that column headers are not present
const column = wrapper.find('col').get(0);
expect(column.props.style.width).toBe('150px');

expect(wrapper).toMatchSnapshot();
});
});

Expand Down Expand Up @@ -301,8 +500,6 @@ describe('Row Selection', () => {

const hiddenText = wrapper.find('VisuallyHiddenText').at(1);
expect(hiddenText.props().text).toBe('Terra.table.row-selection-template');

expect(wrapper).toMatchSnapshot();
});

it('verifies row selection row unselected update', () => {
Expand Down Expand Up @@ -331,8 +528,6 @@ describe('Row Selection', () => {

const hiddenText = wrapper.find('VisuallyHiddenText').at(1);
expect(hiddenText.props().text).toBe('Terra.table.row-selection-cleared-template');

expect(wrapper).toMatchSnapshot();
});

it('verifies row selection all row selection single selction', () => {
Expand Down Expand Up @@ -360,8 +555,6 @@ describe('Row Selection', () => {

const hiddenText = wrapper.find('VisuallyHiddenText').at(1);
expect(hiddenText.props().text).toBe('Terra.table.all-rows-selected');

expect(wrapper).toMatchSnapshot();
});

it('verifies row selection all rows unselected update', () => {
Expand All @@ -380,8 +573,6 @@ describe('Row Selection', () => {

const hiddenText = wrapper.find('VisuallyHiddenText').at(1);
expect(hiddenText.props().text).toBe('Terra.table.all-rows-unselected');

expect(wrapper).toMatchSnapshot();
});

it('verifies row selection all rows unselected single unselect', () => {
Expand All @@ -404,8 +595,6 @@ describe('Row Selection', () => {

const hiddenText = wrapper.find('VisuallyHiddenText').at(1);
expect(hiddenText.props().text).toBe('Terra.table.all-rows-unselected');

expect(wrapper).toMatchSnapshot();
});
});

Expand Down
Loading

0 comments on commit e9979bd

Please sign in to comment.