Skip to content

Commit 2c89abc

Browse files
committed
test(date-picker): add test for control value accessor, #6471
# Conflicts: # projects/igniteui-angular/src/lib/date-picker/date-picker.component.spec.ts
1 parent 7065375 commit 2c89abc

File tree

2 files changed

+170
-31
lines changed

2 files changed

+170
-31
lines changed

projects/igniteui-angular/src/lib/date-picker/date-picker.component.spec.ts

+168-29
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
1-
import { Component, ViewChild, ElementRef } from '@angular/core';
1+
import { Component, ViewChild, ElementRef, EventEmitter } from '@angular/core';
22
import { async, fakeAsync, TestBed, tick, flush, ComponentFixture } from '@angular/core/testing';
3-
import { FormsModule, FormGroup, FormBuilder, FormControl, ReactiveFormsModule } from '@angular/forms';
3+
import { FormsModule, FormGroup, FormBuilder, ReactiveFormsModule, Validators, AbstractControlOptions } from '@angular/forms';
44
import { By } from '@angular/platform-browser';
55
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
66
import { IgxDatePickerComponent, IgxDatePickerModule } from './date-picker.component';
77
import { IgxLabelDirective } from '../directives/label/label.directive';
88
import { IgxInputDirective } from '../directives/input/input.directive';
99
import { UIInteractions, wait } from '../test-utils/ui-interactions.spec';
10-
import { IgxInputGroupModule } from '../input-group';
10+
import { IgxInputGroupModule, IgxInputGroupComponent } from '../input-group';
1111
import { IgxTextSelectionModule } from '../directives/text-selection/text-selection.directive';
1212
import { configureTestSuite } from '../test-utils/configure-suite';
13-
import { DateRangeType } from 'igniteui-angular';
1413
import { IgxButtonModule } from '../directives/button/button.directive';
1514
import { IgxCalendarModule } from '../calendar';
1615
import { InteractionMode } from '../core/enums';
16+
import { DateRangeType } from '../core/dates/dateRange';
17+
import { OverlayCancelableEventArgs, OverlayEventArgs, OverlayClosingEventArgs } from '../services';
1718

18-
describe('IgxDatePicker', () => {
19+
fdescribe('IgxDatePicker', () => {
1920
configureTestSuite();
2021
beforeEach(async(() => {
2122
TestBed.configureTestingModule({
@@ -1262,49 +1263,161 @@ describe('IgxDatePicker', () => {
12621263

12631264
describe('Reactive form', () => {
12641265
let fixture: ComponentFixture<IgxDatePickerReactiveFormComponent>;
1265-
let datePicker: IgxDatePickerComponent;
1266+
let datePickerOnChange: IgxDatePickerComponent;
1267+
let datePickerOnBlur: IgxDatePickerComponent;
12661268

12671269
beforeEach(() => {
12681270
fixture = TestBed.createComponent(IgxDatePickerReactiveFormComponent);
1269-
datePicker = fixture.componentInstance.datePicker;
1271+
datePickerOnChange = fixture.componentInstance.datePickerOnChange;
1272+
datePickerOnBlur = fixture.componentInstance.datePickerOnBlur;
12701273
fixture.detectChanges();
12711274
});
12721275

1273-
it('Should properly initialize when used as a form control in reactive form', fakeAsync(() => {
1274-
expect(datePicker).toBeDefined();
1275-
expect(datePicker.value).toEqual(new Date(2000, 10, 15));
1276+
it('Should properly initialize when used as a form control in reactive form', () => {
1277+
expect(datePickerOnChange).toBeDefined();
1278+
expect(datePickerOnChange.value).toEqual(new Date(2000, 10, 15));
12761279

1277-
const datePickerFormReference = fixture.componentInstance.reactiveForm.controls.datePickerReactive;
1280+
const datePickerFormReference = fixture.componentInstance.reactiveFormOnChange.controls.datePickerReactiveOnChange;
12781281
expect(datePickerFormReference).toBeDefined();
12791282
expect(datePickerFormReference.status).toEqual('VALID');
1283+
});
1284+
1285+
it('Should set date picker status to invalid when it is required and has no value', fakeAsync(() => {
1286+
const inputGroup = (datePickerOnChange as any).inputGroup as IgxInputGroupComponent;
1287+
const datePickerFormReference = fixture.componentInstance.reactiveFormOnChange.controls.datePickerReactiveOnChange;
1288+
expect(datePickerFormReference.status).toEqual('VALID');
1289+
expect(inputGroup.isRequired).toBeFalsy();
1290+
expect(inputGroup.validClass).toBeFalsy();
1291+
1292+
const form = fixture.componentInstance.reactiveFormOnChange;
1293+
form.controls.datePickerReactiveOnChange.setValidators(Validators.required);
1294+
datePickerOnChange.value = null;
1295+
fixture.detectChanges();
1296+
expect(inputGroup.isRequired).toBeTruthy();
1297+
expect(inputGroup.validClass).toBeFalsy();
1298+
expect(datePickerFormReference.status).toEqual('INVALID');
1299+
}));
1300+
1301+
it('Should set date picker status to invalid when it is required and has no value onBlur', fakeAsync(() => {
1302+
const formGroup = fixture.componentInstance.reactiveFormOnBlur;
1303+
datePickerOnBlur.mode = InteractionMode.DropDown;
1304+
datePickerOnBlur.mask = 'dd/mm/yyyy';
1305+
datePickerOnBlur.inputMask = 'dd/mm/yyyy';
1306+
fixture.detectChanges();
1307+
1308+
const inputElement = (datePickerOnBlur as any).inputGroup.input.element.nativeElement;
1309+
inputElement.click();
1310+
inputElement.focus();
1311+
tick();
1312+
fixture.detectChanges();
1313+
1314+
const inputGroup = (datePickerOnBlur as any).inputGroup as IgxInputGroupComponent;
1315+
expect(formGroup.controls.datePickerReactiveOnBlur.status).toEqual('VALID');
1316+
expect(inputGroup.isRequired).toBeFalsy();
1317+
expect(inputGroup.validClass).toBeFalsy();
1318+
1319+
formGroup.controls.datePickerReactiveOnBlur.setValidators(Validators.required);
1320+
fixture.detectChanges();
1321+
1322+
datePickerOnBlur.value = null;
1323+
fixture.detectChanges();
1324+
expect(inputGroup.isRequired).toBeFalsy();
1325+
expect(inputGroup.validClass).toBeFalsy();
1326+
expect(formGroup.controls.datePickerReactiveOnBlur.status).toEqual('VALID');
1327+
1328+
inputElement.blur();
1329+
fixture.detectChanges();
1330+
expect(inputGroup.isRequired).toBeTruthy();
1331+
expect(inputGroup.validClass).toBeFalsy();
1332+
expect(formGroup.controls.datePickerReactiveOnBlur.status).toEqual('INVALID');
12801333
}));
12811334

12821335
// Bug #6025 Date picker does not disable in reactive form
12831336
it('Should disable when form is disabled', fakeAsync(() => {
12841337
fixture.detectChanges();
1285-
const formGroup: FormGroup = fixture.componentInstance.reactiveForm;
1286-
const inputGroup = fixture.debugElement.query(By.css('.igx-input-group'));
1338+
const formGroup: FormGroup = fixture.componentInstance.reactiveFormOnChange;
1339+
const inputGroup = (datePickerOnChange as any).inputGroup as IgxInputGroupComponent;
12871340

1288-
inputGroup.nativeElement.click();
1289-
tick();
1341+
inputGroup.element.nativeElement.click();
12901342
fixture.detectChanges();
1291-
expect(datePicker.collapsed).toBeFalsy();
1343+
tick(500);
1344+
expect(datePickerOnChange.collapsed).toBeFalsy();
12921345

1293-
datePicker.closeCalendar();
1294-
tick();
1346+
datePickerOnChange.closeCalendar();
12951347
fixture.detectChanges();
1348+
tick();
1349+
expect(datePickerOnChange.collapsed).toBeTruthy();
12961350

12971351
formGroup.disable();
1298-
tick();
12991352
fixture.detectChanges();
1300-
1301-
inputGroup.nativeElement.click();
13021353
tick();
1354+
1355+
inputGroup.element.nativeElement.parentElement.click();
13031356
fixture.detectChanges();
1357+
tick();
13041358
const dateDropDown = document.getElementsByClassName('igx-date-picker--dropdown');
13051359
expect(dateDropDown.length).toEqual(0);
13061360
}));
13071361
});
1362+
1363+
describe('Control value accessor unit tests', () => {
1364+
let ngModel;
1365+
let overlay;
1366+
let element;
1367+
let cdr;
1368+
let moduleRef;
1369+
let injector;
1370+
let inputGroup: IgxInputGroupComponent;
1371+
1372+
beforeEach(() => {
1373+
ngModel = {
1374+
control: { touched: false, dirty: false, validator: null },
1375+
valid: false,
1376+
statusChanges: new EventEmitter(),
1377+
};
1378+
overlay = {
1379+
onOpening: new EventEmitter<OverlayCancelableEventArgs>(),
1380+
onOpened: new EventEmitter<OverlayEventArgs>(),
1381+
onClosed: new EventEmitter<OverlayEventArgs>(),
1382+
onClosing: new EventEmitter<OverlayClosingEventArgs>()
1383+
};
1384+
element = {};
1385+
cdr = { markForCheck: () => {}};
1386+
moduleRef = {};
1387+
injector = { get: () => ngModel };
1388+
inputGroup = new IgxInputGroupComponent(null, null);
1389+
});
1390+
1391+
it('should initialize date picker with required correctly', () => {
1392+
const datePicker = new IgxDatePickerComponent(overlay, element, cdr, moduleRef, injector);
1393+
datePicker['inputGroup'] = inputGroup;
1394+
ngModel.control.validator = () => ({ required: true});
1395+
datePicker.ngOnInit();
1396+
datePicker.ngAfterViewInit();
1397+
1398+
expect(datePicker).toBeDefined();
1399+
expect(inputGroup.isRequired).toBeTruthy();
1400+
});
1401+
1402+
it('should update inputGroup isRequired correctly', () => {
1403+
const datePicker = new IgxDatePickerComponent(overlay, element, cdr, moduleRef, injector);
1404+
datePicker['inputGroup'] = inputGroup;
1405+
datePicker.ngOnInit();
1406+
datePicker.ngAfterViewInit();
1407+
expect(datePicker).toBeDefined();
1408+
1409+
ngModel.statusChanges.emit();
1410+
expect(inputGroup.isRequired).toBeFalsy();
1411+
1412+
ngModel.control.validator = () => ({ required: true});
1413+
ngModel.statusChanges.emit();
1414+
expect(inputGroup.isRequired).toBeTruthy();
1415+
1416+
ngModel.control.validator = () => ({ required: false});
1417+
ngModel.statusChanges.emit();
1418+
expect(inputGroup.isRequired).toBeFalsy();
1419+
});
1420+
});
13081421
});
13091422

13101423
@Component({
@@ -1453,20 +1566,46 @@ export class IgxDatePickerOpeningComponent {
14531566

14541567
@Component({
14551568
template: `
1456-
<form [formGroup]="reactiveForm" (ngSubmit)="onSubmitReactive()">
1457-
<igx-date-picker formControlName="datePickerReactive" #datePickerReactive></igx-date-picker>
1458-
<button type="submit" [disabled]="!reactiveForm.valid">Submit</button>
1569+
<form [formGroup]="reactiveFormOnChange" (ngSubmit)="onSubmitReactive()">
1570+
<igx-date-picker formControlName="datePickerReactiveOnChange" #datePickerReactiveOnChange></igx-date-picker>
1571+
<button #submitButtonOnChange type="submit" [disabled]="!reactiveFormOnChange.valid">Submit</button>
1572+
</form>
1573+
<form [formGroup]="reactiveFormOnBlur" (ngSubmit)="onSubmitReactive()">
1574+
<igx-date-picker formControlName="datePickerReactiveOnBlur" #datePickerReactiveOnBlur></igx-date-picker>
1575+
<button #submitButtonOnBlur type="submit" [disabled]="!reactiveFormOnBlur.valid">Submit</button>
14591576
</form>
14601577
`
14611578
})
14621579
class IgxDatePickerReactiveFormComponent {
1463-
@ViewChild('datePickerReactive', { read: IgxDatePickerComponent, static: true })
1464-
public datePicker: IgxDatePickerComponent;
1465-
reactiveForm: FormGroup;
1580+
@ViewChild('datePickerReactiveOnChange', { read: IgxDatePickerComponent, static: true })
1581+
public datePickerOnChange: IgxDatePickerComponent;
1582+
1583+
@ViewChild('datePickerReactiveOnBlur', { read: IgxDatePickerComponent, static: true })
1584+
public datePickerOnBlur: IgxDatePickerComponent;
1585+
1586+
@ViewChild('submitButtonOnChange', { static: true })
1587+
public submitButtonOnChange: ElementRef;
1588+
1589+
@ViewChild('submitButtonOnBlur', { static: true })
1590+
public submitButtonOnBlur: ElementRef;
1591+
1592+
reactiveFormOnChange: FormGroup;
1593+
reactiveFormOnBlur: FormGroup;
1594+
1595+
public validatorOptions: AbstractControlOptions = {
1596+
validators: [],
1597+
asyncValidators: [],
1598+
updateOn: 'change'
1599+
};
14661600

14671601
constructor(fb: FormBuilder) {
1468-
this.reactiveForm = fb.group({
1469-
datePickerReactive: [new Date(2000, 10, 15)],
1602+
this.reactiveFormOnChange = fb.group({
1603+
datePickerReactiveOnChange: [new Date(2000, 10, 15), this.validatorOptions],
1604+
});
1605+
1606+
this.validatorOptions.updateOn = 'blur';
1607+
this.reactiveFormOnBlur = fb.group({
1608+
datePickerReactiveOnBlur: [new Date(2000, 10, 15), this.validatorOptions],
14701609
});
14711610
}
14721611
onSubmitReactive() { }

projects/igniteui-angular/src/lib/date-picker/date-picker.component.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,8 @@ export class IgxDatePickerComponent implements IDatePicker, ControlValueAccessor
932932
if (this._ngControl) {
933933
this._statusChanges$ = this._ngControl.statusChanges.subscribe(this.onStatusChanged.bind(this));
934934
}
935+
936+
this.manageRequiredAsterisk();
935937
}
936938

937939
protected onStatusChanged() {
@@ -1137,7 +1139,6 @@ export class IgxDatePickerComponent implements IDatePicker, ControlValueAccessor
11371139
if (this.collapsed) {
11381140
const input = this.readonlyInputDirective || this.editableInputDirective || this.input;
11391141
if (this._ngControl && !this._ngControl.valid) {
1140-
console.log('onBlur + collapsed + invalid');
11411142
input.valid = IgxInputState.INVALID;
11421143
} else {
11431144
input.valid = IgxInputState.INITIAL;
@@ -1315,7 +1316,6 @@ export class IgxDatePickerComponent implements IDatePicker, ControlValueAccessor
13151316
}
13161317

13171318
private _onOpened(): void {
1318-
this._onTouchedCallback();
13191319
this.onOpened.emit(this);
13201320

13211321
// TODO: remove this line after deprecating 'onOpen'

0 commit comments

Comments
 (0)