我想在Angular 2单元测试中更改输入字段的值。
<input type="text" class="form-control" [(ngModel)]="abc.value" />
我不能只更改ngModel
,因为abc
对象是私有的:
private abc: Abc = new Abc();
在Angular 2测试中,我是否可以模拟用户在输入字段中输入内容,以便使用用户在单元测试中输入的内容更新ngModel
?
我可以毫无问题地抓住输入字段的DebugElement
和nativeElement
。 (仅在输入字段的value
上设置nativeElement
属性似乎不起作用,因为它没有使用我为该值设置的内容更新ngModel
也许可以调用inputDebugEl.triggerEventHandler
,但是我不确定给它的参数是什么,所以它会模拟输入特定输入字符串的用户。
答案 0 :(得分:43)
你是对的,你不能只设置输入,你还需要发送'input'
事件。这是我今天早些时候写的一个函数来输入文本:
function sendInput(text: string) {
inputElement.value = text;
inputElement.dispatchEvent(new Event('input'));
fixture.detectChanges();
return fixture.whenStable();
}
此处fixture
是ComponentFixture
,inputElement
是来自灯具HTTPInputElement
的相关nativeElement
。这会返回一个承诺,因此您可能需要解决它sendInput('whatever').then(...)
。
<强>更新强>:
我们在Angular 2.1中遇到了一些问题,它并不像创建new Event(...)
那样,所以我们做了:
import { dispatchEvent } from '@angular/platform-browser/testing/browser-util';
...
function sendInput(text: string) {
inputElement.value = text;
dispatchEvent(fixture.nativeElement, 'input');
fixture.detectChanges();
return fixture.whenStable();
}
答案 1 :(得分:12)
在Angular 2.4中,我接受的解决方案并不适用于我。即使在调用了detectChanges()之后,我设置的值也没有出现在(测试)UI中。
我开始工作的方式是按如下方式设置我的测试:
describe('TemplateComponent', function () {
let comp: TemplateComponent;
let fixture: ComponentFixture<TemplateComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ FormsModule ],
declarations: [ TemplateComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TemplateComponent);
comp = fixture.componentInstance;
});
it('should allow us to set a bound input field', fakeAsync(() => {
setInputValue('#test2', 'Tommy');
expect(comp.personName).toEqual('Tommy');
}));
// must be called from within fakeAsync due to use of tick()
function setInputValue(selector: string, value: string) {
fixture.detectChanges();
tick();
let input = fixture.debugElement.query(By.css(selector)).nativeElement;
input.value = value;
input.dispatchEvent(new Event('input'));
tick();
}
});
我的TemplateComponent
组件在此示例中有一个名为personName
的属性,它是我在模板中绑定的模型属性:
<input id="test2" type="text" [(ngModel)]="personName" />
答案 2 :(得分:3)
我也很难让jonrsharpe回答使用Angular 2.4。我发现对fixture.detectChanges()
和fixture.whenStable()
的调用导致表单组件重置。在测试开始时,似乎某些初始化函数仍处于未决状态。我通过在每次测试之前添加额外的调用来解决这个问题。以下是我的代码片段:
beforeEach(() => {
TestBed.configureTestingModule({
// ...etc...
});
fixture = TestBed.createComponent(LoginComponent);
comp = fixture.componentInstance;
usernameBox = fixture.debugElement.query(By.css('input[name="username"]'));
passwordBox = fixture.debugElement.query(By.css('input[type="password"]'));
loginButton = fixture.debugElement.query(By.css('.btn-primary'));
formElement = fixture.debugElement.query(By.css('form'));
});
beforeEach(async(() => {
// The magic sauce!!
// Because this is in an async wrapper it will automatically wait
// for the call to whenStable() to complete
fixture.detectChanges();
fixture.whenStable();
}));
function sendInput(inputElement: any, text: string) {
inputElement.value = text;
inputElement.dispatchEvent(new Event('input'));
fixture.detectChanges();
return fixture.whenStable();
}
it('should log in correctly', async(() => {
sendInput(usernameBox.nativeElement, 'User1')
.then(() => {
return sendInput(passwordBox.nativeElement, 'Password1')
}).then(() => {
formElement.triggerEventHandler('submit', null);
fixture.detectChanges();
let spinner = fixture.debugElement.query(By.css('img'));
expect(Helper.isHidden(spinner)).toBeFalsy('Spinner should be visible');
// ...etc...
});
}));