当前位置: 首页 > 知识库问答 >
问题:

Angular2 NgModel在Jasmine测试中未获得值

吕奇
2023-03-14
<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>

组件如下:

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');
    }));
  });
});

我肯定我错过了一些基本的/简单的东西,但我花了过去一天的时间梳理了所有我能找到的东西,没有运气。

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

共有1个答案

危宜
2023-03-14

Angular站点上有大量测试成功地设置了此设置,而无需等待何时稳定https://github.com/Angular/Angular/blob/874243279d5fd2bef567a13e0cef8d0cdf68eec1/modules/%40Angular/forms/test/template_integration_spec.ts#l1043

这是因为这些测试中的所有代码都是在fakeasync区域内执行的,而您在beforeach内激发fixture.detectChanges();。因此fakeasync区域不知道其作用域之外的异步操作。当您调用DetectChanges时,第一次初始化NGModel

 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.detectchangesbeforeace移动到您的测试中,那么它应该可以工作:

 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');
}));

但是这个解决方案似乎非常复杂,因为您需要重写代码来移动每个it语句中的fixture.detectchangesskillcountsubmitbutton等也有问题)

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');
  })
}));

柱塞实例

但是等等,为什么我们要改变我们的代码?

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

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

柱塞实例

 类似资料:
  • 我试图用Jasmine为Angularjs编写单元测试。这是我的控制器: 和测试 测试失败,即使我试图测试期望(true). toBe(true); 茉莉花,因果报应,棱角分明的嘲弄都在我的索引里。jasmine调试页面中的html,还有测试脚本。 我发现如果删除beforeach()块,expect(true)。托比(真的)通过了。 下面是一个错误:

  • 问题内容: 我一直在努力围绕Jasmine 2.0和AngularJS的承诺。我知道: 茉莉花2.0引入的功能,以取代旧的和功能 在触发摘要循环之前,AngularJS Promise 不会解析 如何在Jasmine 2.0中使用新的异步语法测试AngularJS Promise? 问题答案: 致电后: 致电。这将强制进行摘要循环并传播承诺解决方案 致电。告诉Jasmine异步测试已经完成 这是一

  • 问题 假如你正在使用 CoffeeScript 写一个简单地计算器,并且想要验证其功能是否与预期一致。可以使用 Jasmine 测试框架。 讨论 在使用 Jasmine 测试框架时,你要在一个参数(spec)文档中写测试,文档描述的是代码需要测试的预期功能。 例如,我们希望计算器可以实现加法和减法的功能,并且可以正确进行正数和负数的运算。我们的 spec 文档如下列所示。 # calculator

  • 问题内容: 如何使用AngularJS / karma / jasmine测试来测试API后端? 我试图创建显示我的错误的最小测试用例: echo_server.py 测试/单位/apiSpec.js 输出 问题答案: 提到的测试堆栈不适用于这种方式。由于该请求已装饰在您原始请求的顶部,因此该请求永远不会被分派。 要允许请求通过,您要么需要排除,要么指定某些网址应像这样通过: 在此处阅读文档 另外

  • 我知道在摘要周期中手动调用或会导致$digest已经在进行中错误,但我不知道为什么我在这里得到它。 这是一个包装的服务的单元测试,该服务足够简单,它只是防止对服务器进行重复调用,同时确保试图进行调用的代码仍然获得预期的数据。 单元测试也非常简单,它使用来预期请求。 当调用时出现“$digest ready in progress”错误,这将导致失败。我不知道为什么。我可以通过在这样的超时中包装来解

  • 我接着跑道: 咕噜的因果报应 以运行测试,但它失败,出现以下错误: