最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - why ngForm "controls" property is empty in my test? (Angular) - Stack Overflow

programmeradmin0浏览0评论

I have a ponent which employs template-driven form

<form (ngSubmit)="onSearchCorpus(form)" #form="ngForm">
<bo-box [(ngModel)]="model.corpus" name="corpus" #corpus="ngModel"></bo-box>
<input [(ngModel)]="model.label" name="label" id="label" type="text" required pattern="^(?!\s*$)[\w\_\-\:\s]*" maxlength="50" class="form-control label-name" autoplete="off" #label="ngModel">
<textarea [(ngModel)]="model.query" name="query" id="query" maxlength="3600" required validateQuerySyntax class="form-control search-query" #query="ngModel" #queryControl
        placeholder="Example: (&quot;grantee&quot; OR &quot;grant&quot; OR &quot;sponsor&quot; OR &quot;contribute&quot; OR &quot;contributor&quot;) NEAR (&quot;non-profit organization&quot; OR &quot;charities&quot;)">
      </textarea>
 <button [disabled]="corpusValidationInProgress" type="submit" class="button-level-one">Search</button>
</form>

In the method that handles form submission I access controls property of NgForm instance and it works fine in browser.

onSearchCorpus(formData: NgForm) {
   ...
   const corpusErrors = formData.controls.corpus.errors;
   ...
}

However when I try to test this method with Karma the NgForm's controls property is empty. I'm confused why is that. The method fails with error cannot read property "errors" of undefined.

Here is how my test looks like:

it('should not perform corpusSearch if selected corpus no longer exists', () => {
    ponent.ngOnInit();
    const form = fixture.debugElement.query(By.css('form'));
    form.triggerEventHandler('submit', null);
    ...
});

and this is how I'm setting up my test suit:

beforeEach(async(() => {
    TestBed.configureTestingModule({
        // schemas: [NO_ERRORS_SCHEMA],
        imports: [
            FormsModule,
            PopoverModule
        ],
        providers: [
            CorpusSearchService,
            { provide: ApiService, useValue: ApiServiceStub },
            { provide: Router, useClass: RouterStab },
        ],
        declarations: [
            SearchCorpusComponent, //<--ponent under test
            ComboBoxComponent //<-- 3rd party bobox which is used for first control 
        ]
    })pileComponents();
}));

beforeEach(() => {
    fixture = TestBed.createComponent(SearchCorpusComponent);
    ponent = fixtureponentInstance;
    apiService = fixture.debugElement.injector.get(ApiService);
    subject = new Subject();
});

So, why controls is empty in test environment?

I have a ponent which employs template-driven form

<form (ngSubmit)="onSearchCorpus(form)" #form="ngForm">
<bo-box [(ngModel)]="model.corpus" name="corpus" #corpus="ngModel"></bo-box>
<input [(ngModel)]="model.label" name="label" id="label" type="text" required pattern="^(?!\s*$)[\w\_\-\:\s]*" maxlength="50" class="form-control label-name" autoplete="off" #label="ngModel">
<textarea [(ngModel)]="model.query" name="query" id="query" maxlength="3600" required validateQuerySyntax class="form-control search-query" #query="ngModel" #queryControl
        placeholder="Example: (&quot;grantee&quot; OR &quot;grant&quot; OR &quot;sponsor&quot; OR &quot;contribute&quot; OR &quot;contributor&quot;) NEAR (&quot;non-profit organization&quot; OR &quot;charities&quot;)">
      </textarea>
 <button [disabled]="corpusValidationInProgress" type="submit" class="button-level-one">Search</button>
</form>

In the method that handles form submission I access controls property of NgForm instance and it works fine in browser.

onSearchCorpus(formData: NgForm) {
   ...
   const corpusErrors = formData.controls.corpus.errors;
   ...
}

However when I try to test this method with Karma the NgForm's controls property is empty. I'm confused why is that. The method fails with error cannot read property "errors" of undefined.

Here is how my test looks like:

it('should not perform corpusSearch if selected corpus no longer exists', () => {
    ponent.ngOnInit();
    const form = fixture.debugElement.query(By.css('form'));
    form.triggerEventHandler('submit', null);
    ...
});

and this is how I'm setting up my test suit:

beforeEach(async(() => {
    TestBed.configureTestingModule({
        // schemas: [NO_ERRORS_SCHEMA],
        imports: [
            FormsModule,
            PopoverModule
        ],
        providers: [
            CorpusSearchService,
            { provide: ApiService, useValue: ApiServiceStub },
            { provide: Router, useClass: RouterStab },
        ],
        declarations: [
            SearchCorpusComponent, //<--ponent under test
            ComboBoxComponent //<-- 3rd party bobox which is used for first control 
        ]
    }).pileComponents();
}));

beforeEach(() => {
    fixture = TestBed.createComponent(SearchCorpusComponent);
    ponent = fixture.ponentInstance;
    apiService = fixture.debugElement.injector.get(ApiService);
    subject = new Subject();
});

So, why controls is empty in test environment?

Share Improve this question edited Oct 16, 2017 at 14:53 dKab asked Oct 16, 2017 at 12:06 dKabdKab 2,8585 gold badges23 silver badges38 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 11

The reason why controls is "empty" is that the controls were not initialized "yet" in the test environment at the time of calling onSearchCorpus.

I've prepared a Plunkr (see form.ponent.spec file) which demonstrates this issue. In the same file there is also a working solution.

So in short, in order to make this work you need to use fakeAsync mechanism.

So instead of:

  it('testing form the wrong way', () => {

    fixture.detectChanges();

    p.onSubmit(); // Validates and submits a form

    expect(p.submitted).toEqual(false);
  });

you should write a test like:

  it('testing form the proper way', fakeAsync(() => {

    // This first detectChanges is necessary to properly set up the form
    fixture.detectChanges();

    // Tick needs to be called in order for form controls to be registered properly.
    tick();

    p.onSubmit(); // Validates and submits a form

    expect(p.submitted).toEqual(false);

  }));
发布评论

评论列表(0)

  1. 暂无评论