Angular组件模板驱动表单单元测试问题:表单无可用控件
Let’s break down why your test is failing and fix it step by step:
Root Causes
Missing
CustomInputComponentin Test Setup
YourPersonDetailsContactInfoComponentrelies on acustom-inputcomponent, but your test module doesn’t declare or import it. Without this, Angular can’t render the input elements, so their corresponding form controls never get registered with the parentNgForm.Mismatched
nameAttribute on Fax Input
Looking at your template, the fax input usesname="model.fax"but binds to[(ngModel)]="fax". This mismatch would register the control under the namemodel.fax(notfax) if it worked, which is almost certainly not what you intend.Incorrect Timing of
fixture.detectChanges()
You’re setting the model value before triggering initial change detection. Angular needs to run change detection first to initialize the component, render child components, and register form controls with the parent form.
Fixed Solution
Step 1: Update Test Module to Include CustomInputComponent
Add CustomInputComponent to the declarations array (or import its shared module if it’s part of one):
beforeEach(() => { TestBed.configureTestingModule({ imports: [FormsModule, NoopAnimationsModule], declarations: [ TestHostComponent, PersonDetailsContactInfoComponent, CustomInputComponent // Add this line ], providers: [ ] }); fixture = TestBed.createComponent(TestHostComponent); component = fixture.componentInstance; });
Step 2: Fix the Fax Input’s name Attribute
In person-details-contact-info.component.html, align the name attribute with your ngModel binding:
<custom-input type="text" [disabled]="permissions.canViewOnly" name="fax" [(ngModel)]="fax" maxlength="16"> </custom-input>
Step 3: Adjust Change Detection Timing in Tests
Run initial change detection first to set up the form, then update the model and re-run detection:
it('has invalid email format', () => { // Initialize component and form first fixture.detectChanges(); // Set invalid email value component.model.emailAddress = 'an invalid email format.'; fixture.detectChanges(); const ctrl = component.ngForm.form.get('emailAddress'); expect(ctrl).not.toBeNull(); // First verify the control exists expect(ctrl.valid).toBe(false); });
Explanation
- Declaring
CustomInputComponentlets Angular render the input elements and register their controls with the parentNgFormusing theirnameattributes. - Fixing the
nameattribute ensures the control is registered under the correct key, matching yourngModelbinding. - Running
fixture.detectChanges()upfront triggers the component’s initialization lifecycle, which is required for form controls to attach to the parentNgForm.
内容的提问来源于stack exchange,提问作者Jake Shakesworth

