720 lines
24 KiB
TypeScript
720 lines
24 KiB
TypeScript
import {Directionality} from '@angular/cdk/bidi';
|
|
import {ENTER, RIGHT_ARROW, SPACE} from '@angular/cdk/keycodes';
|
|
import {
|
|
dispatchFakeEvent,
|
|
dispatchKeyboardEvent,
|
|
dispatchMouseEvent,
|
|
} from '@angular/cdk/testing/private';
|
|
import {Component} from '@angular/core';
|
|
import {ComponentFixture, TestBed, inject, waitForAsync} from '@angular/core/testing';
|
|
import {DateAdapter, MatNativeDateModule} from '@angular/material/core';
|
|
import {By} from '@angular/platform-browser';
|
|
import {DEC, FEB, JAN, JUL, NOV} from '../testing';
|
|
import {MatCalendar} from './calendar';
|
|
import {MatDatepickerIntl} from './datepicker-intl';
|
|
import {MatDatepickerModule} from './datepicker-module';
|
|
|
|
describe('MatCalendar', () => {
|
|
beforeEach(waitForAsync(() => {
|
|
TestBed.configureTestingModule({
|
|
imports: [MatNativeDateModule, MatDatepickerModule],
|
|
providers: [MatDatepickerIntl, {provide: Directionality, useFactory: () => ({value: 'ltr'})}],
|
|
declarations: [
|
|
// Test components.
|
|
StandardCalendar,
|
|
CalendarWithMinMax,
|
|
CalendarWithDateFilter,
|
|
CalendarWithSelectableMinDate,
|
|
],
|
|
});
|
|
}));
|
|
|
|
describe('standard calendar', () => {
|
|
let fixture: ComponentFixture<StandardCalendar>;
|
|
let testComponent: StandardCalendar;
|
|
let calendarElement: HTMLElement;
|
|
let periodButton: HTMLElement;
|
|
let calendarInstance: MatCalendar<Date>;
|
|
|
|
beforeEach(() => {
|
|
fixture = TestBed.createComponent(StandardCalendar);
|
|
fixture.detectChanges();
|
|
|
|
let calendarDebugElement = fixture.debugElement.query(By.directive(MatCalendar))!;
|
|
calendarElement = calendarDebugElement.nativeElement;
|
|
periodButton = calendarElement.querySelector('.mat-calendar-period-button') as HTMLElement;
|
|
|
|
calendarInstance = calendarDebugElement.componentInstance;
|
|
testComponent = fixture.componentInstance;
|
|
});
|
|
|
|
it(`should update today's date`, inject([DateAdapter], (adapter: DateAdapter<Date>) => {
|
|
let fakeToday = new Date(2018, 0, 1);
|
|
spyOn(adapter, 'today').and.callFake(() => fakeToday);
|
|
|
|
calendarInstance.activeDate = fakeToday;
|
|
calendarInstance.updateTodaysDate();
|
|
fixture.detectChanges();
|
|
|
|
let todayCell = calendarElement.querySelector('.mat-calendar-body-today')!;
|
|
expect(todayCell).not.toBeNull();
|
|
expect(todayCell.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');
|
|
}));
|
|
|
|
it('should be in month view with specified month active', () => {
|
|
expect(calendarInstance.currentView).toBe('month');
|
|
expect(calendarInstance.activeDate).toEqual(new Date(2017, JAN, 31));
|
|
});
|
|
|
|
it('should select date in month view', () => {
|
|
let monthCells = calendarElement.querySelectorAll('.mat-calendar-body-cell');
|
|
(monthCells[monthCells.length - 1] as HTMLElement).click();
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.currentView).toBe('month');
|
|
expect(testComponent.selected).toEqual(new Date(2017, JAN, 31));
|
|
});
|
|
|
|
it('should emit the selected month on cell clicked in year view', () => {
|
|
periodButton.click();
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.currentView).toBe('multi-year');
|
|
expect(calendarInstance.activeDate).toEqual(new Date(2017, JAN, 31));
|
|
|
|
(calendarElement.querySelector('.mat-calendar-body-active') as HTMLElement).click();
|
|
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.currentView).toBe('year');
|
|
|
|
(calendarElement.querySelector('.mat-calendar-body-active') as HTMLElement).click();
|
|
|
|
const normalizedMonth: Date = fixture.componentInstance.selectedMonth;
|
|
expect(normalizedMonth.getMonth()).toEqual(0);
|
|
});
|
|
|
|
it('should emit the selected year on cell clicked in multiyear view', () => {
|
|
periodButton.click();
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.currentView).toBe('multi-year');
|
|
expect(calendarInstance.activeDate).toEqual(new Date(2017, JAN, 31));
|
|
|
|
(calendarElement.querySelector('.mat-calendar-body-active') as HTMLElement).click();
|
|
|
|
fixture.detectChanges();
|
|
|
|
const normalizedYear: Date = fixture.componentInstance.selectedYear;
|
|
expect(normalizedYear.getFullYear()).toEqual(2017);
|
|
});
|
|
|
|
it('should re-render when the i18n labels have changed', inject(
|
|
[MatDatepickerIntl],
|
|
(intl: MatDatepickerIntl) => {
|
|
const button = fixture.debugElement.nativeElement.querySelector(
|
|
'.mat-calendar-period-button',
|
|
);
|
|
|
|
intl.switchToMultiYearViewLabel = 'Go to multi-year view?';
|
|
intl.changes.next();
|
|
fixture.detectChanges();
|
|
|
|
expect(button.getAttribute('aria-label')).toBe('Go to multi-year view?');
|
|
},
|
|
));
|
|
|
|
it('should set all buttons to be `type="button"`', () => {
|
|
const invalidButtons = calendarElement.querySelectorAll('button:not([type="button"])');
|
|
expect(invalidButtons.length).toBe(0);
|
|
});
|
|
|
|
it('should complete the stateChanges stream', () => {
|
|
const spy = jasmine.createSpy('complete spy');
|
|
const subscription = calendarInstance.stateChanges.subscribe({complete: spy});
|
|
|
|
fixture.destroy();
|
|
|
|
expect(spy).toHaveBeenCalled();
|
|
subscription.unsubscribe();
|
|
});
|
|
|
|
describe('a11y', () => {
|
|
describe('calendar body', () => {
|
|
let calendarBodyEl: HTMLElement;
|
|
|
|
beforeEach(() => {
|
|
calendarBodyEl = calendarElement.querySelector('.mat-calendar-content') as HTMLElement;
|
|
expect(calendarBodyEl).not.toBeNull();
|
|
|
|
dispatchFakeEvent(calendarBodyEl, 'focus');
|
|
fixture.detectChanges();
|
|
});
|
|
|
|
it('should initially set start date active', () => {
|
|
expect(calendarInstance.activeDate).toEqual(new Date(2017, JAN, 31));
|
|
});
|
|
|
|
it('should make the calendar body focusable', () => {
|
|
expect(calendarBodyEl.getAttribute('tabindex')).toBe('-1');
|
|
});
|
|
|
|
it('should not move focus to the active cell on init', waitForAsync(async () => {
|
|
const activeCell = calendarBodyEl.querySelector(
|
|
'.mat-calendar-body-active',
|
|
)! as HTMLElement;
|
|
|
|
spyOn(activeCell, 'focus').and.callThrough();
|
|
fixture.detectChanges();
|
|
await new Promise(resolve => setTimeout(resolve));
|
|
|
|
expect(activeCell.focus).not.toHaveBeenCalled();
|
|
}));
|
|
|
|
it('should move focus to the active cell when the view changes', waitForAsync(async () => {
|
|
calendarInstance.currentView = 'multi-year';
|
|
fixture.detectChanges();
|
|
|
|
const activeCell = calendarBodyEl.querySelector(
|
|
'.mat-calendar-body-active',
|
|
)! as HTMLElement;
|
|
spyOn(activeCell, 'focus').and.callThrough();
|
|
|
|
await new Promise(resolve => setTimeout(resolve));
|
|
|
|
expect(activeCell.focus).toHaveBeenCalled();
|
|
}));
|
|
|
|
describe('year view', () => {
|
|
beforeEach(() => {
|
|
dispatchMouseEvent(periodButton, 'click');
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.currentView).toBe('multi-year');
|
|
|
|
(calendarBodyEl.querySelector('.mat-calendar-body-active') as HTMLElement).click();
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.currentView).toBe('year');
|
|
});
|
|
|
|
it('should return to month view on enter', () => {
|
|
const tableBodyEl = calendarBodyEl.querySelector('.mat-calendar-body') as HTMLElement;
|
|
|
|
dispatchKeyboardEvent(tableBodyEl, 'keydown', RIGHT_ARROW);
|
|
fixture.detectChanges();
|
|
|
|
dispatchKeyboardEvent(tableBodyEl, 'keydown', ENTER);
|
|
fixture.detectChanges();
|
|
dispatchKeyboardEvent(tableBodyEl, 'keyup', ENTER);
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.currentView).toBe('month');
|
|
expect(calendarInstance.activeDate).toEqual(new Date(2017, FEB, 28));
|
|
expect(testComponent.selected).toBeUndefined();
|
|
});
|
|
|
|
it('should return to month view on space', () => {
|
|
const tableBodyEl = calendarBodyEl.querySelector('.mat-calendar-body') as HTMLElement;
|
|
|
|
dispatchKeyboardEvent(tableBodyEl, 'keydown', RIGHT_ARROW);
|
|
fixture.detectChanges();
|
|
|
|
dispatchKeyboardEvent(tableBodyEl, 'keydown', SPACE);
|
|
fixture.detectChanges();
|
|
dispatchKeyboardEvent(tableBodyEl, 'keyup', SPACE);
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.currentView).toBe('month');
|
|
expect(calendarInstance.activeDate).toEqual(new Date(2017, FEB, 28));
|
|
expect(testComponent.selected).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe('multi-year view', () => {
|
|
beforeEach(() => {
|
|
dispatchMouseEvent(periodButton, 'click');
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.currentView).toBe('multi-year');
|
|
});
|
|
|
|
it('should go to year view on enter', () => {
|
|
const tableBodyEl = calendarBodyEl.querySelector('.mat-calendar-body') as HTMLElement;
|
|
|
|
dispatchKeyboardEvent(tableBodyEl, 'keydown', RIGHT_ARROW);
|
|
fixture.detectChanges();
|
|
|
|
dispatchKeyboardEvent(tableBodyEl, 'keydown', ENTER);
|
|
fixture.detectChanges();
|
|
dispatchKeyboardEvent(tableBodyEl, 'keyup', ENTER);
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.currentView).toBe('year');
|
|
expect(calendarInstance.activeDate).toEqual(new Date(2018, JAN, 31));
|
|
expect(testComponent.selected).toBeUndefined();
|
|
});
|
|
|
|
it('should go to year view on space', () => {
|
|
const tableBodyEl = calendarBodyEl.querySelector('.mat-calendar-body') as HTMLElement;
|
|
|
|
dispatchKeyboardEvent(tableBodyEl, 'keydown', RIGHT_ARROW);
|
|
fixture.detectChanges();
|
|
|
|
dispatchKeyboardEvent(tableBodyEl, 'keydown', SPACE);
|
|
fixture.detectChanges();
|
|
dispatchKeyboardEvent(tableBodyEl, 'keyup', SPACE);
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.currentView).toBe('year');
|
|
expect(calendarInstance.activeDate).toEqual(new Date(2018, JAN, 31));
|
|
expect(testComponent.selected).toBeUndefined();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should re-render the month view when the locale changes', inject(
|
|
[DateAdapter],
|
|
(adapter: DateAdapter<Date>) => {
|
|
fixture.detectChanges();
|
|
spyOn(calendarInstance.monthView, '_init').and.callThrough();
|
|
|
|
adapter.setLocale('bg-BG');
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.monthView._init).toHaveBeenCalled();
|
|
},
|
|
));
|
|
|
|
it('should re-render the year view when the locale changes', inject(
|
|
[DateAdapter],
|
|
(adapter: DateAdapter<Date>) => {
|
|
periodButton.click();
|
|
fixture.detectChanges();
|
|
|
|
(calendarElement.querySelector('.mat-calendar-body-active') as HTMLElement).click();
|
|
fixture.detectChanges();
|
|
|
|
spyOn(calendarInstance.yearView, '_init').and.callThrough();
|
|
|
|
adapter.setLocale('bg-BG');
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.yearView._init).toHaveBeenCalled();
|
|
},
|
|
));
|
|
|
|
it('should re-render the multi-year view when the locale changes', inject(
|
|
[DateAdapter],
|
|
(adapter: DateAdapter<Date>) => {
|
|
periodButton.click();
|
|
fixture.detectChanges();
|
|
|
|
spyOn(calendarInstance.multiYearView, '_init').and.callThrough();
|
|
|
|
adapter.setLocale('bg-BG');
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.multiYearView._init).toHaveBeenCalled();
|
|
},
|
|
));
|
|
});
|
|
|
|
describe('calendar with min and max date', () => {
|
|
let fixture: ComponentFixture<CalendarWithMinMax>;
|
|
let testComponent: CalendarWithMinMax;
|
|
let calendarElement: HTMLElement;
|
|
let calendarInstance: MatCalendar<Date>;
|
|
|
|
beforeEach(() => {
|
|
fixture = TestBed.createComponent(CalendarWithMinMax);
|
|
|
|
let calendarDebugElement = fixture.debugElement.query(By.directive(MatCalendar))!;
|
|
calendarElement = calendarDebugElement.nativeElement;
|
|
calendarInstance = calendarDebugElement.componentInstance;
|
|
testComponent = fixture.componentInstance;
|
|
});
|
|
|
|
it('should clamp startAt value below min date', () => {
|
|
testComponent.startAt = new Date(2000, JAN, 1);
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.activeDate).toEqual(new Date(2016, JAN, 1));
|
|
});
|
|
|
|
it('should clamp startAt value above max date', () => {
|
|
testComponent.startAt = new Date(2020, JAN, 1);
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.activeDate).toEqual(new Date(2018, JAN, 1));
|
|
});
|
|
|
|
it('should not go back past min date', () => {
|
|
testComponent.startAt = new Date(2016, FEB, 1);
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
let prevButton = calendarElement.querySelector(
|
|
'.mat-calendar-previous-button',
|
|
) as HTMLButtonElement;
|
|
|
|
expect(prevButton.disabled).withContext('previous button should not be disabled').toBe(false);
|
|
expect(calendarInstance.activeDate).toEqual(new Date(2016, FEB, 1));
|
|
|
|
prevButton.click();
|
|
fixture.detectChanges();
|
|
|
|
expect(prevButton.disabled).withContext('previous button should be disabled').toBe(true);
|
|
expect(calendarInstance.activeDate).toEqual(new Date(2016, JAN, 1));
|
|
|
|
prevButton.click();
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.activeDate).toEqual(new Date(2016, JAN, 1));
|
|
});
|
|
|
|
it('should not go forward past max date', () => {
|
|
testComponent.startAt = new Date(2017, DEC, 1);
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
let nextButton = calendarElement.querySelector(
|
|
'.mat-calendar-next-button',
|
|
) as HTMLButtonElement;
|
|
|
|
expect(nextButton.disabled).withContext('next button should not be disabled').toBe(false);
|
|
expect(calendarInstance.activeDate).toEqual(new Date(2017, DEC, 1));
|
|
|
|
nextButton.click();
|
|
fixture.detectChanges();
|
|
|
|
expect(nextButton.disabled).withContext('next button should be disabled').toBe(true);
|
|
expect(calendarInstance.activeDate).toEqual(new Date(2018, JAN, 1));
|
|
|
|
nextButton.click();
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.activeDate).toEqual(new Date(2018, JAN, 1));
|
|
});
|
|
|
|
it('should re-render the month view when the minDate changes', () => {
|
|
fixture.detectChanges();
|
|
spyOn(calendarInstance.monthView, '_init').and.callThrough();
|
|
|
|
testComponent.minDate = new Date(2017, NOV, 1);
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.monthView._init).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should not re-render the month view when the minDate changes to the same day at a different time', () => {
|
|
fixture.detectChanges();
|
|
spyOn(calendarInstance.monthView, '_init').and.callThrough();
|
|
|
|
testComponent.minDate = new Date(2016, JAN, 1, 0, 0, 0, 1);
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.monthView._init).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should re-render the month view when the maxDate changes', () => {
|
|
fixture.detectChanges();
|
|
spyOn(calendarInstance.monthView, '_init').and.callThrough();
|
|
|
|
testComponent.maxDate = new Date(2017, DEC, 1);
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.monthView._init).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should re-render the year view when the minDate changes', () => {
|
|
fixture.detectChanges();
|
|
const periodButton = calendarElement.querySelector(
|
|
'.mat-calendar-period-button',
|
|
) as HTMLElement;
|
|
periodButton.click();
|
|
fixture.detectChanges();
|
|
|
|
(calendarElement.querySelector('.mat-calendar-body-active') as HTMLElement).click();
|
|
fixture.detectChanges();
|
|
|
|
spyOn(calendarInstance.yearView, '_init').and.callThrough();
|
|
|
|
testComponent.minDate = new Date(2017, NOV, 1);
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.yearView._init).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should re-render the year view when the maxDate changes', () => {
|
|
fixture.detectChanges();
|
|
const periodButton = calendarElement.querySelector(
|
|
'.mat-calendar-period-button',
|
|
) as HTMLElement;
|
|
periodButton.click();
|
|
fixture.detectChanges();
|
|
|
|
(calendarElement.querySelector('.mat-calendar-body-active') as HTMLElement).click();
|
|
fixture.detectChanges();
|
|
|
|
spyOn(calendarInstance.yearView, '_init').and.callThrough();
|
|
|
|
testComponent.maxDate = new Date(2017, DEC, 1);
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.yearView._init).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should not re-render the year view when the maxDate changes to the same day at a different time', () => {
|
|
fixture.detectChanges();
|
|
const periodButton = calendarElement.querySelector(
|
|
'.mat-calendar-period-button',
|
|
) as HTMLElement;
|
|
periodButton.click();
|
|
fixture.detectChanges();
|
|
|
|
(calendarElement.querySelector('.mat-calendar-body-active') as HTMLElement).click();
|
|
fixture.detectChanges();
|
|
|
|
spyOn(calendarInstance.yearView, '_init').and.callThrough();
|
|
|
|
testComponent.maxDate = new Date(2018, JAN, 1, 0, 0, 1, 0);
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.yearView._init).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should re-render the multi-year view when the minDate changes', () => {
|
|
fixture.detectChanges();
|
|
const periodButton = calendarElement.querySelector(
|
|
'.mat-calendar-period-button',
|
|
) as HTMLElement;
|
|
periodButton.click();
|
|
fixture.detectChanges();
|
|
|
|
spyOn(calendarInstance.multiYearView, '_init').and.callThrough();
|
|
|
|
testComponent.minDate = new Date(2017, NOV, 1);
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.multiYearView._init).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should re-render the multi-year view when the maxDate changes', () => {
|
|
fixture.detectChanges();
|
|
const periodButton = calendarElement.querySelector(
|
|
'.mat-calendar-period-button',
|
|
) as HTMLElement;
|
|
periodButton.click();
|
|
fixture.detectChanges();
|
|
|
|
spyOn(calendarInstance.multiYearView, '_init').and.callThrough();
|
|
|
|
testComponent.maxDate = new Date(2017, DEC, 1);
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.multiYearView._init).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should update the minDate in the child view if it changed after an interaction', () => {
|
|
fixture.destroy();
|
|
|
|
const dynamicFixture = TestBed.createComponent(CalendarWithSelectableMinDate);
|
|
dynamicFixture.detectChanges();
|
|
|
|
const calendarDebugElement = dynamicFixture.debugElement.query(By.directive(MatCalendar))!;
|
|
const disabledClass = 'mat-calendar-body-disabled';
|
|
calendarElement = calendarDebugElement.nativeElement;
|
|
calendarInstance = calendarDebugElement.componentInstance;
|
|
|
|
let cells = Array.from(calendarElement.querySelectorAll('.mat-calendar-body-cell'));
|
|
|
|
expect(cells.slice(0, 9).every(c => c.classList.contains(disabledClass)))
|
|
.withContext('Expected dates up to the 10th to be disabled.')
|
|
.toBe(true);
|
|
|
|
expect(cells.slice(9).every(c => c.classList.contains(disabledClass)))
|
|
.withContext('Expected dates after the 10th to be enabled.')
|
|
.toBe(false);
|
|
|
|
(cells[14] as HTMLElement).click();
|
|
dynamicFixture.detectChanges();
|
|
cells = Array.from(calendarElement.querySelectorAll('.mat-calendar-body-cell'));
|
|
|
|
expect(cells.slice(0, 14).every(c => c.classList.contains(disabledClass)))
|
|
.withContext('Expected dates up to the 14th to be disabled.')
|
|
.toBe(true);
|
|
|
|
expect(cells.slice(14).every(c => c.classList.contains(disabledClass)))
|
|
.withContext('Expected dates after the 14th to be enabled.')
|
|
.toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('calendar with date filter', () => {
|
|
let fixture: ComponentFixture<CalendarWithDateFilter>;
|
|
let testComponent: CalendarWithDateFilter;
|
|
let calendarElement: HTMLElement;
|
|
let calendarInstance: MatCalendar<Date>;
|
|
|
|
beforeEach(() => {
|
|
fixture = TestBed.createComponent(CalendarWithDateFilter);
|
|
fixture.detectChanges();
|
|
|
|
let calendarDebugElement = fixture.debugElement.query(By.directive(MatCalendar))!;
|
|
calendarElement = calendarDebugElement.nativeElement;
|
|
calendarInstance = calendarDebugElement.componentInstance;
|
|
testComponent = fixture.componentInstance;
|
|
});
|
|
|
|
it('should disable and prevent selection of filtered dates', () => {
|
|
let cells = calendarElement.querySelectorAll('.mat-calendar-body-cell');
|
|
(cells[0] as HTMLElement).click();
|
|
fixture.detectChanges();
|
|
|
|
expect(testComponent.selected).toBeFalsy();
|
|
|
|
(cells[1] as HTMLElement).click();
|
|
fixture.detectChanges();
|
|
|
|
expect(testComponent.selected).toEqual(new Date(2017, JAN, 2));
|
|
});
|
|
|
|
describe('a11y', () => {
|
|
let tableBodyEl: HTMLElement;
|
|
|
|
beforeEach(() => {
|
|
tableBodyEl = calendarElement.querySelector('.mat-calendar-body') as HTMLElement;
|
|
expect(tableBodyEl).not.toBeNull();
|
|
|
|
dispatchFakeEvent(tableBodyEl, 'focus');
|
|
fixture.detectChanges();
|
|
});
|
|
|
|
it('should not allow selection of disabled date in month view', () => {
|
|
expect(calendarInstance.currentView).toBe('month');
|
|
expect(calendarInstance.activeDate).toEqual(new Date(2017, JAN, 1));
|
|
|
|
dispatchKeyboardEvent(tableBodyEl, 'keydown', ENTER);
|
|
fixture.detectChanges();
|
|
|
|
expect(testComponent.selected).toBeUndefined();
|
|
});
|
|
|
|
it('should allow entering month view at disabled month', () => {
|
|
let periodButton = calendarElement.querySelector(
|
|
'.mat-calendar-period-button',
|
|
) as HTMLElement;
|
|
dispatchMouseEvent(periodButton, 'click');
|
|
fixture.detectChanges();
|
|
|
|
(calendarElement.querySelector('.mat-calendar-body-active') as HTMLElement).click();
|
|
fixture.detectChanges();
|
|
|
|
calendarInstance.activeDate = new Date(2017, NOV, 1);
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.currentView).toBe('year');
|
|
|
|
tableBodyEl = calendarElement.querySelector('.mat-calendar-body') as HTMLElement;
|
|
dispatchKeyboardEvent(tableBodyEl, 'keydown', ENTER);
|
|
fixture.detectChanges();
|
|
dispatchKeyboardEvent(tableBodyEl, 'keyup', ENTER);
|
|
fixture.detectChanges();
|
|
|
|
expect(calendarInstance.currentView).toBe('month');
|
|
expect(testComponent.selected).toBeUndefined();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
@Component({
|
|
template: `
|
|
<mat-calendar
|
|
[startAt]="startDate"
|
|
[(selected)]="selected"
|
|
(yearSelected)="selectedYear=$event"
|
|
(monthSelected)="selectedMonth=$event">
|
|
</mat-calendar>`,
|
|
standalone: false,
|
|
})
|
|
class StandardCalendar {
|
|
selected: Date;
|
|
selectedYear: Date;
|
|
selectedMonth: Date;
|
|
startDate = new Date(2017, JAN, 31);
|
|
}
|
|
|
|
@Component({
|
|
template: `
|
|
<mat-calendar [startAt]="startAt" [minDate]="minDate" [maxDate]="maxDate"></mat-calendar>
|
|
`,
|
|
standalone: false,
|
|
})
|
|
class CalendarWithMinMax {
|
|
startAt: Date;
|
|
minDate = new Date(2016, JAN, 1);
|
|
maxDate = new Date(2018, JAN, 1);
|
|
}
|
|
|
|
@Component({
|
|
template: `
|
|
<mat-calendar [startAt]="startDate" [(selected)]="selected" [dateFilter]="dateFilter">
|
|
</mat-calendar>
|
|
`,
|
|
standalone: false,
|
|
})
|
|
class CalendarWithDateFilter {
|
|
selected: Date;
|
|
startDate = new Date(2017, JAN, 1);
|
|
|
|
dateFilter(date: Date) {
|
|
return !(date.getDate() % 2) && date.getMonth() !== NOV;
|
|
}
|
|
}
|
|
|
|
@Component({
|
|
template: `
|
|
<mat-calendar
|
|
[startAt]="startAt"
|
|
(selectedChange)="select($event)"
|
|
[selected]="selected"
|
|
[minDate]="selected">
|
|
</mat-calendar>
|
|
`,
|
|
standalone: false,
|
|
})
|
|
class CalendarWithSelectableMinDate {
|
|
startAt = new Date(2018, JUL, 0);
|
|
selected: Date;
|
|
minDate: Date;
|
|
|
|
constructor() {
|
|
this.select(new Date(2018, JUL, 10));
|
|
}
|
|
|
|
select(value: Date) {
|
|
this.minDate = this.selected = value;
|
|
}
|
|
}
|