Reputation: 2949
I have a multiple Select list that I want to test, basically when you select n items you then click a button that will copy the items from one list an another. I am having problems trying to select more than one value. This is a multi select so I want to be able to select n items.
I can select one item with this line, but how do I select multiple items in the test?
select.value = select.options[0].value;
here is the test selector.component.spec.ts
it('When assign button is clicked expect to be displayed in assigned list', () => {
let unassignedItems = [
{ id:1, name: 'Rob' },
{ id:2, name: 'Dave' },
{ id:3, name: 'Steve' }
] as Person[];
component.unassignedItems = unassignedItems;
fixture.detectChanges();
let select: HTMLSelectElement = unassignedItemsSelect.nativeElement;
select.value = select.options[0].value;
select.dispatchEvent(new Event('change'));
fixture.detectChanges();
assignedItemButton.triggerEventHandler('click', null);
expect(component.assignedItems[0].id).toBe(1)
})
The component looks like this selector.component.ts
import { Component, Input, OnInit} from '@angular/core';
import { Person } from '../Person';
@Component({
selector: 'app-selector',
templateUrl: './selector.component.html',
styleUrls: ['./selector.component.scss']
})
export class SelectorComponent implements OnInit {
constructor() { }
unassignedSelectedItems: Person[] = [];
assignedSelectedItems: Person[] = [];
@Input() unassignedItems : Person[] = [];
@Input() assignedItems: Person[] = [];
ngOnInit(): void {
}
assignSelections(): void {
this.assignedItems.push(...this.unassignedSelectedItems);
// remove the item from the unassigned list
this.unassignedSelectedItems.forEach(selectedItem => {
let index = this.unassignedItems.findIndex(x => x.id == selectedItem.id);
this.unassignedItems.splice(index, 1); // removes the item at that index
});
// clear the selected item for the next ones
this.unassignedSelectedItems = [];
}
unassignSelections(): void {
this.unassignedItems.push(...this.assignedSelectedItems);
// remove the item from the assigned list
this.assignedSelectedItems.forEach(selectedItem => {
let index = this.assignedItems.findIndex(x => x.id == selectedItem.id);
this.assignedItems.splice(index, 1); // removes the item at that index
});
// clear the selected item for the next ones
this.assignedSelectedItems = [];
}
}
The template looks like this selector.component.html
<div class="container">
<div class="row">
<div class="col-3">
<select id="unassignedItems" class="form-select" multiple [(ngModel)]="unassignedSelectedItems">
<option *ngFor="let item of unassignedItems" [ngValue]="item">{{item.name}}</option>
</select>
</div>
<div class="col-1 align-middle" >
<button id="assignedItemButton" [disabled]="unassignedItems.length==0" class="btn btn-primary m-1" type="button" (click)="assignSelections()">></button>
<button id="unassignedItemButton" [disabled]="assignedItems.length==0" class="btn btn-primary m-1" type="button" (click)="unassignSelections()"><</button>
</div>
<div class="col-3">
<select id="assignedItems" class="form-select" multiple [(ngModel)]="assignedSelectedItems">
<option *ngFor="let item of assignedItems" [ngValue]="item">{{item.name}}</option>
</select>
</div>
</div>
</div>
Upvotes: 0
Views: 938
Reputation: 17103
Tricky one, testing a native multi select. The problem is, that <select>
doesn't reflect all selected values in it's value
, only one of them. So setting it to multiple values won't have any effect. Given the awkward way to extract multiple selected values from a select, and the fact that testing native behavior and ngModel
probably isn't (and shouldn't be) your goal, I'd settle for setting the unassignedItems
and assignedItems
manually.
But if you really want to simulate this in your test the "native" way, set the options you want to select like
options[0].selected = true;
and then emit the change
event. This will update <select>
's selectedOptions
property, which is used internally by angular's SelectMultipleControlValueAccessor
. Check its code if you find it interesting. That code will execute upon change
event, grab the selectedOptions
' values, and propagate them into the variable associated with [(ngModel)]
.
Upvotes: 1