gpt4 book ai didi

forms - Angular2 NgModel 在 Jasmine 测试中没有获得值(value)

转载 作者:太空狗 更新时间:2023-10-29 17:08:55 28 4
gpt4 key购买 nike

我在 Angular 2 中使用模板驱动的表单,我正在尝试以测试先行的方式开发它们。我搜索了这个网站和互联网的其他部分,我基本上尝试了所有我能找到的东西(主要是 fakeAsync 中到处都是的 tick() 语句和 detectChanges() 串)来让 NgModel 附加到我的输入上以获取值,以便它可以传递给我的 onSubmit 函数。输入元素的值设置正确,但 NgModel 永远不会更新,这意味着 onSubmit 函数没有从 NgModel 获得正确的值。

这是模板:

<form id="createWorkout" #cwf="ngForm" (ngSubmit)="showWorkout(skillCountFld)" novalidate>  <input name="skillCount" id="skillCount" class="form-control" #skillCountFld="ngModel" ngModel />  <button type="submit" id="buildWorkout">Build a Workout</button></form>

Note: I know that the value sent the ngSubmit is going to cause the test to fail, but it means I can set a break point in the function and inspect the NgModel.

Here's the Component:

import { Component, OnInit } from '@angular/core';import {SkillService} from "../model/skill-service";import {NgModel} from "@angular/forms";@Component({  selector: 'app-startworkout',  templateUrl: './startworkout.component.html',  styleUrls: ['./startworkout.component.css']})export class StartworkoutComponent implements OnInit {  public skillCount:String;  constructor(public skillService:SkillService) { }  showWorkout(value:NgModel):void {    console.log('breakpoint', value.value);  }  ngOnInit() {  }}

Here is the spec:

/* tslint:disable:no-unused-variable */import {async, ComponentFixture, TestBed, fakeAsync, tick} from '@angular/core/testing';import {By, BrowserModule} from '@angular/platform-browser';import { DebugElement } from '@angular/core';import { StartworkoutComponent } from './startworkout.component';import {SkillService} from "../model/skill-service";import {Store} from "../core/store";import {SportService} from "../model/sport-service";import {FormsModule} from "@angular/forms";import {dispatchEvent} from "@angular/platform-browser/testing/browser_util";describe('StartworkoutComponent', () => {  let component: StartworkoutComponent;  let fixture: ComponentFixture;  let element:DebugElement;  let skillService:SkillService;  beforeEach(async(() => {    var storeSpy:any = jasmine.createSpyObj('store', ['getValue', 'storeValue', 'removeValue']);    var stubSkillService:SkillService = new SkillService(storeSpy);    TestBed.configureTestingModule({      declarations: [ StartworkoutComponent ],      providers: [{provide:Store , useValue:storeSpy}, SportService, SkillService],      imports: [BrowserModule, FormsModule]    })    .compileComponents();  }));  beforeEach(() => {    fixture = TestBed.createComponent(StartworkoutComponent);    component = fixture.componentInstance;    element = fixture.debugElement;    fixture.detectChanges();  });  it('should create', () => {    expect(component).toBeTruthy();  });  describe('without workout', () => {    let createWorkout:DebugElement;    let skillCount:HTMLInputElement;    let submitButton:HTMLButtonElement;    beforeEach(() => {      createWorkout = element.query(By.css('#createWorkout'));      skillCount = element.query(By.css('#skillCount')).nativeElement;      submitButton = element.query(By.css('#buildWorkout')).nativeElement;    });    it('has createWorkout form', () => {      expect(createWorkout).toBeTruthy();      expect(skillCount).toBeTruthy();    });    it('submits the value', fakeAsync(() => {      spyOn(component, 'showWorkout').and.callThrough();      tick();      skillCount.value = '10';      dispatchEvent(skillCount, 'input');      fixture.detectChanges();      tick(50);      submitButton.click();      fixture.detectChanges();      tick(50);      expect(component.showWorkout).toHaveBeenCalledWith('10');    }));  });});

I'm sure I'm missing something basic/simple, but I've spent the past day combing through everything I can find with no luck.

Edit:

I think maybe people are focusing on the wrong thing. I'm pretty sure at this point that I'm missing something basic about how ngForm and ngModel work. When I add

&lt;p>{{cwf.value | json}}&lt;/p>

进入表单,它只显示 {}。我相信它应该显示一个代表输入的成员属性。如果我在该字段中键入,值不会改变。如果我尝试绑定(bind)到 skillCountFld,也会发生类似的事情。所以我认为基本表单设置在某种程度上是不正确的,并且在输入正确连接到 skillCountFld Controller 之前测试永远不会工作。我只是看不出我错过了什么。

最佳答案

There are a lot of tests at the Angular site that are successfully setting this without waiting for whenStable https://github.com/angular/angular/blob/874243279d5fd2bef567a13e0cef8d0cdf68eec1/modules/%40angular/forms/test/template_integration_spec.ts#L1043

那是因为当您在 beforeEach 中触发 fixture.detectChanges(); 时,这些测试中的所有代码都在 fakeAsync 区域内执行。所以 fakeAsync 区域不知道其范围之外的异步操作。当您第一次调用 detectChangesngModel 被初始化

 NgModel.prototype.ngOnChanges = function (changes) {
this._checkForErrors();
if (!this._registered)
this._setUpControl(); //<== here

并获得正确的输入事件回调

NgForm.prototype.addControl = function (dir) {
var _this = this;
resolvedPromise.then(function () { // notice async operation
var container = _this._findContainer(dir.path);
dir._control = (container.registerControl(dir.name, dir.control));
setUpControl(dir.control, dir); // <== here

setUpControl 中,您可以看到将由 input 事件调用的函数

dir.valueAccessor.registerOnChange(function (newValue) {
dir.viewToModelUpdate(newValue);
control.markAsDirty();
control.setValue(newValue, { emitModelToViewChange: false });
});

1) 因此,如果您将 fixture.detectChangesbeforeEach 移动到您的测试中,那么它应该可以工作:

 it('submits the value', fakeAsync(() => {
spyOn(component, 'showWorkout').and.callThrough();
fixture.detectChanges();

skillCount = element.query(By.css('#skillCount')).nativeElement;
submitButton = element.query(By.css('#buildWorkout')).nativeElement;

tick();
skillCount.value = '10';
dispatchEvent(skillCount, 'input');
fixture.detectChanges();

submitButton.click();
fixture.detectChanges();
expect(component.showWorkout).toHaveBeenCalledWith('10');
}));

Plunker Example

但是这个解决方案看起来非常复杂,因为您需要重写代码以在每个 it 语句中移动 fixture.detectChanges(并且 skillCount, submitButton 等)

2) 正如 Dinistro 所说的 asyncwhenStable 也应该帮助你:

it('submits the value', async(() => {
spyOn(component, 'showWorkout').and.callThrough();
fixture.whenStable().then(() => {
skillCount.value = '10';
dispatchEvent(skillCount, 'input');
fixture.detectChanges();

submitButton.click();
fixture.detectChanges();

expect(component.showWorkout).toHaveBeenCalledWith('10');
})
}));

Plunker Example

但等等,为什么我们必须更改我们的代码?

3) 只需将 async 添加到您的 beforeEach 函数

beforeEach(async(() => {
fixture = TestBed.createComponent(StartworkoutComponent);
component = fixture.componentInstance;
element = fixture.debugElement;
fixture.detectChanges();
}));

Plunker Example

关于forms - Angular2 NgModel 在 Jasmine 测试中没有获得值(value),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42426891/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com