Amy*_*hip 10 forms karma-jasmine angular
我在Angular 2中使用模板驱动的表单,我正在尝试先测试它们.我已经搜索过这个网站和互联网的其余部分了,我已经尝试了基本上我能找到的所有内容(主要是一串tick()语句和detectChanges()在fakeAsync中的任何地方)以获得附加到我的输入的NgModel来获取该值可以传递给我的onSubmit函数.input元素的值设置正确,但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>
注意:我知道发送ngSubmit的值会导致测试失败,但这意味着我可以在函数中设置断点并检查NgModel.
这是组件:
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() {
}
}
这是规格:
/* 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');
}));
});
});
我确定我错过了一些基本/简单的东西,但是我在过去的一天里一直在梳理我能找到的所有东西而没有运气.
我想也许人们会关注错误的事情.我很确定在这一点上我遗漏了一些关于ngForm和ngModel如何工作的基本知识.当我添加
<p>{{cwf.value | json}}</p>
Run Code Online (Sandbox Code Playgroud)
在表单中,它只显示{}.我相信它应该显示一个表示输入的成员属性.如果我输入字段,则值不会更改.如果我尝试绑定到skillCountFld,会发生类似的事情.所以我认为基本的表单设置是不正确的,并且在输入正确连接到skillCountFld控制器之前测试永远不会工作.我只是看不到我错过的东西.
yur*_*zui 17
Angular网站上有很多测试成功地设置了这个,而没有等待什么时候安装https://github.com/angular/angular/blob/874243279d5fd2bef567a13e0cef8d0cdf68eec1/modules/%40angular/forms/test/template_integration_spec.ts#L1043
那是因为这些测试中的所有代码都是在fakeAsync区域fixture.detectChanges();内执行的beforeEach.因此fakeAsynczone不知道其范围之外的异步操作.当你detectChanges第一次打电话时ngModel初始化
NgModel.prototype.ngOnChanges = function (changes) {
this._checkForErrors();
if (!this._registered)
this._setUpControl(); //<== here
Run Code Online (Sandbox Code Playgroud)
并获得输入事件的正确回调
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
Run Code Online (Sandbox Code Playgroud)
在里面setUpControl你可以看到将被input事件调用的函数
dir.valueAccessor.registerOnChange(function (newValue) {
dir.viewToModelUpdate(newValue);
control.markAsDirty();
control.setValue(newValue, { emitModelToViewChange: false });
});
Run Code Online (Sandbox Code Playgroud)
1)因此,如果你fixture.detectChanges从beforeEach测试转到那么它应该工作:
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');
}));
Run Code Online (Sandbox Code Playgroud)
但是,这种解决方案似乎很复杂,因为你需要重写代码移动fixture.detectChanges在每个的it语句(和也有一个问题skillCount,submitButton等等)
2)正如Dinistro async一起说的那样whenStable也应该帮助你:
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');
})
}));
Run Code Online (Sandbox Code Playgroud)
但是等一下我们为什么要改变我们的代码呢?
3)只需添加async到您的beforeEach功能
beforeEach(async(() => {
fixture = TestBed.createComponent(StartworkoutComponent);
component = fixture.componentInstance;
element = fixture.debugElement;
fixture.detectChanges();
}));
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6281 次 |
| 最近记录: |