import {HarnessLoader, parallel} from '@angular/cdk/testing'; import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed'; import {Component} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {MatNativeDateModule} from '@angular/material/core'; import { DateRange, DefaultMatCalendarRangeStrategy, MAT_DATE_RANGE_SELECTION_STRATEGY, MatDatepickerModule, } from '@angular/material/datepicker'; import {CalendarView, MatCalendarHarness} from './calendar-harness'; /** Date at which the calendars are set. */ const calendarDate = new Date(2020, 7, 1); describe('MatCalendarHarness', () => { let fixture: ComponentFixture; let loader: HarnessLoader; beforeEach(() => { TestBed.configureTestingModule({ imports: [MatNativeDateModule, MatDatepickerModule, CalendarHarnessTest], providers: [ { // Usually it's the date range picker that provides the default range selection strategy, // but since we're testing the calendar on its own, we have to provide it manually. provide: MAT_DATE_RANGE_SELECTION_STRATEGY, useClass: DefaultMatCalendarRangeStrategy, }, ], }); fixture = TestBed.createComponent(CalendarHarnessTest); fixture.detectChanges(); loader = TestbedHarnessEnvironment.loader(fixture); }); it('should load all calendar harnesses', async () => { const calendars = await loader.getAllHarnesses(MatCalendarHarness); expect(calendars.length).toBe(2); }); it('should go to a different view', async () => { const calendar = await loader.getHarness(MatCalendarHarness.with({selector: '#single'})); expect(await calendar.getCurrentView()).toBe(CalendarView.MONTH); await calendar.changeView(); expect(await calendar.getCurrentView()).toBe(CalendarView.MULTI_YEAR); }); it('should get the current view label', async () => { const calendar = await loader.getHarness(MatCalendarHarness.with({selector: '#single'})); expect(await calendar.getCurrentViewLabel()).toBe('AUG 2020'); await calendar.changeView(); expect(await calendar.getCurrentViewLabel()).toBe('2016 – 2039'); }); it('should go to the next page in the view', async () => { const calendar = await loader.getHarness(MatCalendarHarness.with({selector: '#single'})); expect(await calendar.getCurrentViewLabel()).toBe('AUG 2020'); await calendar.next(); expect(await calendar.getCurrentViewLabel()).toBe('SEP 2020'); }); it('should go to the previous page in the view', async () => { const calendar = await loader.getHarness(MatCalendarHarness.with({selector: '#single'})); expect(await calendar.getCurrentViewLabel()).toBe('AUG 2020'); await calendar.previous(); expect(await calendar.getCurrentViewLabel()).toBe('JUL 2020'); }); it('should get all of the date cells inside the calendar', async () => { const calendar = await loader.getHarness(MatCalendarHarness.with({selector: '#single'})); expect((await calendar.getCells()).length).toBe(31); }); it('should get the text of a calendar cell', async () => { const calendar = await loader.getHarness(MatCalendarHarness.with({selector: '#single'})); const cells = await calendar.getCells(); expect(await cells[0].getText()).toBe('1'); expect(await cells[15].getText()).toBe('16'); expect(await cells[30].getText()).toBe('31'); }); it('should be able to select a specific cell through the calendar', async () => { const calendar = await loader.getHarness(MatCalendarHarness.with({selector: '#single'})); const targetCell = (await calendar.getCells({text: '16'}))[0]; expect(await targetCell.isSelected()).toBe(false); await calendar.selectCell({text: '16'}); expect(await targetCell.isSelected()).toBe(true); }); it('should get the aria-label of a cell', async () => { const calendar = await loader.getHarness(MatCalendarHarness.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(), calendarDate.getMonth(), 20, ); fixture.changeDetectorRef.markForCheck(); const calendar = await loader.getHarness(MatCalendarHarness.with({selector: '#single'})); const cells = await calendar.getCells(); expect(await cells[0].isDisabled()).toBe(true); expect(await cells[15].isDisabled()).toBe(true); expect(await cells[30].isDisabled()).toBe(false); }); it('should select a cell', async () => { const calendar = await loader.getHarness(MatCalendarHarness.with({selector: '#single'})); const cell = (await calendar.getCells())[10]; expect(await cell.isSelected()).toBe(false); await cell.select(); expect(await cell.isSelected()).toBe(true); }); it('should get whether a cell is active', async () => { const calendar = await loader.getHarness(MatCalendarHarness.with({selector: '#single'})); const cells = await calendar.getCells(); expect(await cells[0].isActive()).toBe(true); expect(await cells[15].isActive()).toBe(false); }); it('should get the state of the cell within the main range', async () => { const calendar = await loader.getHarness(MatCalendarHarness.with({selector: '#range'})); const allCells = await calendar.getCells(); const [initialStartStates, initialInRangeStates, initialEndStates] = await parallel(() => [ parallel(() => allCells.map(cell => cell.isRangeStart())), parallel(() => allCells.map(cell => cell.isInRange())), parallel(() => allCells.map(cell => cell.isRangeEnd())), ]); expect(initialStartStates.every(state => state === false)).toBe(true); expect(initialInRangeStates.every(state => state === false)).toBe(true); expect(initialEndStates.every(state => state === false)).toBe(true); await (await calendar.getCells({text: '5'}))[0].select(); await (await calendar.getCells({text: '8'}))[0].select(); expect(await allCells[4].isRangeStart()).toBe(true); expect(await allCells[4].isInRange()).toBe(true); expect(await allCells[4].isRangeEnd()).toBe(false); expect(await allCells[5].isRangeStart()).toBe(false); expect(await allCells[5].isInRange()).toBe(true); expect(await allCells[5].isRangeEnd()).toBe(false); expect(await allCells[6].isRangeStart()).toBe(false); expect(await allCells[6].isInRange()).toBe(true); expect(await allCells[6].isRangeEnd()).toBe(false); expect(await allCells[7].isRangeStart()).toBe(false); expect(await allCells[7].isInRange()).toBe(true); expect(await allCells[7].isRangeEnd()).toBe(true); }); it('should get the state of the cell within the comparison range', async () => { const calendar = await loader.getHarness(MatCalendarHarness.with({selector: '#range'})); const allCells = await calendar.getCells(); const [initialStartStates, initialInRangeStates, initialEndStates] = await parallel(() => [ parallel(() => allCells.map(cell => cell.isComparisonRangeStart())), parallel(() => allCells.map(cell => cell.isInComparisonRange())), parallel(() => allCells.map(cell => cell.isComparisonRangeEnd())), ]); expect(initialStartStates.every(state => state === false)).toBe(true); expect(initialInRangeStates.every(state => state === false)).toBe(true); expect(initialEndStates.every(state => state === false)).toBe(true); fixture.componentInstance.comparisonStart = new Date( calendarDate.getFullYear(), calendarDate.getMonth(), 5, ); fixture.componentInstance.comparisonEnd = new Date( calendarDate.getFullYear(), calendarDate.getMonth(), 8, ); fixture.changeDetectorRef.markForCheck(); expect(await allCells[4].isComparisonRangeStart()).toBe(true); expect(await allCells[4].isInComparisonRange()).toBe(true); expect(await allCells[4].isComparisonRangeEnd()).toBe(false); expect(await allCells[5].isComparisonRangeStart()).toBe(false); expect(await allCells[5].isInComparisonRange()).toBe(true); expect(await allCells[5].isComparisonRangeEnd()).toBe(false); expect(await allCells[6].isComparisonRangeStart()).toBe(false); expect(await allCells[6].isInComparisonRange()).toBe(true); expect(await allCells[6].isComparisonRangeEnd()).toBe(false); expect(await allCells[7].isComparisonRangeStart()).toBe(false); expect(await allCells[7].isInComparisonRange()).toBe(true); expect(await allCells[7].isComparisonRangeEnd()).toBe(true); }); it('should get the state of the cell within the preview range', async () => { const calendar = await loader.getHarness(MatCalendarHarness.with({selector: '#range'})); const allCells = await calendar.getCells(); const [initialStartStates, initialInRangeStates, initialEndStates] = await parallel(() => [ parallel(() => allCells.map(cell => cell.isPreviewRangeStart())), parallel(() => allCells.map(cell => cell.isInPreviewRange())), parallel(() => allCells.map(cell => cell.isPreviewRangeEnd())), ]); expect(initialStartStates.every(state => state === false)).toBe(true); expect(initialInRangeStates.every(state => state === false)).toBe(true); expect(initialEndStates.every(state => state === false)).toBe(true); await (await calendar.getCells({text: '5'}))[0].select(); await (await calendar.getCells({text: '8'}))[0].hover(); expect(await allCells[4].isPreviewRangeStart()).toBe(true); expect(await allCells[4].isInPreviewRange()).toBe(true); expect(await allCells[4].isPreviewRangeEnd()).toBe(false); expect(await allCells[5].isPreviewRangeStart()).toBe(false); expect(await allCells[5].isInPreviewRange()).toBe(true); expect(await allCells[5].isPreviewRangeEnd()).toBe(false); expect(await allCells[6].isPreviewRangeStart()).toBe(false); expect(await allCells[6].isInPreviewRange()).toBe(true); expect(await allCells[6].isPreviewRangeEnd()).toBe(false); expect(await allCells[7].isPreviewRangeStart()).toBe(false); expect(await allCells[7].isInPreviewRange()).toBe(true); expect(await allCells[7].isPreviewRangeEnd()).toBe(true); }); it('should filter cells by their text', async () => { const calendar = await loader.getHarness(MatCalendarHarness.with({selector: '#single'})); const cells = await calendar.getCells({text: /^3/}); expect(await parallel(() => cells.map(cell => cell.getText()))).toEqual(['3', '30', '31']); }); it('should filter cells by their selected state', async () => { const calendar = await loader.getHarness(MatCalendarHarness.with({selector: '#single'})); const allCells = await calendar.getCells(); await allCells[0].select(); const selectedCells = await calendar.getCells({selected: true}); expect(await parallel(() => selectedCells.map(cell => cell.getText()))).toEqual(['1']); }); it('should filter cells by their active state', async () => { const calendar = await loader.getHarness(MatCalendarHarness.with({selector: '#single'})); const cells = await calendar.getCells({active: true}); expect(await parallel(() => cells.map(cell => cell.getText()))).toEqual(['1']); }); it('should filter cells by their disabled state', async () => { fixture.componentInstance.minDate = new Date( calendarDate.getFullYear(), calendarDate.getMonth(), 3, ); fixture.changeDetectorRef.markForCheck(); const calendar = await loader.getHarness(MatCalendarHarness.with({selector: '#single'})); const cells = await calendar.getCells({disabled: true}); expect(await parallel(() => cells.map(cell => cell.getText()))).toEqual(['1', '2']); }); it('should filter cells based on whether they are inside the comparison range', async () => { const calendar = await loader.getHarness(MatCalendarHarness.with({selector: '#range'})); fixture.componentInstance.comparisonStart = new Date( calendarDate.getFullYear(), calendarDate.getMonth(), 5, ); fixture.componentInstance.comparisonEnd = new Date( calendarDate.getFullYear(), calendarDate.getMonth(), 8, ); fixture.changeDetectorRef.markForCheck(); const cells = await calendar.getCells({inComparisonRange: true}); expect(await parallel(() => cells.map(cell => cell.getText()))).toEqual(['5', '6', '7', '8']); }); it('should filter cells based on whether they are inside the preview range', async () => { const calendar = await loader.getHarness(MatCalendarHarness.with({selector: '#range'})); await (await calendar.getCells({text: '5'}))[0].select(); await (await calendar.getCells({text: '8'}))[0].hover(); const cells = await calendar.getCells({inPreviewRange: true}); expect(await parallel(() => cells.map(cell => cell.getText()))).toEqual(['5', '6', '7', '8']); }); }); @Component({ template: ` `, standalone: true, imports: [MatNativeDateModule, MatDatepickerModule], }) class CalendarHarnessTest { // Start the datepickers off at a specific date so tests // run consistently no matter what the current date is. readonly startAt = new Date(calendarDate); minDate: Date | null; singleValue: Date | null = null; rangeValue = new DateRange(null, null); comparisonStart: Date | null = null; comparisonEnd: Date | null = null; rangeChanged(selectedDate: Date) { let {start, end} = this.rangeValue; if (start == null || end != null) { start = selectedDate; } else if (end == null) { end = selectedDate; } this.rangeValue = new DateRange(start, end); } }