Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 - testing a component with @input used in ngOnInit lifecycle hook

Currently I am trying to test a child component which is accepting an input from the host component, and used within the ngOnInit life cycle hook like the code below.

@Component({
   selector: 'my-child-component',
   template: '<div></div>'
})
class ChildComponent implements OnInit {
    @Input() myValue: MyObject;
    transformedValue: SomeOtherObject;

    ngOnInit():void {
        // Do some data transform requiring myValue
        transformedValue = ...;
    }
}

@Component({
    template:`<my-child-component [myValue]="someValue"></my-child-component>`
})
class HostComponent {
    someValue: MyObject = new MyObject(); // how it is initialized it is not important.
}

How should the ChildComponent be tested in this case where myValue needs the to be present upon creation while being able to have access to ChildComponent.transformedValue for assertion.

I tried creating the ChildComponent using the Angular TestBed class like this

componentFixture = testBed.createComponent(LoginFormComponent)

however the ngOnInit would have already been called up to the point where I call

fixture.componentInstance.myValue = someValue;

I also tried creating a fixture of the HostComponent, and while that works, I got stuck at getting access to the ChildComponent instance that was created, which i require to perform assertions on the ChildComponent.transformedValue field.

Help is greatly appreciated!

Thanks a lot!

like image 227
JeanPaul A. Avatar asked Nov 25 '16 08:11

JeanPaul A.


People also ask

What is ngoninit hook in angular?

This is a life cycle hook called by Angular to indicate that the component has been completed. All initialization/declaration should be done with this method. Because the component will be initialized at this point. We simply added the console.log statement in ngOnInit for the parent and child component. Now let’s see the output.

Should you unit test the whole angular component?

When developing an Angular (read Angular 2 or Angular 4, or whatever the current version is when you read this) component that takes an input, you might decide to unit test the whole component. At least I hope you do! For example, we have a component, ComponentUnderTest, in which we want to display upcased input…

Do all lifecycle methods need to be implemented in angular?

There are a few who only execute once after component initialization. All lifecycle methods are available from @angular/core. Although not required, Angular recommends implementing every hook. This practice leads to better error messages regarding the component.

What does setinput do in angular?

setInput () sets the input in our host component. Assigning the input in our test before we let Angular detect the changes allows both our tests to pass.. Now, imagine we have to bind not only one but multiple inputs to our component.


1 Answers

Angular offers the ability to inject children components to their parent components using the @ViewChild() decorator. See https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-view-child

By updating the TestHostcomponent (that is written within the .spec.ts file) to the following

@Component({
    template:`<my-child-component [myValue]="someValue"></my-child-component>`
})
class TestHostComponent {
    @ViewChild(MyChildComponent)
    childComponent: MyChildComponent;
}

it exposes its child component instance ( and its variables ), making the assertion of the 'transformedValue' possible, as per below.

componentFixture = testBed.createComponent(TestHostComponent)
expect(componentFixture.componentInstance.childComponent.transformedValue).toEqual(...someValue);
like image 127
JeanPaul A. Avatar answered Oct 20 '22 09:10

JeanPaul A.