angularjestjs

Inherited @Input() variable initialized in child-constructor is null in ngOnInit only when testing


I am trying to test Angular components with jest. One component initializes an inherited (previously undefined) variable in its constructor. When running the application it works as expected. When I run my test and call MockRender(MyComponent), the variable is initialized in the constructor but when the ngOnInit-Block is reached, it is null (only for testing, not when running the application).

When I completely remove the initialization of the variable from my constructor, it is still changed from undefined to null between constructor-call and ngOnInit.

From my understanding, when a component is set up, the constructor is called and then ngOnInit, so nothing should be able to interfere between those two calls. In addition, I can't find anything in the code that might set the variable to null.

What might be the cause for a variable being reset to null between constructor-call and ngOnInit only when testing, not when running the application?

Edit: I finally managed to get a (not) working minimal example on stackblitz https://stackblitz.com/edit/stackblitz-starters-oj7kfs?file=src%2Fapp%2Ftest-child%2Ftest-child.component.ts I missed, that in the parent component, the variable is decorated with @Input(). The reason is: The variable represents a form-group which can be composed of multiple sub-forms from different components OR it represents one of those sub-forms. When it represents multiple sub-forms, it is defined in the corresponding component constructor. When it is a sub-form, it is passed to the parent component via @Input().

When running a test, the parent component sees "there is no value set for the @Input(), so the variable must be null". What I still do not know is, while testing, how I can keep the value assigned in the child component instead of letting the parent component overwrite it with null from @Input().


Solution

  • As stated in the question, during tests the @Input() variable is set to null despite being defined in the child class constructor. To avoid this, the code in the parent class was now changed from

    @Input()
    public input!: string
    

    to

    private _input!: string
    
    @Input()
    get input(): string {
      return this._input;
    }
    set input(value: string) {
      if (value) {
        this._input = value;
      }
    }
    

    This way, it is possible to set the variable via input or via child class constructor without breaking tests. This workaround is possible because resetting the variable to null/undefined is not desired (at least for our use case).