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

[terra-table] Fixed screenreader issue due to space in headers attribute #1889

Merged
merged 4 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading