带有 setTimeOut 的 Angular 6 单元测试 ngOnInit 不起作用 [英] Angular 6 Unit Test ngOnInit with a setTimeOut not working

查看:47
本文介绍了带有 setTimeOut 的 Angular 6 单元测试 ngOnInit 不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 ngOnInit 函数中有一个带有 setTimeOut 函数的组件.要为此编写单元测试用例,我使用 tick 和 fakeAsync 来快进 setTimeOut.但是,它没有被执行,这反过来也没有调用其他函数 closeAlert().

组件代码:

导出类 BannerComponent 实现 OnInit {@Input()errorData: 任何;@Input() 回调:任意;@Input()autoHide: 布尔值;构造函数(){}ngOnInit() {如果(this.autoHide){设置超时(() => {this.closeAlert();}, 500);}}关闭警报(){this.errorData = null;如果(this.callback){this.callback();}};}

规范文件:

describe('BannerComponent', () => {让组件:BannerComponent;让夹具:ComponentFixture;beforeEach(async(() => {TestBed.configureTestingModule({声明:[ BannerComponent ]}).compileComponents();}));beforeEach(async() => {夹具 = TestBed.createComponent(BannerComponent);组件 = 夹具.componentInstance;component.ngOnInit();夹具.detectChanges();});it("横幅应该在 500 毫秒后隐藏", fakeAsync(() => {组件.errorData = {_statusMessage: "新的警报横幅",_statusCode: '200',};component.callback = null;;component.autoHide = true;滴答(600);夹具.detectChanges()fixture.whenStable().then(() => {让横幅 = fixture.debugElement.query(By.css('.success'));期望(横幅).toBe(空)})}));});

HTML 代码:

<p>{{errorData._statusMessage}}</p>

解决方案

我在代码中看到的几个问题.

  • 中设置有效数据之前,您正在调用 component.ngOnInit()fixture.detectChanges()(也会调用 ngOnInit)component.errorData.
  • 我不清楚为什么您希望 banner 为空,并且显示的 html 为空.因此,我将测试更改为查看 component.closeAlert() 已被调用,并且如果 component.errorData 已重置为 null,因为看起来这就是您的真实情况想测试.为了对此进行测试,我监视了 component.closeAlert().
  • 我通过在 tick(499) 之后进行测试,然后再进行一次测试,设置了对 component.closeAlert() 进行调用的准确时间...

正在运行 StackBlitz.

代码:

beforeEach(async(() => {//稍微修正了不正确的异步包装器 ...夹具 = TestBed.createComponent(BannerComponent);组件 = 夹具.componentInstance;//component.ngOnInit();//<-- 不要在这里调用,数据尚未设置...//fixture.detectChanges();//同上}));it("横幅应该在 500 毫秒后隐藏", fakeAsync(() => {spyOn(component, 'closeAlert').and.callThrough();//设置一个 spy 以便我们稍后进行测试组件.errorData = {_statusMessage: "新的警报横幅",_statusCode: '200',};component.callback = null;;component.autoHide = true;夹具.detectChanges();//<-- 这将执行 ngOnInit()期望(component.errorData).not.toBeNull();//<-- 在 ngOnInit 之后,仍然不是 null期望(component.closeAlert).not.toHaveBeenCalled();滴答(499);//<-- 现在让 499 毫秒过去...期望(component.errorData).not.toBeNull();//<-- 在所有的假"时间之后,仍然不为空期望(component.closeAlert).not.toHaveBeenCalled();滴答(1);//<-- 现在再打 1 毫秒...期望(component.errorData).toBeNull();//<-- 现在这变成了 NULL期望(component.closeAlert).toHaveBeenCalled();//<-- 方法被调用//fixture.whenStable().then(() => {//let banner = fixture.debugElement.query(By.css('.success'));//期望(横幅).toBe(null)//});}));

我希望这会有所帮助!

I have a component with a setTimeOut function inside a ngOnInit function. To write unit test cases for that I'm using tick and fakeAsync to fast forward the setTimeOut. But, it's not getting executed which in turn is not calling other function closeAlert().

Component code:

export class BannerComponent implements OnInit {

  @Input()errorData: any;

  @Input()callback: any;

  @Input()autoHide: boolean;

  constructor() { }

  ngOnInit() {

    if (this.autoHide) {
      setTimeout
        (() => {
          this.closeAlert();
        }, 500);
    }
  }

  closeAlert() {
    this.errorData = null;
    if (this.callback) {
      this.callback();
    }
  };
}

Spec file:

describe('BannerComponent', () => {
  let component: BannerComponent;
  let fixture: ComponentFixture<BannerComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ BannerComponent ]
    })
    .compileComponents();
  }));

  beforeEach(async() => {
    fixture = TestBed.createComponent(BannerComponent);
    component = fixture.componentInstance;
    component.ngOnInit();
    fixture.detectChanges();
  });

  it("banner should hide after 500ms", fakeAsync(() => {
    component.errorData = {
      _statusMessage: "New alert banner",
      _statusCode: '200',
    };
    component.callback = null;;
    component.autoHide = true;

    tick(600);
    fixture.detectChanges()

    fixture.whenStable().then(() => {
      let banner = fixture.debugElement.query(By.css('.success'));
      expect(banner).toBe(null)
    })
  }));

});

Html code:

<div class="success">
    <p>{{errorData._statusMessage}}</p>
</div>

解决方案

A couple of issues I saw with the code.

  • You are calling both component.ngOnInit() and fixture.detectChanges() (which will also call ngOnInit) BEFORE you have set up valid data in component.errorData.
  • It is unclear to me why you are expecting banner to be null with the html you have shown. I therefore changed the test to seeing component.closeAlert() had been called, and if component.errorData had been reset to null, since it appears that is what you are really wanting to test. To test for this I spied on component.closeAlert().
  • I set up the ticks to show exactly when the call is made to component.closeAlert() by testing after tick(499), and then after one more tick ...

Working StackBlitz.

Code:

beforeEach(async(() => { // slight correction of incorrect async wrapper ...
  fixture = TestBed.createComponent(BannerComponent);
  component = fixture.componentInstance;
  // component.ngOnInit(); // <-- don't call this here, the data isn't set up yet ...
  // fixture.detectChanges(); // ditto
}));

it("banner should hide after 500ms", fakeAsync(() => {
  spyOn(component, 'closeAlert').and.callThrough(); // set up a spy so we can test later
  component.errorData = {
    _statusMessage: "New alert banner",
    _statusCode: '200',
  };
  component.callback = null;;
  component.autoHide = true;

  fixture.detectChanges(); // <-- this will execute ngOnInit()
  expect(component.errorData).not.toBeNull(); // <-- after ngOnInit, still NOT null
  expect(component.closeAlert).not.toHaveBeenCalled();
  tick(499); // <-- now let 499ms pass ...
  expect(component.errorData).not.toBeNull(); // <-- after all that "fake" time, still NOT null
  expect(component.closeAlert).not.toHaveBeenCalled();
  tick(1); // <-- now tick for just 1 more millisecond ...
  expect(component.errorData).toBeNull(); // <-- now this has become NULL
  expect(component.closeAlert).toHaveBeenCalled(); // <-- and the method was called
  // fixture.whenStable().then(() => {
  //   let banner = fixture.debugElement.query(By.css('.success'));
  //   expect(banner).toBe(null)
  // });
}));

I hope this helps!

这篇关于带有 setTimeOut 的 Angular 6 单元测试 ngOnInit 不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆