Angular click select option in component test
Asked Answered
S

4

23

I have tried the following to try to click an option in a select dropdown none of which work.

selectEl = fixture.debugElement.query(By.css('#dropdown'));
selectEl.nativeElement.options[3].nativeElement.dispatchEvent(new Event('click'));
selectEl.queryAll(By.css('option'))[3].nativeElement.click();
selectEl.nativeElement.options[3].nativeElement.click();

After each i run fixture.detectChanges(); to run the change detection but when I go to check the elements value it hasn't changed. expect(selectEl.nativeElement.options[selectEl.nativeElement.selectedIndex].textContent).toBe('name2');

Am I missing something simple to get this to work?

Syrup answered 23/2, 2018 at 11:58 Comment(0)
P
56

The way to change the selected option of a dropdown is to set the dropdown value and then dispatch a change event.

You can use this answer as reference: Angular unit test select onChange spy on empty value

In your case, you should do something like this:

  const select: HTMLSelectElement = fixture.debugElement.query(By.css('#dropdown')).nativeElement;
  select.value = select.options[3].value;  // <-- select a new value
  select.dispatchEvent(new Event('change'));
  fixture.detectChanges();
Proffitt answered 23/2, 2018 at 12:19 Comment(0)
S
15

You don't have to dispatch a change event. First you need to click on the trigger for your dropdown, i'm assuming it's your selectEl selectEl = fixture.debugElement.query(By.css('#dropdown')).

selectEl.click();
fixture.detectChanges();

After detectChanges your dropdown should be opened. Only after this will you be able to get your options from fixture, because before they where not present in your fixture.

The only way I have been able to get my options is by doing const selectOptions = fixture.debugElement.queryAll(By.css('.select-option')); where 'select-option'is the class I put on the options. I am using mat-select in my project, so this might be due to that.

You can click the first option by doing selectOptions[0].nativeElement.click();. Afterwards you need to call fixture.detectChanges() again. Now you have selected an option!

I was able to get the value that is now selected by doing selectEl.innerText.trim(). Not sure if this is the best way to do it, but it works. Trim is used to remove the whitespace.

Sungod answered 19/9, 2018 at 9:6 Comment(1)
Excellent! I am using mat-select as well. +1 for expanding on this answer.Quintet
Q
5

I expanded on Emmy's answer a little bit. Here is a working "helper" method for selecting material drop downs.

import { By } from '@angular/platform-browser';

export default class TestUtils {
  static selectDropdown(id: string, fixture: any): void {
    const select = fixture.debugElement.query(By.css(`#${id}`)).nativeElement;
    select.click();
    fixture.detectChanges();
    const selectOptions = fixture.debugElement.queryAll(By.css(`.${id}Option`));
    selectOptions[5].nativeElement.click();
    fixture.detectChanges();
  }
}

This lets your specify the drop down you would like to select (by id) and the index you would like to select. The only caveat for this method is you have to add a class to your mat-option elements in your dropdown. Example:

<mat-option *ngFor="let trim of trims" value="{{trim}}" class="trimDropdownOption">{{trim}}</mat-option>

Just make sure the class for the mat-option contains the ID with the addition of 'Option'.

This solves an issue with Emmy's answer where if you have multiple drop downs on a single form, you can specify which mat-option you click on.

You can make use of the above extension method by referencing it in your test like so:

TestUtils.selectDropdown('yearDropdown', 1, fixture);
expect(fixture.componentInstance.onYearChange).toHaveBeenCalled();
Quintet answered 8/7, 2019 at 17:6 Comment(0)
L
0

The easiest solution that I can provide is below.

let selectElement: HTMLSelectElement = fixture.nativeElement.querySelector('#dropdown');
selectElement.selectedIndex = 3;
selectElement.dispatchEvent(new Event('change'));

Firstly you get the element by ID and then select the Index by number In your case it's 3 and then by dispatching event will trigger the change event.

Lafleur answered 19/5, 2022 at 12:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.