angular - 尝试在组件中对基于模板的表单进行单元测试,表单没有控件

标签 angular forms unit-testing

我正在尝试对我的组件中的基于模板 的表单进行单元测试。表格很简单,包含一个人的联系信息。我要做的是对各种验证场景进行单元测试。我想我能做的就是简单地设置一个值,比如说,电子邮件地址,然后检查 ngForm 对象,获取 emailAddress 的相应 formControl,然后检查有效性状态。但是,我发现该表单虽然存在,但根本不包含任何控件。因此,表格似乎从未完全构建。

代码(为简洁起见,我省略了导入和一些提供程序语句等):

person-details-contact-info.component.html

<custom-input type="text"
            name="emailAddress"
            [(ngModel)]="model.emailAddress"
            maxlength="255"
            pattern="^[^\s@]+@[^\s@]+\.[^\s@]{2,}$"
            #emailAddress="ngModel">
</custom-input>

<custom-input type="text"
            [disabled]="permissions.canViewOnly"
            name="phone"
            [(ngModel)]="model.phone"
            maxlength="16">
</custom-input>

<custom-input type="text"
            [disabled]="permissions.canViewOnly"
            name="model.fax"
            [(ngModel)]="fax"
            maxlength="16">
</custom-input>

person-details-contact-info.component.ts

@Component({
    selector: 'person-details-contact-info',
    templateUrl: 'person-details-contact-info.component.html',
    viewProviders: [{ provide: ControlContainer, useExisting: NgForm }]
})
export class PersonDetailsContactInfoComponent {

    @Input('model')
    model: {
        emailAddress: '',
        phone: '',
        fax: ''
    }
}

** 单元测试代码**

@Component({
    template: `
        <form #form="ngForm">
            <person-details-contact-info [(model)]="model">
            </person-details-contact-info>
        </form>
    `,
    providers: [ ]
})
export class TestHostComponent {
    model: PersonDetailsContactInfoModel = new PersonDetailsContactInfoModel();

    @ViewChild('form')
    ngForm: NgForm;
}

describe('In the file "person-details-contact-info.component.ts', () => {

    let fixture: ComponentFixture<TestHostComponent>;
    let component: TestHostComponent;

    beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [FormsModule, NoopAnimationsModule],
            declarations: [TestHostComponent, PersonDetailsContactInfoComponent],
            providers: [ ]
        });

        fixture = TestBed.createComponent(TestHostComponent);
        component = fixture.componentInstance;
    });

    it('is has invalid email format', () => {
        component.model.emailAddress = 'an invalid email format.';
        fixture.detectChanges();

        const ctrl = component.ngForm.form.get('emailAddress');
        expect(ctrl.valid).toBe(false);
    });
});

上面的测试是错误的,因为“ctrl”对象是空的。表单中不存在 emailAddress 控件。顺便说一下,这一切在实际组件中都运行良好,所以很明显我在单元测试设置方面做错了。

最后,为了理解代码,我的应用程序的方式是将一个非常大的表单分解成单独的组件。所以这个“联系信息”组件是一个更大表单的一部分。这就是为什么我绑定(bind)到一个模型并在 person-details-contact-info.component 的提供者部分提供一个现有的 NgForm。同样,应用本身内的一切都完美运行,只是我尝试进行单元测试的方式没有达到我的预期。

最佳答案

好的,我知道发生了什么。我尝试做的事情会起作用,但在单元测试的“it” block 内和“fixture.detectChanges()”之后我需要做一个“fixture.whenStable()”。例如:

it('is has invalid email format', () => {
    component.model.emailAddress = 'an invalid email format.';
    fixture.detectChanges();

    fixture.whenStable().then(() => {
        const ctrl = component.ngForm.form.get('emailAddress');
        expect(ctrl.valid).toBe(false);
    });        
});

这很有趣,因为我在实际应用程序中遇到过类似的问题,其中组件显然不是“稳定的”。尝试立即访问(在 OnInit 或 AfterViewInit 中)表单中的 formControl 将导致空对象。

关于angular - 尝试在组件中对基于模板的表单进行单元测试,表单没有控件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48045651/

相关文章:

javascript - 从小部件获取表单父级

javascript - 按下按钮时使用 Javascript 刷新 div 内容

java - Jmock/junit 测试

javascript - Angular Material 将原色添加到 Div

javascript - 如何从内容丰富的 CDA 响应中删除 sys 对象?

sass - 如何将 TypeScript WebPack ts-loader 与 Angular2 @View 样式集成?

css - Mat-autocomplete 宽度不随输入主机上的动态宽度调整

javascript - 我需要一个表单的答案才能立即重定向到另一个表单

jquery - 如何为 Chrome 编写 Greasemonkey 脚本以便对其进行单元测试?

Android:如何保存、清除然后恢复 SharedPreferences 以进行单元测试?