I am new to Angular, I am trying to build a text field with autocomplete using Angular 5.
I found this example in Angular Material docs:
https://stackblitz.com/angular/kopqvokeddbq?file=app%2Fautocomplete-overview-example.ts
I was wondering how to write a unit test for testing the autocomplete functionality. I am setting a value to the input element and triggering an 'input' event and tried selecting the mat-option elements, but see that none of them got created:
Relevant part of my component html:
<form>
<mat-form-field class="input-with-icon">
<div>
<i ngClass="jf jf-search jf-lg md-primary icon"></i>
<input #nameInput matInput class="input-field-with-icon" placeholder="Type name here"
type="search" [matAutocomplete]="auto" [formControl]="userFormControl" [value]="inputField">
</div>
</mat-form-field>
</form>
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let option of filteredOptions | async" [value]="option.name"
(onSelectionChange)="onNameSelect(option)">
{{ option.name }}
</mat-option>
</mat-autocomplete>
Spec file:
it('should filter users based on input', fakeAsync(() => {
const hostElement = fixture.nativeElement;
sendInput('john').then(() => {
fixture.detectChanges();
expect(fixture.nativeElement.querySelectorAll('mat-option').length).toBe(1);
expect(hostElement.textContent).toContain('John Rambo');
});
}));
function sendInput(text: string) {
let inputElement: HTMLInputElement;
inputElement = fixture.nativeElement.querySelector('input');
inputElement.focus();
inputElement.value = text;
inputElement.dispatchEvent(new Event('input'));
fixture.detectChanges();
return fixture.whenStable();
}
Component html:
userFormControl: FormControl = new FormControl();
ngOnInit() {
this.filteredOptions = this.userFormControl.valueChanges
.pipe(
startWith(''),
map(val => this.filter(val))
);
}
filter(val: string): User[] {
if (val.length >= 3) {
console.log(' in filter');
return this.users.filter(user =>
user.name.toLowerCase().includes(val.toLowerCase()));
}
}
Before this, I realised that for making the FormControl object set the value, I have to do a inputElement.focus() first, this is something to do with using mat input of angular material. Is there something I have to do to trigger opening the mat-options pane?
How do I make this test work?
@Adam's comment to previous answer led me to the mat-autocomplete component's own test, specially here. Where you can see that focusin
is the event that opens the "options".
But they actually open in an overlay outside your component, so in my test fixture.nativeElement.querySelectorAll('mat-option').length
was 0
but if i query over the element document.querySelectorAll('mat-option')
I got the expected number of options.
To sumarize:
fixture.detectChanges();
const inputElement = fixture.debugElement.query(By.css('input')); // Returns DebugElement
inputElement.nativeElement.dispatchEvent(new Event('focusin'));
inputElement.nativeElement.value = text;
inputElement.nativeElement.dispatchEvent(new Event('input'));
fixture.detectChanges();
await fixture.whenStable();
fixture.detectChanges();
const matOptions = document.querySelectorAll('mat-option');
expect(matOptions.length).toBe(3,
'Expect to have less options after input text and filter');
Extra ball: And if you want to click on an option (I did) you can continue like that:
const optionToClick = matOptions[0] as HTMLElement;
optionToClick.click();
fixture.detectChanges();
Although I didn't success on clicking and getting the value into the input. 🤨 Well, I'm not an expert tester, but probably that behaviour should be cover in the own mat-autocomplete
's tests (and actually it is) and rely on it?
You need to add more events. I had more or less the same problem as you and it only worked when I triggered the focusin event.
I am using these events in my code. Not sure if all are needed.
inputElement.dispatchEvent(new Event('focus'));
inputElement.dispatchEvent(new Event('focusin'));
inputElement.dispatchEvent(new Event('input'));
inputElement.dispatchEvent(new Event('keydown'));
You need to add this to your sendInput function...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With