为什么使用模板驱动 return 未定义值进行测试?
Why does testing with template driven return undefined value?
我正在尝试使用 Angular 中的模板驱动表单测试一个简单的表单。我将值插入输入并单击提交按钮,该按钮将值发送到服务。代码有效,但测试失败,因为值始终未定义。
我已经创建了一个问题演示以在此处显示(我的实际代码会太复杂):
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'.
有人可以帮助我让测试正确填写输入吗?谢谢!
我找到了解决方案,虽然我不明白为什么,因为文档没有解释它。
有不同的方法来纠正测试。
在我创建的示例中,需要将测试代码包含在 fakeAsync 中,并分别调用 fixture.detectChanges() 和 tick() 函数:
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,并且在您的测试(它)中使用异步或 fakeAsync 是可选的。
beforeEach(async(() => {
const fixture = TestBed.configureTestingModule({
declarations: [ AppComponent ],
imports: [ FormsModule ],
}).createComponent(AppComponent)
fixture.detectChanges();
}));
it('shoud to submit the text', () => {
// rest of the code ...
我正在尝试使用 Angular 中的模板驱动表单测试一个简单的表单。我将值插入输入并单击提交按钮,该按钮将值发送到服务。代码有效,但测试失败,因为值始终未定义。
我已经创建了一个问题演示以在此处显示(我的实际代码会太复杂):
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'.
有人可以帮助我让测试正确填写输入吗?谢谢!
我找到了解决方案,虽然我不明白为什么,因为文档没有解释它。
有不同的方法来纠正测试。
在我创建的示例中,需要将测试代码包含在 fakeAsync 中,并分别调用 fixture.detectChanges() 和 tick() 函数:
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,并且在您的测试(它)中使用异步或 fakeAsync 是可选的。
beforeEach(async(() => {
const fixture = TestBed.configureTestingModule({
declarations: [ AppComponent ],
imports: [ FormsModule ],
}).createComponent(AppComponent)
fixture.detectChanges();
}));
it('shoud to submit the text', () => {
// rest of the code ...