unit test fails when the component is marked as ChangeDetectionStrategy.OnPush

Viewed 456

I have the angular component l

@Component({
  selector: 'aas-add-option',
  templateUrl: './add-option-modal.component.html',
  styleUrls: ['./add-option-modal.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})

having form group

this.formBuilder.group({
      newOptionInput: new FormControl('', [
        Validators.required,
        Validators.maxLength(150),
        Validators.pattern(this.htmlPattern),
      ]),
      newOptionHint: new FormControl(''),
    });

============================== .html file

<vt-modal-footer>
    <button
      vtButton
      ot-auto-id="AAResultsAddModalCancelButton"
      [disabled]="isLoading"
      (click)="closeModal()"
    >
      {{ 'Cancel' | translate }}
    </button>
    <button
      vtButton
      color="neutral"
      class="slds-m-right_medium"
      ot-auto-id="AAResultsAddModalSaveAndAddAnotherButton"
      [disabled]="
        !optionsForm?.get('newOptionInput').value?.trim() ||
        !optionsForm?.get('newOptionInput').valid   <--HERE BUTTON DISABLED CHECK
      "
      (click)="onSaveAndAddAnother()"
    >
      {{ 'SaveAndAddAnother' | translate }}
    </button>
    <button
      vtButton
      color="primary"
      *ngIf="!isLoading"
      ot-auto-id="AAResultsAddModalSaveButton"
      [disabled]="
        !optionsForm?.get('newOptionInput').value?.trim() ||   <--HERE BUTTON DISABLED CHECK
        !optionsForm?.get('newOptionInput').valid
      "
      (click)="addOption(true)"
    >
      {{ 'Save' | translate }}
    </button>
  </vt-modal-footer>

spec.ts

fit('should saveNewOptionButton and saveAndAddAnotherButton should get enabled, when the value is set in input', () => { 
    const saveNewOptionButtonElement = fixture.debugElement.query(
      By.css('button[ot-auto-id="AAResultsAddModalSaveButton"]')
    );
    const saveAndAddAnotherButtonElement = fixture.debugElement.query(
      By.css('button[ot-auto-id="AAResultsAddModalSaveAndAddAnotherButton"]')
    );

    //fixture.nativeElement.querySelector('[ot-auto-id="AAResultsNewOptionInput"]').value = 'ravi'; // basically I want to test, by setting like this.
     
    component.optionsForm.controls.newOptionInput.setValue('ravi'); //trying this too
    fixture.detectChanges();
    expect(component.optionsForm.valid).toBeTruthy(); <- got failed 
    expect(saveNewOptionButtonElement.nativeElement.disabled).toBe(false); <- got failed 
    // expect(saveAndAddAnotherButtonElement.nativeElement.disabled).toBe(false); <- got failed 
  });

Now I need to unit test the Formcontrol by setting the value to the input DOM and expect the button to be enabled since the value is set in the specs,

But if I remove the changeDetection: ChangeDetectionStrategy.OnPush from the @Component, things are working fine, but I want the Change Detection Strategy to be on the component.

So the question is why my spec fails when the @Component has changeDetection: ChangeDetectionStrategy.OnPush and what I should make the change to make it work in my Spec

1 Answers

When working with OnPush components in tests you should be aware that fixture.detectChanges() doesn't trigger change detection on undeflying component's view but rather on host view.

In order to remedy this behavior you can get hold of actual component's changeDetector like this:

// fixture.changeDetectorRef.markForCheck();
const cdRef = fixture.componentRef.injector.get(ChangeDetectorRef);
cdRef.detectChanges();
Related