如何在 angular2 单元测试中更改选择框的值?
i具有一个Angular2组件,其中包含一个看起来像
887511471
的选择框,我正在尝试为NGModelChange事件编写一个单元测试。 这是我最新的失败尝试
583756382
我遇到麻烦的部分是更改基础模型
comp.envfilter ='env3';
不会触发更改方法。 我添加了
el.triggereventhandler('change',{});
,但是这引发了
失败:未摄取(在Promise):referenceError:未定义
。 我找不到文档中的任何提示...有什么想法吗?
至于错误。似乎您只需要导入
By
。这不是全局的东西。它应该从以下模块导入
import { By } from '@angular/platform-browser';
至于测试部分,这是我能够弄清楚的。当您更改组件中的值时,您需要触发更改检测以更新视图。您可以使用
fixture.detectChanges()
执行此操作。完成此操作后,
通常
视图应该使用该值进行更新。
从测试与您的示例类似的内容来看,情况似乎并非如此。似乎在更改检测后仍有一些异步任务在进行。假设我们有以下内容
const comp = fixture.componentInstance;
const select = fixture.debugElement.query(By.css('select'));
comp.selectedValue = 'a value';
fixture.DetectChanges();
expect(select.nativeElement.value).toEqual('1: a value');
这似乎不起作用。似乎有一些异步操作导致尚未设置值。因此,我们需要通过调用
fixture.whenStable
来等待异步任务。
comp.selectedValue = 'a value';
fixture.DetectChanges();
fixture.whenStable().then(() => {
expect(select.nativeElement.value).toEqual('1: a value');
});
上述方法可行。但现在我们需要触发更改事件,因为这不会自动发生。
fixture.whenStable().then(() => {
expect(select.nativeElement.value).toEqual('1: a value');
dispatchEvent(select.nativeElement, 'change');
fixture.detectChanges();
fixture.whenStable().then(() => {
// component expectations here
});
});
现在我们有了来自该事件的另一个异步任务。因此,我们需要再次稳定它。
下面是我测试过的完整测试。它是
源代码集成测试
中示例的重构。他们使用了
fakeAsync
和
tick
,这类似于使用
async
和
whenStable
。但是使用
fakeAsync
,您无法使用
templateUrl
,因此我认为最好将其重构为使用
async
。
此外,源代码测试进行了一种双重单向测试,首先测试模型到视图,然后测试视图到模型。而您的测试似乎试图进行一种双向测试,从模型回到模型。所以我对其进行了一些重构,以更好地适合您的示例。
import { Component } from '@angular/core';
import { TestBed, getTestBed, async } from '@angular/core/testing';
import { FormsModule } from '@angular/forms';
import { By } from '@angular/platform-browser';
import { dispatchEvent } from '@angular/platform-browser/testing/browser_util';
@Component({
selector: 'ng-model-select-form',
template: `
<select [(ngModel)]="selectedCity" (ngModelChange)="onSelected($event)">
<option *ngFor="let c of cities" [ngValue]="c"> {{c.name}} </option>
</select>
`
})
class NgModelSelectForm {
selectedCity: {[k: string]: string} = {};
cities: any[] = [];
onSelected(value) {
}
}
describe('component: NgModelSelectForm', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ FormsModule ],
declarations: [ NgModelSelectForm ]
});
});
it('should go from model to change event', async(() => {
const fixture = TestBed.createComponent(NgModelSelectForm);
const comp = fixture.componentInstance;
spyOn(comp, 'onSelected');
comp.cities = [{'name': 'SF'}, {'name': 'NYC'}, {'name': 'Buffalo'}];
comp.selectedCity = comp.cities[1];
fixture.detectChanges();
const select = fixture.debugElement.query(By.css('select'));
fixture.whenStable().then(() => {
dispatchEvent(select.nativeElement, 'change');
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(comp.onSelected).toHaveBeenCalledWith({name : 'NYC'});
console.log('after expect NYC');
});
});
}));
});
我发现 peeskillet 的答案非常有用,但遗憾的是它有点过时了,因为调度事件的方式已经改变。我还发现对 whenStable() 进行了不必要的调用。因此,这里是使用 peeskillet 设置的更新测试:
it('should go from model to change event', async(() => {
const fixture = TestBed.createComponent(NgModelSelectForm);
const comp = fixture.componentInstance;
spyOn(comp, 'onSelected');
comp.cities = [{'name': 'SF'}, {'name': 'NYC'}, {'name': 'Buffalo'}];
comp.selectedCity = comp.cities[1];
fixture.detectChanges();
const select = fixture.debugElement.query(By.css('select'));
fixture.whenStable().then(() => {
select.nativeElement.dispatchEvent(new Event('change'));
fixture.detectChanges();
expect(comp.onSelected).toHaveBeenCalledWith({name : 'NYC'});
console.log('after expect NYC');
});
}));
查看此示例,来自角度源(template_integration_spec.ts)
@Component({
selector: 'ng-model-select-form',
template: `
<select [(ngModel)]="selectedCity">
<option *ngFor="let c of cities" [ngValue]="c"> {{c.name}} </option>
</select>
`
})
class NgModelSelectForm {
selectedCity: {[k: string]: string} = {};
cities: any[] = [];
}
it('with option values that are objects', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelSelectForm);
const comp = fixture.componentInstance;
comp.cities = [{'name': 'SF'}, {'name': 'NYC'}, {'name': 'Buffalo'}];
comp.selectedCity = comp.cities[1];
fixture.detectChanges();
tick();
const select = fixture.debugElement.query(By.css('select'));
const nycOption = fixture.debugElement.queryAll(By.css('option'))[1];
// model -> view
expect(select.nativeElement.value).toEqual('1: Object');
expect(nycOption.nativeElement.selected).toBe(true);
select.nativeElement.value = '2: Object';
dispatchEvent(select.nativeElement, 'change');
fixture.detectChanges();
tick();
// view -> model
expect(comp.selectedCity['name']).toEqual('Buffalo');
}));