angular: bug(testing) ngOnChanges not called for component initialized via TestComponentBuilder

I’m submitting a … (check one with “x”)

[x] bug report
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior

When creating a component via TestComponentBuilder the ngOnChanges-Callback is not executed. Having a component like this:

export class TimePickerComponent {

  @Input("time") private timeString = "";

  ngOnInit() {
    console.log("init")
  }
  ngOnChanges(changes) {
    console.log("changes");

    //do some transformation on the timeString- inputbinding
    }
  }
...
}

And creating the component in the test like this:

 it('display passed time in input fields', (done) => {
    tcb
      .createAsync(TimePickerComponent)
      .then(fixture => {
        let timePicker: TimePickerComponent = fixture.componentInstance;
        (<any>timePicker).timeString = "11:20:23";
     //   timePicker.ngOnChanges(null);  ->> needs to be called manually
        fixture.detectChanges();

        let hourInput = fixture.debugElement.query(By.css('#hours > input'));
        expect(hourInput.nativeElement.value).toBe("11");
        done();
      });
  });

the ngOnChanges callback of the component gets never called. (ngOnInit gets called by the way). To fix the test it is currently needed to call ngOnChanges manually…

Expected/desired behavior

ngOnChanges should be called while initializing the component

What is the motivation / use case for changing the behavior?

Being able to test components that use ngOnChanges callback without having to call the method manually

Please tell us about your environment:

  • Angular version: 2.0.0-rc.4
  • Browser: [all ]
  • Language: [all]

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 35
  • Comments: 23 (4 by maintainers)

Commits related to this issue

Most upvoted comments

It burdensome and arguably impractical to create a dummy parent component just to have it pass a value via Input() to trigger ngOnChanges(). This especially true when unit testing.

Why is it that detectChanges() cannot trigger the ngOnChanges() hook?

I would actually expect that fixture.detectChanges(); will trigger the ngOnChange callback as it anyways synchronises the state between the component and the view…

In any case, this needs to be clarified in the docs as suggested by @StdVectorBool.

this is still an issue in Angular 2.0 Final Release

I understand why the framework specifies the event model for ngOnChanges that way but the behavior from the testing infrastructure is not intuitive. The majority of comments in the thread suggest the natural expectation is that the test code should automatically be executed in an ngZone as if it was application code.

Granted there are other things in the existing testing infrastructure (fixture.detectChanges(), fakeAsync(), tick()) that already establish a convention that this seamlessness can’t be expected… so perhaps this just needs better documentation in the Testing manual?

I’m working with angular 2.1 and still meeting this issue.

Can this issue be reopened, as the angular.io repository has been archived and the docs still need updating.

I’ll throw in a “me to” 😃

Can confirm this bug is still occurring in 7.2.

https://github.com/angular/angular/issues/9866#issuecomment-261631059 is absolutely right. To me it works as expected. If u need to test ngOnChanges without changing component inputs then call it yourself.

If I understand correctly, you manually changed the input value in the component instance. Basically the OnChanges hook is triggered when inputs are passed via the view only. Please read this answer: http://stackoverflow.com/questions/37408801/testing-ngonchanges-lifecycle-hook-in-angular-2

@DzmitryShylovich http://plnkr.co/edit/1RnC7gAF7PmqHFskUCVU?p=preview

Just changed the template from “hello {{name}}” to “{{calculatedName}}”, the "hello " is supposed to be added by ngOnChanges, but it never gets called so calculatedName is always empty.

My interpretation of these two pages is that you can only expect ngOnChanges() to be called if the data-binding is updated by Angular and not your direct manipulation: https://angular.io/docs/ts/latest/api/core/index/OnChanges-class.html https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html#!#onchanges

Here’s an example where a test host data-binds to time-pickers input and ngOnChanges correctly firing when the input changes due to a data-binding update: https://plnkr.co/edit/84gFtoT7FgEiew8brp9L?p=preview