Angular 6 - Unit Testing Mat-Select

18,428

Solution 1

This one is worked for me in Angular 7

    const debugElement = fixture.debugElement;
    // open options dialog
    const matSelect = debugElement.query(By.css('.mat-select-trigger')).nativeElement;
    matSelect.click();
    fixture.detectChanges();
    // select the first option (use queryAll if you want to chose an option)
    const matOption = debugElement.query(By.css('.mat-option')).nativeElement;
    matOption.click();
    fixture.detectChanges();
    fixture.whenStable().then( () => {
       const inputElement: HTMLElement = debugElement.query(By.css('.ask-input')).nativeElement;
       expect(inputElement.innerHTML.length).toBeGreaterThan(0);
    });

Solution 2

After some testing I found an answer (at least for my code) and hope, that this is helpful to you as well:

When I looked at the DOM, when the application is running, I noticed that the default value of the mat-select is inside this DOM structure:

<mat-select>
    <div class="mat-select-trigger">
        <div class="mat-select-value">
            <span class="something">
                <span class="something">
                The value is here!

But in my case, I had a form builder in my .ts file and it was used in ngOnInit(). It seems that the normal TestBed.createComponent(MyComponent) does not call ngOnInit(). So I had to do that in order to get the value. Otherwise there was just a placeholder span.

So, my final code looks like this:

it('should validate the drop down value if it is set by default', async () => {

    const matSelectValueObject: HTMLElement = fixture.debugElement.query(By.css('.mat-select-value')).nativeElement;
    component.ngOnInit();
    fixture.detectChanges();

    const innerSpan =
          matSelectValueObject.children[0].children[0];  // for getting the inner span

    expect(innerSpan.innerHTML).toEqual(3);              // or '3', I did not test that
});

By the way I'm using Angular 7, in case this matters.

Solution 3

Helper method for your page object to set the option by text:

public setMatSelectValue(element: HTMLElement, value: string): Promise<void> {
  // click on <mat-select>
  element.click();
  this.fixture.detectChanges();

  // options will be rendered inside OverlayContainer
  const overlay = TestBed.get(OverlayContainer).getContainerElement();

  // find an option by text value and click it
  const matOption = Array.from(overlay.querySelectorAll<HTMLElement>('.mat-option span.mat-option-text'))
    .find(opt => opt.textContent.includes(value));
  matOption.click();

  this.fixture.detectChanges();
  return this.fixture.whenStable();
}

Solution 4

let loader = TestbedHarnessEnvironment.loader(fixture);

const matSelect = await loader.getAllHarnesses(MatSelectHarness);
await matSelect[0].clickOptions();
const options = await matSelect[0].getOptions();
expect(await options[0].getText()).toMatch("");
expect(await options[1].getText()).toMatch('option1');
expect(await options[2].getText()).toMatch('option2');
Share:
18,428
Admin
Author by

Admin

Updated on June 10, 2022

Comments

  • Admin
    Admin about 2 years

    1: The mat-select has 4 values, 1,2,3,4.

    The code below works good for the select. So I'd like to share if it helps the readers.

    it('check the length of drop down', async () => {
    
        const trigger = fixture.debugElement.query(By.css('.mat-select-trigger')).nativeElement;
        trigger.click();
        fixture.detectChanges();
        await fixture.whenStable().then(() => {
            const inquiryOptions = fixture.debugElement.queryAll(By.css('.mat-option-text'));
            expect(inquiryOptions.length).toEqual(4);
        });
    });
    

    2: I need another test to verify the default value in the same mat-select is 3 or not. When page loads the default value for the drop down is set to 3.

    it('should validate the drop down value if it is set by default', async () => {
    
        const trigger = fixture.debugElement.query(By.css('.mat-select-trigger')).nativeElement;
        trigger.click();
        fixture.detectChanges();
        await fixture.whenStable().then(() => {
            const inquiryOptions = fixture.debugElement.queryAll(By.css('.mat-option-text'));
            const value = trigger.options[0].value;
            expect(value).toContain(3);
        });
    });
    

    Any help is appreciated.

  • Zozo
    Zozo about 5 years
    You have a typo: detechChanges -> detectChanges
  • Sunil Garg
    Sunil Garg almost 4 years
    how can i test the same in e2e?
  • Stephen
    Stephen over 2 years
    const options didn't get populated until I added await matSelect[0].open();.
  • AlignedDev
    AlignedDev over 2 years
    I didn't know about the Component Harnesses before this. Thanks! There's more information at github.com/angular/components/blob/master/guides/… and they encourage using this.