diff --git a/src/material/datepicker/calendar-body.html b/src/material/datepicker/calendar-body.html index ffdfef27c1cd..9afc0fb74de9 100644 --- a/src/material/datepicker/calendar-body.html +++ b/src/material/datepicker/calendar-body.html @@ -46,7 +46,6 @@ [class.mat-calendar-body-preview-start]="_isPreviewStart(item.compareValue)" [class.mat-calendar-body-preview-end]="_isPreviewEnd(item.compareValue)" [class.mat-calendar-body-in-preview]="_isInPreview(item.compareValue)" - [attr.aria-label]="item.ariaLabel" [attr.aria-disabled]="!item.enabled || null" [attr.aria-selected]="_isSelected(item.compareValue)" [attr.aria-current]="todayValue === item.compareValue ? 'date' : null" @@ -58,7 +57,18 @@ [class.mat-calendar-body-selected]="_isSelected(item.compareValue)" [class.mat-calendar-body-comparison-identical]="_isComparisonIdentical(item.compareValue)" [class.mat-calendar-body-today]="todayValue === item.compareValue"> - {{item.displayValue}} + + {{item.ariaLabel}} + diff --git a/src/material/datepicker/calendar-body.spec.ts b/src/material/datepicker/calendar-body.spec.ts index df10b757c081..1ec29c75e86c 100644 --- a/src/material/datepicker/calendar-body.spec.ts +++ b/src/material/datepicker/calendar-body.spec.ts @@ -47,49 +47,17 @@ describe('MatCalendarBody', () => { }); it('highlights today', () => { - const todayCells = calendarBodyNativeElement.querySelectorAll('.mat-calendar-body-today')!; - expect(todayCells.length).toBe(1); - - const todayCell = todayCells[0]; - - expect(todayCell).not.toBeNull(); - expect(todayCell.textContent!.trim()).toBe('3'); - }); - - it('sets aria-current="date" on today', () => { - const todayCells = calendarBodyNativeElement.querySelectorAll( - '[aria-current="date"] .mat-calendar-body-today', - )!; - expect(todayCells.length).toBe(1); - - const todayCell = todayCells[0]; - - expect(todayCell).not.toBeNull(); - expect(todayCell.textContent!.trim()).toBe('3'); - }); - - it('does not highlight today if today is not within the scope', () => { - testComponent.todayValue = 100000; - fixture.detectChanges(); - const todayCell = calendarBodyNativeElement.querySelector('.mat-calendar-body-today')!; - expect(todayCell).toBeNull(); - }); - - it('does not set aria-current="date" on any cell if today is not ' + 'the scope', () => { - testComponent.todayValue = 100000; - fixture.detectChanges(); - - const todayCell = calendarBodyNativeElement.querySelector( - '[aria-current="date"] .mat-calendar-body-today', - )!; - expect(todayCell).toBeNull(); + const todayContent = todayCell.querySelector('.mat-calendar-body-cell-visual-label')!; + expect(todayCell).not.toBeNull(); + expect(todayContent.textContent!.trim()).toBe('3'); }); it('highlights selected', () => { const selectedCell = calendarBodyNativeElement.querySelector('.mat-calendar-body-selected')!; + const selectedContent = selectedCell.querySelector('.mat-calendar-body-cell-visual-label')!; expect(selectedCell).not.toBeNull(); - expect(selectedCell.innerHTML.trim()).toBe('4'); + expect(selectedContent.textContent!.trim()).toBe('4'); }); it('should set aria-selected correctly', () => { @@ -132,15 +100,24 @@ describe('MatCalendarBody', () => { }); it('should mark active date', () => { - expect((cellEls[10] as HTMLElement).innerText.trim()).toBe('11'); - expect(cellEls[10].classList).toContain('mat-calendar-body-active'); + const cell = cellEls[10] as HTMLElement; + const content = cell.querySelector('.mat-calendar-body-cell-visual-label') as HTMLElement; + + expect(content.innerText.trim()).toBe('11'); + expect(cell.classList).toContain('mat-calendar-body-active'); }); it('should set a class on even dates', () => { - expect((cellEls[0] as HTMLElement).innerText.trim()).toBe('1'); - expect((cellEls[1] as HTMLElement).innerText.trim()).toBe('2'); - expect(cellEls[0].classList).not.toContain('even'); - expect(cellEls[1].classList).toContain('even'); + const labelClass = '.mat-calendar-body-cell-visual-label'; + const firstCell = cellEls[0] as HTMLElement; + const secondCell = cellEls[1] as HTMLElement; + const firstContent = firstCell.querySelector(labelClass) as HTMLElement; + const secondContent = secondCell.querySelector(labelClass) as HTMLElement; + + expect(firstContent.innerText.trim()).toBe('1'); + expect(secondContent.innerText.trim()).toBe('2'); + expect(firstCell.classList).not.toContain('even'); + expect(secondCell.classList).toContain('even'); }); it('should have a focus indicator', () => { diff --git a/src/material/datepicker/calendar.spec.ts b/src/material/datepicker/calendar.spec.ts index 64c7cb18f836..7b70d631b914 100644 --- a/src/material/datepicker/calendar.spec.ts +++ b/src/material/datepicker/calendar.spec.ts @@ -67,17 +67,21 @@ describe('MatCalendar', () => { calendarInstance.updateTodaysDate(); fixture.detectChanges(); - let todayCell = calendarElement.querySelector('.mat-calendar-body-today')!; - expect(todayCell).not.toBeNull(); - expect(todayCell.innerHTML.trim()).toBe('1'); + let todayContent = calendarElement.querySelector( + '.mat-calendar-body-today .mat-calendar-body-cell-visual-label', + )!; + expect(todayContent).not.toBeNull(); + expect(todayContent.innerHTML.trim()).toBe('1'); fakeToday = new Date(2018, 0, 10); calendarInstance.updateTodaysDate(); fixture.detectChanges(); - todayCell = calendarElement.querySelector('.mat-calendar-body-today')!; - expect(todayCell).not.toBeNull(); - expect(todayCell.innerHTML.trim()).toBe('10'); + todayContent = calendarElement.querySelector( + '.mat-calendar-body-today .mat-calendar-body-cell-visual-label', + )!; + expect(todayContent).not.toBeNull(); + expect(todayContent.innerHTML.trim()).toBe('10'); })); it('should be in month view with specified month active', () => { diff --git a/src/material/datepicker/date-range-input.spec.ts b/src/material/datepicker/date-range-input.spec.ts index 26c5680670b7..5512884bd28d 100644 --- a/src/material/datepicker/date-range-input.spec.ts +++ b/src/material/datepicker/date-range-input.spec.ts @@ -536,7 +536,10 @@ describe('MatDateRangeInput', () => { '.mat-calendar-body-range-end', ].join(','), ), - ).map(cell => cell.textContent!.trim()); + ).map(cell => { + const content = cell.querySelector('.mat-calendar-body-cell-visual-label') as HTMLElement; + return content.textContent!.trim(); + }); expect(rangeTexts).toEqual(['2', '3', '4', '5']); })); @@ -569,7 +572,10 @@ describe('MatDateRangeInput', () => { '.mat-calendar-body-comparison-end', ].join(','), ), - ).map(cell => cell.textContent!.trim()); + ).map(cell => { + const content = cell.querySelector('.mat-calendar-body-cell-visual-label') as HTMLElement; + return content.textContent!.trim(); + }); expect(rangeTexts).toEqual(['2', '3', '4', '5']); })); diff --git a/src/material/datepicker/datepicker.spec.ts b/src/material/datepicker/datepicker.spec.ts index 40835b3b921a..e5d242b0f013 100644 --- a/src/material/datepicker/datepicker.spec.ts +++ b/src/material/datepicker/datepicker.spec.ts @@ -681,7 +681,7 @@ describe('MatDatepicker', () => { testComponent.datepicker.open(); fixture.detectChanges(); - const firstCalendarCell = document.querySelector('.mat-calendar-body-cell')!; + const firstCalendarCell = document.querySelector('.mat-calendar-body-cell-visual-label')!; // When the calendar is in year view, the first cell should be for a month rather than // for a date. @@ -732,7 +732,7 @@ describe('MatDatepicker', () => { testComponent.datepicker.open(); fixture.detectChanges(); - const firstCalendarCell = document.querySelector('.mat-calendar-body-cell')!; + const firstCalendarCell = document.querySelector('.mat-calendar-body-cell-visual-label')!; // When the calendar is in year view, the first cell should be for a month rather than // for a date. diff --git a/src/material/datepicker/month-view.spec.ts b/src/material/datepicker/month-view.spec.ts index 7a4909f8efbb..b2ef00794741 100644 --- a/src/material/datepicker/month-view.spec.ts +++ b/src/material/datepicker/month-view.spec.ts @@ -84,8 +84,10 @@ describe('MatMonthView', () => { }); it('shows selected date if in same month', () => { - let selectedEl = monthViewNativeElement.querySelector('.mat-calendar-body-selected')!; - expect(selectedEl.innerHTML.trim()).toBe('10'); + const selectedContent = monthViewNativeElement.querySelector( + '.mat-calendar-body-selected .mat-calendar-body-cell-visual-label', + )!; + expect(selectedContent.textContent!.trim()).toBe('10'); }); it('does not show selected date if in different month', () => { @@ -97,18 +99,23 @@ describe('MatMonthView', () => { }); it('fires selected change event on cell clicked', () => { - let cellEls = monthViewNativeElement.querySelectorAll('.mat-calendar-body-cell'); + const cellEls = monthViewNativeElement.querySelectorAll('.mat-calendar-body-cell'); (cellEls[cellEls.length - 1] as HTMLElement).click(); fixture.detectChanges(); - let selectedEl = monthViewNativeElement.querySelector('.mat-calendar-body-selected')!; - expect(selectedEl.innerHTML.trim()).toBe('31'); + const selectedContent = monthViewNativeElement.querySelector( + '.mat-calendar-body-selected .mat-calendar-body-cell-visual-label', + )!; + expect(selectedContent.textContent!.trim()).toBe('31'); }); it('should mark active date', () => { - let cellEls = monthViewNativeElement.querySelectorAll('.mat-calendar-body-cell'); - expect((cellEls[4] as HTMLElement).innerText.trim()).toBe('5'); - expect(cellEls[4].classList).toContain('mat-calendar-body-active'); + const cellEls = monthViewNativeElement.querySelectorAll('.mat-calendar-body-cell'); + const cell = cellEls[4] as HTMLElement; + const content = cell.querySelector('.mat-calendar-body-cell-visual-label') as HTMLElement; + + expect(content.innerText.trim()).toBe('5'); + expect(cell.classList).toContain('mat-calendar-body-active'); }); describe('a11y', () => { diff --git a/src/material/datepicker/multi-year-view.spec.ts b/src/material/datepicker/multi-year-view.spec.ts index 61c14607eb26..92681f9efd3c 100644 --- a/src/material/datepicker/multi-year-view.spec.ts +++ b/src/material/datepicker/multi-year-view.spec.ts @@ -62,8 +62,10 @@ describe('MatMultiYearView', () => { }); it('shows selected year if in same range', () => { - let selectedEl = multiYearViewNativeElement.querySelector('.mat-calendar-body-selected')!; - expect(selectedEl.innerHTML.trim()).toBe('2020'); + const selectedContent = multiYearViewNativeElement.querySelector( + '.mat-calendar-body-selected .mat-calendar-body-cell-visual-label', + )!; + expect(selectedContent.innerHTML.trim()).toBe('2020'); }); it('does not show selected year if in different range', () => { @@ -79,8 +81,10 @@ describe('MatMultiYearView', () => { (cellEls[cellEls.length - 1] as HTMLElement).click(); fixture.detectChanges(); - let selectedEl = multiYearViewNativeElement.querySelector('.mat-calendar-body-selected')!; - expect(selectedEl.innerHTML.trim()).toBe('2039'); + const selectedContent = multiYearViewNativeElement.querySelector( + '.mat-calendar-body-selected .mat-calendar-body-cell-visual-label', + )!; + expect(selectedContent.textContent!.trim()).toBe('2039'); }); it('should emit the selected year on cell clicked', () => { @@ -94,9 +98,12 @@ describe('MatMultiYearView', () => { }); it('should mark active date', () => { - let cellEls = multiYearViewNativeElement.querySelectorAll('.mat-calendar-body-cell'); - expect((cellEls[1] as HTMLElement).innerText.trim()).toBe('2017'); - expect(cellEls[1].classList).toContain('mat-calendar-body-active'); + const cellEls = multiYearViewNativeElement.querySelectorAll('.mat-calendar-body-cell'); + const cell = cellEls[1] as HTMLElement; + const content = cell.querySelector('.mat-calendar-body-cell-visual-label') as HTMLElement; + + expect(content.innerText.trim()).toBe('2017'); + expect(cell.classList).toContain('mat-calendar-body-active'); }); describe('a11y', () => { @@ -278,7 +285,12 @@ describe('MatMultiYearView', () => { fixture.detectChanges(); const cells = multiYearViewNativeElement.querySelectorAll('.mat-calendar-body-cell'); - expect((cells[0] as HTMLElement).innerText.trim()).toBe('2014'); + const firstCell = cells[0] as HTMLElement; + const content = firstCell.querySelector( + '.mat-calendar-body-cell-visual-label', + ) as HTMLElement; + + expect(content.innerText.trim()).toBe('2014'); }); }); @@ -301,7 +313,9 @@ describe('MatMultiYearView', () => { fixture.detectChanges(); const cells = multiYearViewNativeElement.querySelectorAll('.mat-calendar-body-cell'); - expect((cells[cells.length - 1] as HTMLElement).innerText.trim()).toBe('2020'); + const lastCell = cells[cells.length - 1] as HTMLElement; + const content = lastCell.querySelector('.mat-calendar-body-cell-visual-label') as HTMLElement; + expect(content.innerText.trim()).toBe('2020'); }); }); @@ -324,7 +338,9 @@ describe('MatMultiYearView', () => { fixture.detectChanges(); const cells = multiYearViewNativeElement.querySelectorAll('.mat-calendar-body-cell'); - expect((cells[cells.length - 1] as HTMLElement).innerText.trim()).toBe('2020'); + const lastCell = cells[cells.length - 1] as HTMLElement; + const content = lastCell.querySelector('.mat-calendar-body-cell-visual-label') as HTMLElement; + expect(content.innerText.trim()).toBe('2020'); }); it('should disable dates before minDate', () => { diff --git a/src/material/datepicker/testing/calendar-cell-harness.ts b/src/material/datepicker/testing/calendar-cell-harness.ts index 4ebee4c8ccb4..25837b928f74 100644 --- a/src/material/datepicker/testing/calendar-cell-harness.ts +++ b/src/material/datepicker/testing/calendar-cell-harness.ts @@ -16,6 +16,9 @@ export class MatCalendarCellHarness extends ComponentHarness { /** Reference to the inner content element inside the cell. */ private _content = this.locatorFor('.mat-calendar-body-cell-content'); + /** Inner element containing the visual label. */ + private _visualLabel = this.locatorFor('.mat-calendar-body-cell-visual-label'); + /** * Gets a `HarnessPredicate` that can be used to search for a `MatCalendarCellHarness` * that meets certain criteria. @@ -56,10 +59,14 @@ export class MatCalendarCellHarness extends ComponentHarness { /** Gets the text of the calendar cell. */ async getText(): Promise { - return (await this._content()).text(); + return (await this._visualLabel()).text(); } - /** Gets the aria-label of the calendar cell. */ + /** + * Gets the aria-label of the calendar cell. + * @deprecated Calendar cells no longer have an `aria-label`. To be removed. + * @breaking-change 14.0.0 + */ async getAriaLabel(): Promise { // We're guaranteed for the `aria-label` to be defined // since this is a private element that we control. diff --git a/src/material/datepicker/testing/calendar-harness-shared.spec.ts b/src/material/datepicker/testing/calendar-harness-shared.spec.ts index 8e9b264f7ab1..0c0b9a59ab99 100644 --- a/src/material/datepicker/testing/calendar-harness-shared.spec.ts +++ b/src/material/datepicker/testing/calendar-harness-shared.spec.ts @@ -101,15 +101,6 @@ export function runCalendarHarnessTests( expect(await targetCell.isSelected()).toBe(true); }); - it('should get the aria-label of a cell', async () => { - const calendar = await loader.getHarness(calendarHarness.with({selector: '#single'})); - const cells = await calendar.getCells(); - - expect(await cells[0].getAriaLabel()).toBe('August 1, 2020'); - expect(await cells[15].getAriaLabel()).toBe('August 16, 2020'); - expect(await cells[30].getAriaLabel()).toBe('August 31, 2020'); - }); - it('should get the disabled state of a cell', async () => { fixture.componentInstance.minDate = new Date( calendarDate.getFullYear(), diff --git a/src/material/datepicker/year-view.spec.ts b/src/material/datepicker/year-view.spec.ts index 99e6ca6783f9..33f857ca9dd5 100644 --- a/src/material/datepicker/year-view.spec.ts +++ b/src/material/datepicker/year-view.spec.ts @@ -66,8 +66,10 @@ describe('MatYearView', () => { }); it('shows selected month if in same year', () => { - let selectedEl = yearViewNativeElement.querySelector('.mat-calendar-body-selected')!; - expect(selectedEl.innerHTML.trim()).toBe('MAR'); + const selectedContent = yearViewNativeElement.querySelector( + '.mat-calendar-body-selected .mat-calendar-body-cell-visual-label', + )!; + expect(selectedContent.textContent!.trim()).toBe('MAR'); }); it('does not show selected month if in different year', () => { @@ -83,8 +85,10 @@ describe('MatYearView', () => { (cellEls[cellEls.length - 1] as HTMLElement).click(); fixture.detectChanges(); - let selectedEl = yearViewNativeElement.querySelector('.mat-calendar-body-selected')!; - expect(selectedEl.innerHTML.trim()).toBe('DEC'); + const selectedContent = yearViewNativeElement.querySelector( + '.mat-calendar-body-selected .mat-calendar-body-cell-visual-label', + )!; + expect(selectedContent.textContent!.trim()).toBe('DEC'); }); it('should emit the selected month on cell clicked', () => { @@ -98,9 +102,12 @@ describe('MatYearView', () => { }); it('should mark active date', () => { - let cellEls = yearViewNativeElement.querySelectorAll('.mat-calendar-body-cell'); - expect((cellEls[0] as HTMLElement).innerText.trim()).toBe('JAN'); - expect(cellEls[0].classList).toContain('mat-calendar-body-active'); + const cellEls = yearViewNativeElement.querySelectorAll('.mat-calendar-body-cell'); + const cell = cellEls[0] as HTMLElement; + const content = cell.querySelector('.mat-calendar-body-cell-visual-label') as HTMLElement; + + expect(content.innerText.trim()).toBe('JAN'); + expect(cell.classList).toContain('mat-calendar-body-active'); }); it('should allow selection of month with less days than current active date', () => { diff --git a/tools/public_api_guard/material/datepicker-testing.md b/tools/public_api_guard/material/datepicker-testing.md index d971eaaf3290..55eebe22e5f2 100644 --- a/tools/public_api_guard/material/datepicker-testing.md +++ b/tools/public_api_guard/material/datepicker-testing.md @@ -54,6 +54,7 @@ export interface DateRangeInputHarnessFilters extends BaseHarnessFilters { export class MatCalendarCellHarness extends ComponentHarness { blur(): Promise; focus(): Promise; + // @deprecated getAriaLabel(): Promise; getText(): Promise; // (undocumented)