Kashyap
Kashyap

Reputation: 216

OverrideComponent with TestBed

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.

Upvotes: 8

Views: 15967

Answers (3)

Marco C.
Marco C.

Reputation: 1412

This is what I did with Angular 16 and standalone components:

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

and then:

await TestBed.configureTestingModule({
  ...
}).overrideComponent(ParentComponent, {
  remove: {imports: [ChildComponent]},
  add: {imports: [MockComponent]}
}).compileComponents();

Upvotes: 7

DWilches
DWilches

Reputation: 23035

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.

Upvotes: 2

Luis Cazacu
Luis Cazacu

Reputation: 226

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/

Upvotes: 11

Related Questions