sass-references/angular-material/material/datepicker/calendar-header.spec.ts

413 lines
14 KiB
TypeScript

import {Directionality} from '@angular/cdk/bidi';
import {Component} from '@angular/core';
import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing';
import {MatNativeDateModule, DateAdapter} from '@angular/material/core';
import {DEC, FEB, JAN} from '../testing';
import {By} from '@angular/platform-browser';
import {MatCalendar} from './calendar';
import {MatDatepickerIntl} from './datepicker-intl';
import {MatDatepickerModule} from './datepicker-module';
import {yearsPerPage} from './multi-year-view';
describe('MatCalendarHeader', () => {
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [
MatNativeDateModule,
MatDatepickerModule,
// Test components.
StandardCalendar,
CalendarWithMinMaxDate,
],
providers: [MatDatepickerIntl, {provide: Directionality, useFactory: () => ({value: 'ltr'})}],
});
}));
describe('standard calendar', () => {
let fixture: ComponentFixture<StandardCalendar>;
let testComponent: StandardCalendar;
let calendarElement: HTMLElement;
let periodButton: HTMLElement;
let prevButton: HTMLElement;
let nextButton: 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;
prevButton = calendarElement.querySelector('.mat-calendar-previous-button') as HTMLElement;
nextButton = calendarElement.querySelector('.mat-calendar-next-button') as HTMLElement;
calendarInstance = calendarDebugElement.componentInstance;
testComponent = fixture.componentInstance;
});
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 toggle view when period clicked', () => {
expect(calendarInstance.currentView).toBe('month');
periodButton.click();
fixture.detectChanges();
expect(calendarInstance.currentView).toBe('multi-year');
periodButton.click();
fixture.detectChanges();
expect(calendarInstance.currentView).toBe('month');
});
it("should emit viewChanged when view changed from 'month' to 'multi-year'", () => {
expect(calendarInstance.currentView).toBe('month');
spyOn(calendarInstance.viewChanged, 'emit');
periodButton.click();
fixture.detectChanges();
expect(calendarInstance.viewChanged.emit).toHaveBeenCalledWith('multi-year');
});
it("should emit viewChanged when view changed from 'multi-year' to 'month'", () => {
periodButton.click();
fixture.detectChanges();
expect(calendarInstance.currentView).toBe('multi-year');
spyOn(calendarInstance.viewChanged, 'emit');
periodButton.click();
fixture.detectChanges();
expect(calendarInstance.viewChanged.emit).toHaveBeenCalledWith('month');
});
it("should emit viewChanged when view changed from 'multi-year' to 'year'", () => {
periodButton.click();
fixture.detectChanges();
expect(calendarInstance.currentView).toBe('multi-year');
spyOn(calendarInstance.viewChanged, 'emit');
(calendarElement.querySelector('.mat-calendar-body-active') as HTMLElement).click();
fixture.detectChanges();
expect(calendarInstance.viewChanged.emit).toHaveBeenCalledWith('year');
});
it('should go to next and previous month', () => {
expect(calendarInstance.activeDate).toEqual(new Date(2017, JAN, 31));
nextButton.click();
fixture.detectChanges();
expect(calendarInstance.activeDate).toEqual(new Date(2017, FEB, 28));
prevButton.click();
fixture.detectChanges();
expect(calendarInstance.activeDate).toEqual(new Date(2017, JAN, 28));
});
it('should go to previous and next year', () => {
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');
nextButton.click();
fixture.detectChanges();
expect(calendarInstance.activeDate).toEqual(new Date(2018, JAN, 31));
prevButton.click();
fixture.detectChanges();
expect(calendarInstance.activeDate).toEqual(new Date(2017, JAN, 31));
});
it('should go to previous and next multi-year range', () => {
periodButton.click();
fixture.detectChanges();
expect(calendarInstance.currentView).toBe('multi-year');
expect(calendarInstance.activeDate).toEqual(new Date(2017, JAN, 31));
nextButton.click();
fixture.detectChanges();
expect(calendarInstance.activeDate).toEqual(new Date(2017 + yearsPerPage, JAN, 31));
prevButton.click();
fixture.detectChanges();
expect(calendarInstance.activeDate).toEqual(new Date(2017, JAN, 31));
});
it('should go back to month view after selecting year and month', () => {
periodButton.click();
fixture.detectChanges();
expect(calendarInstance.currentView).toBe('multi-year');
expect(calendarInstance.activeDate).toEqual(new Date(2017, JAN, 31));
let yearCells = calendarElement.querySelectorAll('.mat-calendar-body-cell');
(yearCells[0] as HTMLElement).click();
fixture.detectChanges();
expect(calendarInstance.currentView).toBe('year');
expect(calendarInstance.activeDate).toEqual(new Date(2016, JAN, 31));
let monthCells = calendarElement.querySelectorAll('.mat-calendar-body-cell');
(monthCells[monthCells.length - 1] as HTMLElement).click();
fixture.detectChanges();
expect(calendarInstance.currentView).toBe('month');
expect(calendarInstance.activeDate).toEqual(new Date(2016, DEC, 31));
expect(testComponent.selected).withContext('no date should be selected yet').toBeFalsy();
});
it('should format the year in the period button using the date adapter', () => {
const adapter = fixture.debugElement.injector.get(DateAdapter);
spyOn(adapter, 'getYearName').and.returnValue('FAKE_YEAR');
periodButton.click();
fixture.detectChanges();
expect(calendarInstance.currentView).toBe('multi-year');
expect(periodButton.textContent).toContain('FAKE_YEAR');
});
it('should label and describe period button for assistive technology', () => {
expect(calendarInstance.currentView).toBe('month');
periodButton.click();
fixture.detectChanges();
expect(calendarInstance.currentView).toBe('multi-year');
expect(periodButton.hasAttribute('aria-label')).toBe(true);
expect(periodButton.getAttribute('aria-label')).toMatch(/^[a-z0-9\s]+$/i);
expect(periodButton.hasAttribute('aria-describedby')).toBe(true);
expect(periodButton.getAttribute('aria-describedby')).toMatch(
/mat-calendar-period-label-\w+[0-9]+/i,
);
});
});
describe('calendar with minDate only', () => {
let fixture: ComponentFixture<CalendarWithMinMaxDate>;
let testComponent: CalendarWithMinMaxDate;
let calendarElement: HTMLElement;
let periodButton: HTMLButtonElement;
let prevButton: HTMLButtonElement;
let nextButton: HTMLButtonElement;
let calendarInstance: MatCalendar<Date>;
beforeEach(() => {
fixture = TestBed.createComponent(CalendarWithMinMaxDate);
fixture.detectChanges();
let calendarDebugElement = fixture.debugElement.query(By.directive(MatCalendar))!;
calendarElement = calendarDebugElement.nativeElement;
periodButton = calendarElement.querySelector(
'.mat-calendar-period-button',
) as HTMLButtonElement;
prevButton = calendarElement.querySelector(
'.mat-calendar-previous-button',
) as HTMLButtonElement;
nextButton = calendarElement.querySelector('.mat-calendar-next-button') as HTMLButtonElement;
calendarInstance = calendarDebugElement.componentInstance;
testComponent = fixture.componentInstance;
});
it('should start the first page with minDate', () => {
testComponent.minDate = new Date(2010, JAN, 1);
periodButton.click();
fixture.detectChanges();
expect(calendarInstance.currentView).toBe('multi-year');
expect(periodButton.innerText.trim()).toEqual('2010 \u2013 2033');
});
it('should disable the page before the one showing minDate', () => {
testComponent.minDate = new Date(2010, JAN, 1);
periodButton.click();
fixture.detectChanges();
expect(calendarInstance.currentView).toBe('multi-year');
expect(prevButton.disabled).toBe(true);
});
it('should enable the page after the one showing minDate', () => {
testComponent.minDate = new Date(2010, JAN, 1);
periodButton.click();
fixture.detectChanges();
expect(calendarInstance.currentView).toBe('multi-year');
expect(nextButton.disabled).toBe(false);
});
});
describe('calendar with maxDate only', () => {
let fixture: ComponentFixture<CalendarWithMinMaxDate>;
let testComponent: CalendarWithMinMaxDate;
let calendarElement: HTMLElement;
let periodButton: HTMLButtonElement;
let prevButton: HTMLButtonElement;
let nextButton: HTMLButtonElement;
let calendarInstance: MatCalendar<Date>;
beforeEach(() => {
fixture = TestBed.createComponent(CalendarWithMinMaxDate);
fixture.detectChanges();
let calendarDebugElement = fixture.debugElement.query(By.directive(MatCalendar))!;
calendarElement = calendarDebugElement.nativeElement;
periodButton = calendarElement.querySelector(
'.mat-calendar-period-button',
) as HTMLButtonElement;
prevButton = calendarElement.querySelector(
'.mat-calendar-previous-button',
) as HTMLButtonElement;
nextButton = calendarElement.querySelector('.mat-calendar-next-button') as HTMLButtonElement;
calendarInstance = calendarDebugElement.componentInstance;
testComponent = fixture.componentInstance;
});
it('should end the last page with maxDate', () => {
testComponent.maxDate = new Date(2020, JAN, 1);
periodButton.click();
fixture.detectChanges();
expect(calendarInstance.currentView).toBe('multi-year');
expect(periodButton.innerText.trim()).toEqual('1997 \u2013 2020');
});
it('should disable the page after the one showing maxDate', () => {
testComponent.maxDate = new Date(2020, JAN, 1);
periodButton.click();
fixture.detectChanges();
expect(calendarInstance.currentView).toBe('multi-year');
expect(nextButton.disabled).toBe(true);
});
it('should enable the page before the one showing maxDate', () => {
testComponent.maxDate = new Date(2020, JAN, 1);
periodButton.click();
fixture.detectChanges();
expect(calendarInstance.currentView).toBe('multi-year');
expect(prevButton.disabled).toBe(false);
});
});
describe('calendar with minDate and maxDate', () => {
let fixture: ComponentFixture<CalendarWithMinMaxDate>;
let testComponent: CalendarWithMinMaxDate;
let calendarElement: HTMLElement;
let periodButton: HTMLButtonElement;
let prevButton: HTMLButtonElement;
let nextButton: HTMLButtonElement;
let calendarInstance: MatCalendar<Date>;
beforeEach(() => {
fixture = TestBed.createComponent(CalendarWithMinMaxDate);
fixture.detectChanges();
let calendarDebugElement = fixture.debugElement.query(By.directive(MatCalendar))!;
calendarElement = calendarDebugElement.nativeElement;
periodButton = calendarElement.querySelector(
'.mat-calendar-period-button',
) as HTMLButtonElement;
prevButton = calendarElement.querySelector(
'.mat-calendar-previous-button',
) as HTMLButtonElement;
nextButton = calendarElement.querySelector('.mat-calendar-next-button') as HTMLButtonElement;
calendarInstance = calendarDebugElement.componentInstance;
testComponent = fixture.componentInstance;
});
it('should end the last page with maxDate', () => {
testComponent.minDate = new Date(1993, JAN, 1);
testComponent.maxDate = new Date(2020, JAN, 1);
periodButton.click();
fixture.detectChanges();
expect(calendarInstance.currentView).toBe('multi-year');
expect(periodButton.innerText.trim()).toEqual('1997 \u2013 2020');
});
it('should disable the page after the one showing maxDate', () => {
testComponent.minDate = new Date(1993, JAN, 1);
testComponent.maxDate = new Date(2020, JAN, 1);
periodButton.click();
fixture.detectChanges();
expect(calendarInstance.currentView).toBe('multi-year');
expect(nextButton.disabled).toBe(true);
});
it('should disable the page before the one showing minDate', () => {
testComponent.minDate = new Date(1993, JAN, 1);
testComponent.maxDate = new Date(2020, JAN, 1);
periodButton.click();
fixture.detectChanges();
expect(calendarInstance.currentView).toBe('multi-year');
prevButton.click();
fixture.detectChanges();
expect(calendarInstance.activeDate).toEqual(new Date(2018 - yearsPerPage, JAN, 1));
expect(prevButton.disabled).toBe(true);
});
});
});
@Component({
template: `
<mat-calendar
[startAt]="startDate"
[(selected)]="selected"
(yearSelected)="selectedYear=$event"
(monthSelected)="selectedMonth=$event">
</mat-calendar>`,
standalone: true,
imports: [MatNativeDateModule, MatDatepickerModule],
})
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: true,
imports: [MatNativeDateModule, MatDatepickerModule],
})
class CalendarWithMinMaxDate {
startAt = new Date(2018, JAN, 1);
minDate: Date | null;
maxDate: Date | null;
}