samedi 29 août 2020

Angular mat-datepicker's input not working in unit tests

I'm building a custom Angular component which contains a mat-datepicker. Basically component should let user to choose a date and it then emits an event. I have the following implementation which seems to work fine when testing manually:

TS:

@Component({
  selector: 'kms-date-range-picker',
  templateUrl: './date-range-picker.component.html',
  styleUrls: ['./date-range-picker.component.scss'],
})
export class DateRangePickerComponent implements OnInit {
  @Input() startDate: moment.Moment;
  @Input() endDate: moment.Moment;
  @Output() onDateChange = new EventEmitter<{ startDate: moment.Moment; endDate: moment.Moment }>();
  startDateFormControl: FormControl;
  endDateFormControl: FormControl;

  constructor() {}

  ngOnInit(): void {
    this.startDateFormControl = new FormControl(this.startDate);
    this.endDateFormControl = new FormControl(this.endDate);
  }

  onStartDateChange(event: any): void {
    this.startDate = event.value !== null ? moment(event.value) : undefined;
    this.emitDates();
  }

  onEndDateChange(event: any): void {
    this.endDate = event.value !== null ? moment(event.value) : undefined;
    this.emitDates();
  }

  private emitDates(): void {
    this.onDateChange.emit({
      startDate: this.startDateFormControl.value,
      endDate: this.endDateFormControl.value
    })
  }
}

Template:

<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="5px">
  <mat-form-field>
    <mat-label i18n="@@start_date">Start</mat-label>
    <input
      matInput
      data-testId="start-date-input"
      [matDatepicker]="startDatePicker"
      [formControl]="startDateFormControl"
      (dateChange)="onStartDateChange($event)"
    />
    <mat-datepicker-toggle matSuffix [for]="startDatePicker"></mat-datepicker-toggle>
    <mat-datepicker #startDatePicker></mat-datepicker>
  </mat-form-field>
  <mat-form-field>
    <mat-label i18n="@@end_date">End</mat-label>
    <input
      matInput
      data-testId="end-date-input"
      [matDatepicker]="endDatePicker"
      [formControl]="endDateFormControl"
      (dateChange)="onEndDateChange($event)"
    />
    <mat-datepicker-toggle matSuffix [for]="endDatePicker"></mat-datepicker-toggle>
    <mat-datepicker #endDatePicker></mat-datepicker>
  </mat-form-field>
</div>

The problem is that if I try to unit test this by writing something to the input field, nothing happens. Same happens if I try to set the starting values in the tests. Instead of updating the input field its value stays empty. Here is my test suite where I'm using MatInputHarness to set the value:

  beforeEach(() => {
    fixture = TestBed.createComponent(DateRangePickerComponent);
    loader = TestbedHarnessEnvironment.loader(fixture);
    component = fixture.componentInstance;

    // Set @Input values here to avoid the parent component template
    component.startDate = moment('2020-05-01');
    component.endDate = moment('2020-10-12');

    spyOn(component.onDateChange, 'emit');

    fixture.detectChanges();
  });

  it('should initialize fields with given start and end dates', async () => {
    expect(component).toBeTruthy();
    const startDateInput = await getInputHarness('start-date-input');
    const endDateInput = await getInputHarness('end-date-input');

    // await startDateInput.setValue('1234');

    expect(await startDateInput.getValue()).toBe('1.5.2020');
    expect(await endDateInput.getValue()).toBe('12.10.2020');
  });

  it('should emit date range when a date is changed to valid range', async () => {
    expect(component).toBeTruthy();
    const startDateInput = await getInputHarness('start-date-input');
    // const endDateInput = await getInputHarness('end-date-input');

    await startDateInput.setValue('4.6.2020');
    expect(component.onDateChange.emit).toHaveBeenCalledTimes(1);
  });

  async function getInputHarness(testId: string): Promise<MatInputHarness> {
    return await loader.getHarness(MatInputHarness.with({ selector: `[data-testId="${testId}"]` }));
  }

Both of these tests fail in this way:

Chrome 85.0.4183 (Linux 0.0.0) DateRangePickerComponent should initialize fields with given start and end dates FAILED
        Error: Expected '' to be '1.5.2020'.
            at <Jasmine>
            at http://localhost:9876/_karma_webpack_/main.js:35635:49
            at <Jasmine>
            at fulfilled (http://localhost:9876/_karma_webpack_/vendor.js:351548:58)
        Error: Expected '' to be '12.10.2020'.
            at <Jasmine>
            at http://localhost:9876/_karma_webpack_/main.js:35636:47
            at <Jasmine>

What gives? If I remove the [matDatepicker]="startDatePicker" from inputs, the text input via test works and input fields are updated. However, if I add them back, input fails. How should I test these fields in Angular unit tests?

Aucun commentaire:

Enregistrer un commentaire