测试不识别模板驱动形式中的默认 属性 `form.invalid`
Test not recognising default property `form.invalid` in a template driven form
我想测试一个模板驱动的表单。最初我希望禁用表单的按钮,因为我想确保用户输入名称。这是通过名称输入字段中的 '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 设置为具有无效的 属性 如果输入值之一不符合要求。
但是我该如何在测试中执行此操作?
我希望测试尽可能接近现实世界的例子。因此必须手动将 form.invalid
设置为 true
有点违背了测试的目的。
这是上述代码的 Stackblitz 示例:https://stackblitz.com/edit/angular-ivy-pfnkfc
所以好像有一些异步任务需要完成(我们等待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
时视图都会发生变化。如果我们像在 beforeEach
中那样继续使用 el
,您将对 HTML 的外观有一个旧的参考。
2.) 您不需要在 Angular 单元测试中导入 CommonModule
。
我想测试一个模板驱动的表单。最初我希望禁用表单的按钮,因为我想确保用户输入名称。这是通过名称输入字段中的 '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 设置为具有无效的 属性 如果输入值之一不符合要求。
但是我该如何在测试中执行此操作?
我希望测试尽可能接近现实世界的例子。因此必须手动将 form.invalid
设置为 true
有点违背了测试的目的。
这是上述代码的 Stackblitz 示例:https://stackblitz.com/edit/angular-ivy-pfnkfc
所以好像有一些异步任务需要完成(我们等待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
时视图都会发生变化。如果我们像在 beforeEach
中那样继续使用 el
,您将对 HTML 的外观有一个旧的参考。
2.) 您不需要在 Angular 单元测试中导入 CommonModule
。