angulartestingjasmine

Jasmine not detecting changes on input, maybe bad testing bad strategy


I am trying to unit test (Karma/Jasmine Angular 9.15) the disable property of a select going from true to false when an input is filled (not null or empty). Jasmine do not seem to detect de changes becauses I don't pass through the function that processes the boolean 'disabled' when I simulate the value change on the input.

So I am wondering why it doesn't detect the change and since I didn't found a working solution I am questionning my testing strategy about this : Am I doign it right ?

Here is the code :

filter.spec.ts

  fdescribe('FilterComponent', () => {
    let component: FilterComponent;
    let fixture: ComponentFixture<FilterComponent>;

    beforeEach(async(() => {
      TestBed.configureTestingModule({
        declarations: [ FilterComponent ]
      })
      .compileComponents();
    }));

    beforeEach(() => {
      fixture = TestBed.createComponent(FilterComponent);
      component = fixture.componentInstance;
      fixture.detectChanges();
    });



   it('should able the select when input is filled', () => {
    let inputFilter = fixture.debugElement.nativeElement.querySelector('#my-filter');
    inputFilter.value = "testing";
    inputFilter.dispatchEvent(new Event('input'));
    fixture.detectChanges();
    fixture.whenStable().then(fix=>{
      expect(fixture.debugElement.nativeElement.querySelector('#my- 
      select').disabled).toBeFalse();
    });
  });

filter.component.html

    <!-- Filter -->
    <div class="flex-container-h flex-align-center flex-nowrap mlm">
        <label class="mt-label txtc-15 mrs" for="my-filter">Contract number</label>
        <div class="flex-item-fluid">
            <input [(ngModel)]="contractFilter" id="my-filter" type="text"
                class="form-control">
        </div>
    </div>

    <!-- Filtre select-->
    <div class="flex-container-h flex-align-center flex-nowrap mlm">
        <label class="mt-label txtc-15 mrs" for="my-select">Statut</label>
        <div class="flex-item-fluid">
            <select id="my-select" name="statuts" [disabled]="isSelectDisabled()">
                <option value="" selected disabled hidden>Select an option</option>
                <option *ngFor="let status of statusesList" [value]="status.code">{{status.libelle}}</option>
            </select>
        </div>
    </div>

filter.component.ts

   public isSelectDisabled(): boolean {
    return (!this.contractFilter || this.contractFilter === "");
  }

Thanks for reading me


Solution

  • Doing it from the HTML like so might be tricky because there might be asynchronous tasks with updating values and you might need another fixture.whenStable(). What I would do is directly change contractFilter because the Angular team has already tested ngModel.

    import { By } from '@angular/platform-browser';
    .....
    it('should able the select when input is filled', () => {
        component.contractFilter = 'testing';
        fixture.detectChanges();
        // I like to query the DOM like so
        const disableSelect = fixture.debugElement.query(By.css('#my-select[disabled]'));
        const enableSelect = fixture.debugElement.query(By.css('#my-select'));
        expect(disableSelect).toBeFalsy();
        expect(enableSelect).toBeTruthy();
     });
    

    We query the DOM for #my-select with disabled attribute and expect it to be falsy and we query the DOM for #my-select without disabled attribute and expect it to be truthy.