import { Component, Renderer2, ViewChild } from '@angular/core';
import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { dispatchKeyboardEvent } from '@ngneat/spectator';
import { registerEscClick } from 'ngx-bootstrap/utils';
import { BsDatepickerDirective } from '../bs-datepicker.component';
import { BsDatepickerConfig } from '../bs-datepicker.config';
import { BsDatepickerModule } from '../bs-datepicker.module';
import { BsDatepickerViewMode, CalendarCellViewModel, WeekViewModel } from '../models';
import { BsDatepickerContainerComponent } from '../themes/bs/bs-datepicker-container.component';
@Component({
selector: 'test-cmp',
template: ``
})
class TestComponent {
@ViewChild(BsDatepickerDirective, { static: false }) datepicker: BsDatepickerDirective;
bsConfig: Partial = {
displayMonths: 2,
selectWeek: true,
showTodayButton: true
};
}
type TestFixture = ComponentFixture;
function getDatepickerDirective(fixture: TestFixture): BsDatepickerDirective {
return fixture.componentInstance.datepicker;
}
function showDatepicker(fixture: TestFixture): BsDatepickerDirective {
const datepicker = getDatepickerDirective(fixture);
datepicker.show();
fixture.detectChanges();
return datepicker;
}
function hideDatepicker(fixture: TestFixture): BsDatepickerDirective {
const datepicker = getDatepickerDirective(fixture);
datepicker.hide();
fixture.detectChanges();
return datepicker;
}
function getDatepickerContainer(datepicker: BsDatepickerDirective): BsDatepickerContainerComponent | null {
return datepicker[`_datepickerRef`] ? datepicker[`_datepickerRef`].instance : null;
}
describe('datepicker:', () => {
let fixture: TestFixture;
beforeEach(
waitForAsync(() => TestBed.configureTestingModule({
declarations: [TestComponent],
imports: [
BsDatepickerModule.forRoot(),
BrowserAnimationsModule
]
}).compileComponents()
));
beforeEach(() => {
fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();
});
it('should display datepicker on show', fakeAsync(() => {
const datepicker = showDatepicker(fixture);
tick(10);
expect(getDatepickerContainer(datepicker)).toBeDefined();
}));
it('should hide datepicker on hide', () => {
const datepicker = hideDatepicker(fixture);
expect(getDatepickerContainer(datepicker)).toBeNull();
});
it('should select correct year when a month other than selected year is chosen', () => {
const datepicker = showDatepicker(fixture);
const datepickerContainerInstance = getDatepickerContainer(datepicker);
const yearSelection: CalendarCellViewModel = { date: new Date(2017, 1, 1), label: 'label' };
const monthSelection: CalendarCellViewModel = { date: new Date(2018, 1, 1), label: 'label' };
datepickerContainerInstance.yearSelectHandler(yearSelection);
datepickerContainerInstance.monthSelectHandler(monthSelection);
fixture.detectChanges();
datepickerContainerInstance[`_store`]
.select(state => state.view)
.subscribe(view => {
expect(view.date.getFullYear()).toEqual(monthSelection.date.getFullYear());
});
});
it('should select a week, when selectWeek flag is true', () => {
const datepicker = showDatepicker(fixture);
const datepickerContainerInstance = getDatepickerContainer(datepicker);
datepickerContainerInstance.setViewMode('day');
const weekSelection: WeekViewModel = {
days: [
{ date: new Date(2019, 1, 6), label: 'label' },
{ date: new Date(2019, 1, 7), label: 'label' },
{ date: new Date(2019, 1, 8), label: 'label' },
{ date: new Date(2019, 1, 9), label: 'label' },
{ date: new Date(2019, 1, 10), label: 'label' },
{ date: new Date(2019, 1, 11), label: 'label' },
{ date: new Date(2019, 1, 12), label: 'label' }
], isHovered: true
};
datepickerContainerInstance.weekHoverHandler(weekSelection);
fixture.detectChanges();
datepickerContainerInstance[`_store`]
.select(state => state.view)
.subscribe(view => {
const currentDate = `${view.date.getDate()}${view.date.getFullYear()}`;
const oldDate = `${weekSelection.days[0].date.getDate()}${weekSelection.days[0].date.getFullYear()}`;
expect(currentDate).not.toEqual(oldDate);
});
});
it('should hide on esc', waitForAsync(() => {
const datepicker = showDatepicker(fixture);
const spy = jest.spyOn(datepicker, 'hide');
const renderer = fixture.componentRef.injector.get(Renderer2);
registerEscClick(renderer, {
outsideEsc: true,
target: fixture.nativeElement,
hide: () => datepicker.hide()
});
dispatchKeyboardEvent(document, 'keyup', 'Escape');
expect(spy).toHaveBeenCalled();
}));
it('should show the today button when showTodayButton config is true', fakeAsync(() => {
showDatepicker(fixture);
tick();
fixture.whenStable().then(() => {
const buttonText: string[] = [];
Array.from(document.body.getElementsByTagName('button'))
.forEach(button => buttonText.push(button.textContent));
expect(buttonText.filter(button => button === 'Today').length).toEqual(1);
});
expect(true).toBeTruthy();
}));
it('should show custom label for today button if set in config', () => {
const todayBtnCustomLbl = 'Select today';
const datepickerDirective = getDatepickerDirective(fixture);
datepickerDirective.bsConfig = {
todayButtonLabel: todayBtnCustomLbl,
showTodayButton: true
};
showDatepicker(fixture);
const buttonText: string[] = [];
Array.from(document.body.getElementsByTagName('button'))
.forEach(button => buttonText.push(button.textContent));
expect(buttonText.filter(button => button === todayBtnCustomLbl).length).toEqual(1);
});
it('should show custom label for clear button if set in config', () => {
const clearBtnCustomLbl = 'Clear current';
const datepickerDirective = getDatepickerDirective(fixture);
datepickerDirective.bsConfig = {
clearButtonLabel: clearBtnCustomLbl,
showClearButton: true
};
showDatepicker(fixture);
const buttonText: string[] = [];
// fixture.debugElement.queryAll(By.css('button'))
Array.from(document.body.getElementsByTagName('button'))
.forEach(button => buttonText.push(button.textContent));
expect(buttonText.filter(button => button === clearBtnCustomLbl).length).toEqual(1);
});
describe('should start with', () => {
const parameters = [
{
description: 'year view if set in config',
startView: 'year',
expectedVisibleContainer: ['bs-years-calendar-view'],
expectedInvisibleContainer: ['bs-month-calendar-view', 'bs-days-calendar-view'],
expectedViewMode: 'year'
},
{
description: 'month view if set in config',
startView: 'month',
expectedVisibleContainer: ['bs-month-calendar-view'],
expectedInvisibleContainer: ['bs-years-calendar-view', 'bs-days-calendar-view'],
expectedViewMode: 'month'
},
{
description: 'day view if set in config',
startView: 'day',
expectedVisibleContainer: ['bs-days-calendar-view'],
expectedInvisibleContainer: ['bs-years-calendar-view', 'bs-month-calendar-view'],
expectedViewMode: 'day'
}
];
parameters.forEach(parameter => {
it(parameter.description, done => {
const datepickerDirective = getDatepickerDirective(fixture);
datepickerDirective.bsConfig = {
startView: parameter.startView as BsDatepickerViewMode
};
const bsDatepickerDirective = showDatepicker(fixture);
const datepickerContainerInstance = getDatepickerContainer(bsDatepickerDirective);
parameter.expectedVisibleContainer.forEach(container => {
expect(datepickerContainerInstance[`_element`].nativeElement.querySelectorAll(container)[0]).toBeTruthy();
});
parameter.expectedInvisibleContainer.forEach(container => {
expect(datepickerContainerInstance[`_element`].nativeElement.querySelectorAll(container)[0]).toBeFalsy();
});
datepickerContainerInstance.viewMode.subscribe(res => {
expect(res).toBe(parameter.expectedViewMode);
done();
});
});
});
});
it('should set today date', () => {
const datepicker = showDatepicker(fixture);
const datepickerContainerInstance = getDatepickerContainer(datepicker);
datepickerContainerInstance[`_store`]
.select(state => state.view)
.subscribe(view => {
view.date = new Date(2020, 0, 1);
}).unsubscribe();
fixture.detectChanges();
datepickerContainerInstance[`_store`]
.select(state => state.view)
.subscribe(view => {
expect(`${(view.date.getDate())}-${(view.date.getMonth())}-${(view.date.getFullYear())}`)
.not.toEqual(`${(new Date().getDate())}-${(new Date().getMonth())}-${(new Date().getFullYear())}`);
}).unsubscribe();
datepickerContainerInstance.setToday();
fixture.detectChanges();
datepickerContainerInstance[`_store`]
.select(state => state.view)
.subscribe(view => {
expect(`${(view.date.getDate())}-${(view.date.getMonth())}-${(view.date.getFullYear())}`)
.toEqual(`${(new Date().getDate())}-${(new Date().getMonth())}-${(new Date().getFullYear())}`);
}).unsubscribe();
});
it('should clear date', () => {
const datepicker = showDatepicker(fixture);
const datepickerContainerInstance = getDatepickerContainer(datepicker);
datepickerContainerInstance.clearDate();
fixture.detectChanges();
datepickerContainerInstance[`_store`]
.select(state => state.selectedDate)
.subscribe(date => {
expect(date).toBe(undefined);
}).unsubscribe();
});
it('should display one timepicker when withTimepicker is true', () => {
const datepickerDirective = getDatepickerDirective(fixture);
datepickerDirective.bsConfig = {
withTimepicker: true
};
showDatepicker(fixture);
const timepickerZone = document.querySelector('.bs-timepicker-in-datepicker-container');
const timepickers = document.querySelectorAll('timepicker');
expect(timepickerZone).toBeTruthy();
expect(timepickers.length).toEqual(1);
});
it('should not display timepicker when withTimepicker is true', () => {
const datepickerDirective = getDatepickerDirective(fixture);
datepickerDirective.bsConfig = {
withTimepicker: false
};
showDatepicker(fixture);
const timepickerZone = document.querySelector('.bs-timepicker-in-datepicker-container');
expect(timepickerZone).not.toBeTruthy();
});
});