问题描述
我正在尝试使用Angular 9中的模板驱动的表单来测试一个简单的表单.我将值插入输入中,然后单击提交"按钮,该按钮将值发送到服务.该代码有效,但是测试失败,因为这些值始终保持未定义状态.
I'm trying to test a simple form using template-driven forms in Angular 9. I insert values into the inputs and click on a submit button, which sends the values to a service. The code works, but the test fails because the values always remain undefined.
我已经创建了该问题的演示以在此处显示(我的实际代码太复杂了):
I've created a demo of the problem to show here (my actual code would be too complex):
app.component.ts
@Component({
selector: 'app-root',
template: `
<form #f="ngForm" (ngSubmit)="submit(f)">
<input type="text" ngModel name="field1">
<input type="text" [(ngModel)]="field2" name="field2">
<input type="submit" value="submit">
<br>field1: {{ f.value.field1 }}
<br>submitedText: {{ submitedText }}
<br>field2: {{ field2 }}
</form>
`
})
export class AppComponent {
public submitedText: string;
public field2: string;
public submit(form: NgForm) {
this.submitedText = form.value.field1;
}
}
app.component.spec.ts
describe('AppComponent', () => {
it('shoud to submit the text', () => {
const fixture = TestBed.configureTestingModule({
declarations: [ AppComponent ],
imports: [ FormsModule ],
}).createComponent(AppComponent)
fixture.detectChanges();
const field1 = fixture.elementRef.nativeElement.querySelector('input[name="field1"]');
const field2 = fixture.elementRef.nativeElement.querySelector('input[name="field2"]');
const button = fixture.elementRef.nativeElement.querySelector('input[type="submit"]');
field1.value = 'test 1';
field2.value = 'test 2';
field1.dispatchEvent(newEvent('input'));
field2.dispatchEvent(newEvent('input'));
fixture.detectChanges();
button.click();
fixture.detectChanges();
expect(fixture.componentInstance.submitedText).toBe('test 1');
expect(fixture.componentInstance.field2).toBe('test 2');
});
});
export function newEvent(eventName: string, bubbles = false, cancelable = false) {
const evt = document.createEvent('CustomEvent'); // MUST be 'CustomEvent'
evt.initCustomEvent(eventName, bubbles, cancelable, null);
return evt;
}
结果是:
Failures
AppComponent > shoud to submit the text
Expected undefined to be 'test 1'.
Expected undefined to be 'test 2'.
有人可以帮助我使测试正确填写输入吗?谢谢!
Could someone help me to make the inputs are correctly filled out by the test? Thanks!
推荐答案
我找到了解决方案,尽管我不知道确切的原因,因为文档没有对此进行解释.
I found the solution, although I don't understand exactly why, since the documentation doesn't explain it.
有多种方法可以更正测试.
There are different ways to correct the test.
在我创建的示例中,有必要将测试代码包含在fakeAsync中,并分别调用Fixture.detectChanges()和tick()函数:
In the example I created, it is necessary to include the test code inside a fakeAsync, and call the fixture.detectChanges() and tick() functions, respectively:
describe('AppComponent', () => {
it('shoud to submit the text', fakeAsync(() => {
const fixture = TestBed.configureTestingModule({
declarations: [ AppComponent ],
imports: [ FormsModule ],
}).createComponent(AppComponent)
fixture.detectChanges();
tick();
// rest of the code ...
}));
我需要提到的是,我的原始代码在beforeEach(没有异步)中创建了组件,这有所作为.如果在没有异步的beforeEach内创建组件,则必须在其中使用fakeAsync,并且不能在beforeEach内调用Fixture.detectChanges()(那是破坏我原始代码的原因).但是,如果您的beforeEach具有异步,则不需要使用fakeAsync,并且在测试(it)中使用async或fakeAsync是可选的.
I need to mention that my original code creates the component inside a beforeEach (without async), and that makes a difference. If you create the component inside a beforeEach without async, you must use fakeAsync in it, and you CANNOT call fixture.detectChanges() inside this beforeEach (that was what broke my original code). However, if your beforeEach has async, the use of fakeAsync is unnecessary, and using async or fakeAsync in your test (it) is optional.
beforeEach(async(() => {
const fixture = TestBed.configureTestingModule({
declarations: [ AppComponent ],
imports: [ FormsModule ],
}).createComponent(AppComponent)
fixture.detectChanges();
}));
it('shoud to submit the text', () => {
// rest of the code ...
这篇关于为什么用模板驱动的测试返回未定义的值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!