试图对组件中基于模板的表单进行单元测试,表单没有控件 [英] Trying to unit test template-based form in a component, form has no controls

查看:58
本文介绍了试图对组件中基于模板的表单进行单元测试,表单没有控件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在组件中对基于基于模板的表单进行单元测试.表格很简单,包含一个人的联系信息.我想做的是对各种验证方案进行单元测试.我认为我可以做的就是简单地在例如email-address上设置一个值,然后检查ngForm对象,为emailAddress获取相应的formControl,然后检查有效性状态.但是,我发现的是,表单虽然存在,但根本不包含任何控件.因此,该表单似乎从未完全构建.

I'm trying to unit test a template-based form in my component. The form is simple and contains contact information for a person. What I'm trying to do is unit test various validation scenarios. I thought what I could do is simply set a value on, say, email-address and then inspect the ngForm object, obtain the respective formControl for emailAddress and then check for the validity status. However, what I'm finding is that the form, while it exists, it does not contain any controls at all. So it appears the form is never built entirely.

代码(为简便起见,我省略了import和一些提供程序的声明,等等):

The code (I've omitted import and some provider statements, etc for brevity):

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: ''
    }
}

**单元测试代码**

** unit test code **

@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控件.顺便说一下,这一切在实际组件中都可以正常工作,因此很明显,我在单元测试设置中做错了.

The above test is wrong because the "ctrl" object is null. The emailAddress control does not exist within the form. By the way, this all works fine in the actual component so clearly I'm doing something wrong with the unit test setup.

最后,为了理解代码,我将我的应用程序分解成一个很大的形式,分成了单独的组件.因此,此联系信息"组件是更大形式的一部分.这就是为什么我要绑定模型并在person-details-contact-info.component的providers部分中提供现有NgForm的原因.同样,一切都可以在应用程序内部完美运行,这只是我尝试进行单元测试的方式无法达到我期望的方式.

Lastly, for the sake of understanding the code, the way my app is I've broken up a very large form into separate components. So this "contact-info" component is a section of a much larger form. That is why I am binding to a model and providing an existing NgForm in the providers section of the person-details-contact-info.component. Again, everything works perfectly within the app itself, it's just the way I'm attempting to do my unit testing isn't working out the way I expected.

推荐答案

好的,我知道发生了什么事.我正在尝试执行的操作将起作用,但是在单元测试的"it"块内,并且在"fixture.detectChanges()"之后,我需要执行"fixture.whenStable()".例如:

Okay, I figured out what's going on. What I'm attempting to do will work but within the unit test's "it" block and after "fixture.detectChanges()" I need to then do a "fixture.whenStable()". For example:

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中)表单中的formControls将导致空对象.

This is interesting because I've had a similar issue within the actual app where a component, apparently, isn't "stable". Trying to immediately access (either within OnInit or AfterViewInit) formControls within a form will result in null objects.

这篇关于试图对组件中基于模板的表单进行单元测试,表单没有控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆