问题描述
我想测试一个模板驱动的表单。最初,我希望禁用表单的按钮,因为我想确保用户输入名称。这是通过名称输入字段上的'required'属性完成的。
所以我创建了以下模板:
<form #form="ngForm">
<!-- note the 'required' property on the input field -->
<input
type="text"
name="name"
id="name"
#name="ngModel"
required
ngModel
/>
<button type="submit" [disabled]="form.invalid">Submit</button>
{{ form.invalid | json }}
</form>
这在浏览器中呈现得很好:
现在,我想测试这种行为。这就是时髦的地方。测试如下:
import { async,ComponentFixture,Testbed } from "@angular/core/testing";
import { AppComponent } from "./app.component";
import { DebugElement } from "@angular/core";
import { By } from "@angular/platform-browser";
import { FormsModule } from "@angular/forms";
import { CommonModule } from "@angular/common";
describe("AppComponent",() => {
let component: AppComponent;
let fixture: ComponentFixture<AppComponent>;
let el: DebugElement;
let button: HTMLButtonElement;
beforeEach(async(() => {
Testbed.configureTestingModule({
declarations: [AppComponent],imports: [CommonModule,FormsModule]
}).compileComponents();
}));
beforeEach(() => {
fixture = Testbed.createComponent(AppComponent);
component = fixture.componentInstance;
el = fixture.debugElement;
fixture.detectChanges();
button = el.query(By.css("button")).nativeElement;
});
describe("submit button",() => {
it("should be disabled by default",() => {
expect(button.nativeNode.disabled).toBeTrue();
});
});
});
我的测试失败,并且无法识别form.invalid
属性。它将其设置为“ false”:
所以我最好的猜测是,如果输入值之一不符合要求,Angular应用程序的实际'ng build'或'ng serve'会做一些魔术,将ngForm设置为具有无效属性。 / p>
但是我该如何在测试中做到这一点?
我希望测试尽可能接近真实示例。因此,必须手动将form.invalid
设置为true
会破坏测试的目的。
这是上述代码的https://stackblitz.com/edit/angular-ivy-pfnkfc
的Stackblitz示例解决方法
因此,似乎有一些异步任务需要完成(我们等待fixture.whenStable
,然后需要调用fixture.detectChanges()
。这是我几乎总是使用反应形式的原因之一,因为它更容易测试。您可以仅通过TypeScript代码进行测试,而不必完全查看HTML。
import { async,ComponentFixture,TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { DebugElement } from '@angular/core';
import { By } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
describe('AppComponent',() => {
let component: AppComponent;
let fixture: ComponentFixture<AppComponent>;
let el: DebugElement;
let button: HTMLButtonElement;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [AppComponent],imports: [FormsModule]
}).compileComponents();
}));
beforeEach(async () => {
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
el = fixture.debugElement;
fixture.detectChanges();
});
describe('submit button',() => {
it('should be disabled by default',async () => {
await fixture.whenStable(); // wait for all asynchronous tasks to complete
fixture.detectChanges(); // call detectChanges again
button = fixture.debugElement.query(By.css('button')).nativeElement;
expect(button.disabled).toBe(true);
});
});
});
注意事项:
1。)每次调用fixture.detectChanges
时,都需要重新引用fixture.debugElement.query...
,因为每次调用fixture.detectChanges
时视图都会改变。如果我们要像在el
中一样继续使用beforeEach
,那么您将对HTML的外观有旧的了解。
2。)您无需在Angular单元测试中导入CommonModule
。