Angular 6 Unit Test ngOnInit with a setTimeOut not working

蹲街弑〆低调 提交于 2019-12-12 10:21:27

问题


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>

回答1:


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!



来源:https://stackoverflow.com/questions/54336414/angular-6-unit-test-ngoninit-with-a-settimeout-not-working

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!