7

I have MainComponent that uses ChildComponentA as a @ViewChild. MainComponent is calling a method on ChildComponentA.

I want to write an unit test case mocking ChildComponentA. How can I do this using TestBed (in Angular 2 RC5)?

Before I used to use overrideDirective(MainComponentName, ChildComponentA, MockChildComponentA); Is there an equivalent to this using TestBed?

I tried using

TestBed.overrideComponent(ChildComponentA,{
        set: {
          template: '<div></div>'
        }
      }); 

which just sets the template, but I want to mock the methods in the component as well.

Mathijs Segers
  • 6,168
  • 9
  • 51
  • 75
Kashyap
  • 178
  • 1
  • 2
  • 11

2 Answers2

7

I think in this case you can try and replace the child component with a mock component. Just create a mock component with the same selector and use TestBed to remove the declaration of the real child component and add the declaration to your mock component.

@Component({
  selector: 'child',
  template: '<div></div>'
})
class MockComponent {

}

And in your test do this to use the mock component:

    TestBed.configureTestingModule({
        imports: [MyModule],
        declarations: [ParentComponent, MockComponent]
    });

    TestBed.overrideModule(MyModule, {
        remove: {
            declarations: [ParentComponent, ChildComponent],
            exports: [ParentComponent, ChildComponent]
        }
    });

More details here: https://github.com/angular/angular/issues/10689. Make sure to re-declare the ParentComponent, it does not work otherwise (not sure why).

If you use @ViewChild to get a reference to the child component, you will need to modify it to not use the type of the component, but an id. Use @ViewChild('child') instead of @ViewChild(ChildComponent). See second example from here: http://learnangular2.com/viewChild/

Luis Cazacu
  • 186
  • 4
  • Thanks for your response. I have configured the TestBed.configureTestingModule with the mockComponent as you mentioned, but didn't overrideModule and still works. I didn't import the MyModule. – Kashyap Sep 07 '16 at 18:31
  • Yes, the override example was there just in case you want to reuse the production ngModule in your tests. – Luis Cazacu Sep 07 '16 at 18:36
  • I have a similar case, but I'm testing a service, which uses a component. I want to mock that component. I tried this, but it does not work. When I run the tests, I get "Error: No component factory found for XComponent". Any Ideas? – jpgrassi Oct 27 '16 at 15:00
2

Notice that if the ChildComponent is being declared in the TestModule itself, there is no need to override the module where the original was declared.

So, if your TestBed declaration looks like this:

TestBed.configureTestingModule({
    declarations: [
        ParentComponent,
        ChildComponent         // This is what you'd like to mock
    ]
});

Then, to override ChildComponent all you need is:

@Component({
    selector: 'child',
    template: '<div></div>'
})
class MockChildComponent {
}

TestBed.configureTestingModule({
    declarations: [
        ParentComponent,
        MockChildComponent      // Notice the original is replaced by the mock
    ]
});

As long as ChildComponent and MockChildComponent have the same selector, this one should work.

The other answer given for this question works for the cases the ChildComponent is being brought from a different module into the TestBed.

Note

If your ChildComponent has any @Input or @Output, then include those too in your MockChildComponent.

Daniel
  • 21,933
  • 14
  • 72
  • 101