diff --git a/lib/core/datatable/components/datatable/datatable.component.html b/lib/core/datatable/components/datatable/datatable.component.html index fb2cfd4238..61b17b3d65 100644 --- a/lib/core/datatable/components/datatable/datatable.component.html +++ b/lib/core/datatable/components/datatable/datatable.component.html @@ -1,10 +1,11 @@
-
-
+
+
Actions @@ -21,7 +22,7 @@ [class.adf-data-table__header--sorted-desc]="isColumnSorted(col, 'desc')" (click)="onColumnHeaderClick(col)" (keyup.enter)="onColumnHeaderClick(col)" - role="button" + role="columnheader" tabindex="0" title="{{ col.title | translate }}"> {{ col.srTitle | translate }} @@ -45,18 +46,18 @@
-
+
-
+
+
\ No newline at end of file diff --git a/lib/core/datatable/components/datatable/datatable.component.spec.ts b/lib/core/datatable/components/datatable/datatable.component.spec.ts index 42a89a01d6..406854dfdd 100644 --- a/lib/core/datatable/components/datatable/datatable.component.spec.ts +++ b/lib/core/datatable/components/datatable/datatable.component.spec.ts @@ -32,12 +32,15 @@ import { DataColumnComponent } from '../../../data-column/data-column.component' class FakeDataRow implements DataRow { isDropTarget = false; isSelected = true; + hasValue(key: any) { return true; } + getValue() { return '1'; } + imageErrorResolver() { return './assets/images/ft_ic_miscellaneous.svg'; } @@ -53,7 +56,7 @@ describe('DataTable', () => { imports: [ CoreTestingModule ], - schemas: [ NO_ERRORS_SCHEMA ] + schemas: [NO_ERRORS_SCHEMA] }); beforeEach(() => { @@ -69,7 +72,7 @@ describe('DataTable', () => { it('should preserve the historical selection order', () => { dataTable.data = new ObjectDataTableAdapter( [{ id: 0 }, { id: 1 }, { id: 2 }], - [ new ObjectDataColumn({ key: 'id' })] + [new ObjectDataColumn({ key: 'id' })] ); const rows = dataTable.data.getRows(); @@ -200,7 +203,7 @@ describe('DataTable', () => { { name: '1' }, { name: '2' } ], - [ column ] + [column] ); dataTable.data.setSorting(new DataSorting('name', 'desc')); @@ -270,7 +273,7 @@ describe('DataTable', () => { { name: 'test3' }, { name: 'test4' } ]; - dataTable.sorting = [ 'dummyName', 'asc' ]; + dataTable.sorting = ['dummyName', 'asc']; dataTable.ngOnChanges({ rows: new SimpleChange(null, dataRows, false) }); @@ -287,7 +290,7 @@ describe('DataTable', () => { { name: '1' }, { name: '2' } ], - [ new ObjectDataColumn({ key: 'name'}) ] + [new ObjectDataColumn({ key: 'name' })] ); const rows = dataTable.data.getRows(); rows[0].isSelected = true; @@ -305,10 +308,10 @@ describe('DataTable', () => { it('should select the row where isSelected is true', () => { dataTable.rows = [ - { name: 'TEST1' }, - { name: 'FAKE2' }, - { name: 'TEST2', isSelected : true }, - { name: 'FAKE2' }]; + { name: 'TEST1' }, + { name: 'FAKE2' }, + { name: 'TEST2', isSelected: true }, + { name: 'FAKE2' }]; dataTable.data = new ObjectDataTableAdapter([], [new ObjectDataColumn({ key: 'name' })] ); @@ -395,7 +398,7 @@ describe('DataTable', () => { { name: '1' }, { name: '2' } ], - [ new ObjectDataColumn({ key: 'name'}) ] + [new ObjectDataColumn({ key: 'name' })] ); const rows = dataTable.data.getRows(); @@ -416,7 +419,7 @@ describe('DataTable', () => { { name: '1' }, { name: '2' } ], - [ new ObjectDataColumn({ key: 'name'}) ] + [new ObjectDataColumn({ key: 'name' })] ); const rows = dataTable.data.getRows(); @@ -467,7 +470,10 @@ describe('DataTable', () => { done(); }); - dataTable.onRowClick(rows[0], { metaKey: true, preventDefault() { } }); + dataTable.onRowClick(rows[0], { + metaKey: true, preventDefault() { + } + }); }); it('should select multiple rows with [multiple] selection mode and modifier key', (done) => { @@ -535,7 +541,7 @@ describe('DataTable', () => { it('should initialize default adapter', () => { let table = new DataTableComponent(null, null); expect(table.data).toBeUndefined(); - table.ngOnChanges({'data': new SimpleChange('123', {}, true)}); + table.ngOnChanges({ 'data': new SimpleChange('123', {}, true) }); expect(table.data).toEqual(jasmine.any(ObjectDataTableAdapter)); }); @@ -563,7 +569,7 @@ describe('DataTable', () => { let row = {}; dataTable.ngOnChanges({}); - dataTable.rowDblClick.subscribe( () => { + dataTable.rowDblClick.subscribe(() => { done(); }); @@ -580,7 +586,7 @@ describe('DataTable', () => { let row = {}; dataTable.ngOnChanges({}); - dataTable.rowDblClick.subscribe( () => { + dataTable.rowDblClick.subscribe(() => { done(); }); @@ -601,7 +607,7 @@ describe('DataTable', () => { dataTable.ngOnChanges({}); - dataTable.rowClick.subscribe( () => { + dataTable.rowClick.subscribe(() => { clickCount += 1; if (clickCount === 2) { done(); @@ -655,7 +661,7 @@ describe('DataTable', () => { }); it('should not sort if column is missing', () => { - dataTable.ngOnChanges({'data': new SimpleChange('123', {}, true)}); + dataTable.ngOnChanges({ 'data': new SimpleChange('123', {}, true) }); let adapter = dataTable.data; spyOn(adapter, 'setSorting').and.callThrough(); dataTable.onColumnHeaderClick(null); @@ -663,7 +669,7 @@ describe('DataTable', () => { }); it('should not sort upon clicking non-sortable column header', () => { - dataTable.ngOnChanges({'data': new SimpleChange('123', {}, true)}); + dataTable.ngOnChanges({ 'data': new SimpleChange('123', {}, true) }); let adapter = dataTable.data; spyOn(adapter, 'setSorting').and.callThrough(); @@ -676,7 +682,7 @@ describe('DataTable', () => { }); it('should set sorting upon column header clicked', () => { - dataTable.ngOnChanges({'data': new SimpleChange('123', {}, true)}); + dataTable.ngOnChanges({ 'data': new SimpleChange('123', {}, true) }); let adapter = dataTable.data; spyOn(adapter, 'setSorting').and.callThrough(); @@ -695,7 +701,7 @@ describe('DataTable', () => { }); it('should invert sorting upon column header clicked', () => { - dataTable.ngOnChanges({'data': new SimpleChange('123', {}, true)}); + dataTable.ngOnChanges({ 'data': new SimpleChange('123', {}, true) }); let adapter = dataTable.data; let sorting = new DataSorting('column_1', 'asc'); @@ -742,7 +748,7 @@ describe('DataTable', () => { dataTable.data = data; dataTable.multiselect = true; dataTable.ngAfterContentInit(); - dataTable.onSelectAllClick( { checked: true }); + dataTable.onSelectAllClick( {checked: true }); expect(dataTable.selection.every((entry) => entry.isSelected)); @@ -760,13 +766,13 @@ describe('DataTable', () => { dataTable.multiselect = true; dataTable.ngAfterContentInit(); - dataTable.onSelectAllClick( { checked: true }); + dataTable.onSelectAllClick( {checked: true }); expect(dataTable.isSelectAllChecked).toBe(true); for (let i = 0; i < rows.length; i++) { expect(rows[i].isSelected).toBe(true); } - dataTable.onSelectAllClick( { checked: false }); + dataTable.onSelectAllClick( {checked: false }); expect(dataTable.isSelectAllChecked).toBe(false); for (let i = 0; i < rows.length; i++) { expect(rows[i].isSelected).toBe(false); @@ -775,9 +781,9 @@ describe('DataTable', () => { it('should allow "select all" calls with no rows', () => { dataTable.multiselect = true; - dataTable.ngOnChanges({'data': new SimpleChange('123', {}, true)}); + dataTable.ngOnChanges({ 'data': new SimpleChange('123', {}, true) }); - dataTable.onSelectAllClick( { checked: true }); + dataTable.onSelectAllClick( {checked: true }); expect(dataTable.isSelectAllChecked).toBe(true); }); @@ -789,7 +795,7 @@ describe('DataTable', () => { dataTable.multiselect = false; dataTable.ngAfterContentInit(); - dataTable.onSelectAllClick( { checked: true }); + dataTable.onSelectAllClick( {checked: true }); expect(dataTable.isSelectAllChecked).toBe(true); for (let i = 0; i < rows.length; i++) { expect(rows[i].isSelected).toBe(false); @@ -863,16 +869,16 @@ describe('DataTable', () => { }); it('should require adapter sorting to evaluate sorting state', () => { - dataTable.ngOnChanges({'data': new SimpleChange('123', {}, true)}); + dataTable.ngOnChanges({ 'data': new SimpleChange('123', {}, true) }); spyOn(dataTable.data, 'getSorting').and.returnValue(null); expect(dataTable.isColumnSorted( {}, 'asc')).toBeFalsy(); }); it('should evaluate column sorting state', () => { - dataTable.ngOnChanges({'data': new SimpleChange('123', {}, true)}); + dataTable.ngOnChanges({ 'data': new SimpleChange('123', {}, true) }); spyOn(dataTable.data, 'getSorting').and.returnValue(new DataSorting('column_1', 'asc')); - expect(dataTable.isColumnSorted( {key: 'column_1'}, 'asc')).toBeTruthy(); - expect(dataTable.isColumnSorted( {key: 'column_2'}, 'desc')).toBeFalsy(); + expect(dataTable.isColumnSorted( { key: 'column_1' }, 'asc')).toBeTruthy(); + expect(dataTable.isColumnSorted( { key: 'column_2' }, 'desc')).toBeFalsy(); }); it('should replace image source with fallback thumbnail on error', () => { @@ -897,7 +903,7 @@ describe('DataTable', () => { const row = new FakeDataRow(); dataTable.fallbackThumbnail = null; dataTable.onImageLoadingError(event, row); - expect(event.target.src).toBe('./assets/images/ft_ic_miscellaneous.svg' ); + expect(event.target.src).toBe('./assets/images/ft_ic_miscellaneous.svg'); }); it('should not get cell tooltip when row is not provided', () => { @@ -921,7 +927,7 @@ describe('DataTable', () => { const col = { key: 'name', type: 'text', - formatTooltip: () => tooltip + formatTooltip: () => tooltip }; const row = {}; expect(dataTable.getCellTooltip(row, col)).toBe(tooltip); @@ -931,7 +937,7 @@ describe('DataTable', () => { const col = { key: 'name', type: 'text', - formatTooltip: () => null + formatTooltip: () => null }; const row = {}; expect(dataTable.getCellTooltip(row, col)).toBeNull(); @@ -939,15 +945,78 @@ describe('DataTable', () => { it('should reset the menu cache after rows change', () => { let emitted = 0; - dataTable.showRowActionsMenu.subscribe(() => { emitted++; }); + dataTable.showRowActionsMenu.subscribe(() => { + emitted++; + }); const column = {}; - const row = { getValue: function (key: string) { return 'id'; } }; + const row = { + getValue: function (key: string) { + return 'id'; + } + }; dataTable.getRowActions(row, column); - dataTable.ngOnChanges({'data': new SimpleChange('123', {}, true)}); + dataTable.ngOnChanges({ 'data': new SimpleChange('123', {}, true) }); dataTable.getRowActions(row, column); expect(emitted).toBe(2); }); }); + +describe('Accesibility', () => { + + let fixture: ComponentFixture; + let dataTable: DataTableComponent; + let element: any; + + setupTestBed({ + imports: [ + CoreTestingModule + ], + schemas: [NO_ERRORS_SCHEMA] + }); + + beforeEach(() => { + fixture = TestBed.createComponent(DataTableComponent); + dataTable = fixture.componentInstance; + element = fixture.debugElement.nativeElement; + }); + + afterEach(() => { + fixture.destroy(); + }); + + it('should have accessibility tags', () => { + + const dataRows = + [ + { name: 'test1' }, + { name: 'test2' }, + { name: 'test3' }, + { name: 'test4' } + ]; + dataTable.data = new ObjectDataTableAdapter([], + [new ObjectDataColumn({ key: 'name' })] + ); + + dataTable.ngOnChanges({ + rows: new SimpleChange(null, dataRows, false) + }); + + fixture.detectChanges(); + const datatableAttributes = element.querySelector('.adf-data-table').attributes; + const datatableHeaderAttributes = element.querySelector('.adf-data-table .adf-datatable-header').attributes; + const datatableHeaderCellAttributes = element.querySelector('.adf-datatable-table-cell-header').attributes; + const datatableBodyAttributes = element.querySelector('.adf-datatable-body').attributes; + const datatableBodyRowAttributes = element.querySelector('.adf-datatable-body .adf-datatable-row').attributes; + const datatableBodyCellAttributes = element.querySelector('.adf-datatable-body .adf-datatable-table-cell').attributes; + + expect(datatableAttributes.getNamedItem('role').value).toEqual('grid'); + expect(datatableHeaderAttributes.getNamedItem('role').value).toEqual('rowgroup'); + expect(datatableHeaderCellAttributes.getNamedItem('role').value).toEqual('columnheader'); + expect(datatableBodyAttributes.getNamedItem('role').value).toEqual('rowgroup'); + expect(datatableBodyRowAttributes.getNamedItem('role').value).toEqual('row'); + expect(datatableBodyCellAttributes.getNamedItem('role').value).toEqual('gridcell'); + }); +});