Suppose I have a component I want to test that uses a very complex component. Furthermore it calls some of its methods using references obtained by @viewChildren
. For example
@Component({
moduleId: module.id,
selector: 'test',
template: '<complex *ngFor='let v of vals'></complex>' ,
})
export class TestComponent{
vals = [1,2,3,4]
@ViewChildren(ComplexComponent) cpxs : QueryList<ComplexComponent>
// ....
}
How can I replace the complex-component for a test double in `TestBed'?
Something like
@Component({
moduleId : module.id,
selector: 'complex', template: ''
})
class ComplexComponentStub {
}
describe('TestComponent', () => {
beforeEach( async(() => {
TestBed.configureTestingModule({
declarations : [ComplexComponentStub, TestComponent],
});
it('should have four sons',()=>{
let fixture = TestBed.createComponent(TestComponent);
let comp = fixture.componentInstance as TestComponent;
fixture.detectChanges();
expect(comp.cpxs.length).toBe(4);
});
//....
}));
For a full example see the plnkr http://plnkr.co/edit/ybdrN8VimzktiDCTvhwe?p=preview
A mock component in Angular tests can be created by MockComponent function. The mock component respects the interface of its original component, but all its methods are dummies. To create a mock component, simply pass its class into MockComponent function.
The TestBed. createComponent() method is used to create an instance of the AppComponent. The spec then uses expect and matcher functions to see if the component produces the expected behavior. As a result, the spec will either pass or fail.
You can use reflect-metadata features to do it working:
it('should have four sons', () => {
const propMetadata = Reflect['getMetadata']('propMetadata', FatherComponent);
var originType = propMetadata.cpxs[0].selector;
propMetadata.cpxs[0].selector = ComplexComponentStub; // Replace ViewChild Type
let fixture = TestBed.createComponent(FatherComponent);
let comp = fixture.componentInstance as FatherComponent;
fixture.detectChanges();
expect(comp.cpxs.length).toBe(4);
propMetadata.cpxs[0].selector = originType; // reset ViewChild
});
Test in Plunker
You can read more about decorators and about reflect-metadata here:
if u just want to test the function in child component are called or not u can try this
component.ts
@ViewChildren('childComponent') childComponents: QueryList<YourComponent>;
component.spec.ts
it('Your test name', () => {
component.dashboard = dashboardMock; // ur using ngFor so u need to populate it first. u can mock it with ur own data
fixture.detectChanges(); // component will render the ngfor
const spies = [];
component.childComponents.toArray().forEach((comp) => {
comp.childFunction = () => { // Mock the function.
return 'Child function called!';
};
const tempSpy = {
spyKey: spyOn(comp, 'functionToBeMocked') // spy the mocked function
};
spies.push(tempSpy); // add to array
});
component.functionToTest(); // call the function u wish to test
spies.forEach((spy) => {
expect(spy.spyKey).toHaveBeenCalled(); // check if child function are called
});
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With