Reputation: 1121
I have a component that gets data from a service which creates children on the View
. Those children are only available when the View
is created. In my example below the View
is not created before it reaches its tests, thus test 2 fails.
component:
@Component({
selector: 'component-to-test',
providers: [Service],
directives: [NgFor, ChildComponent],
template: `
<child [data]="childData" *ngFor="let childData of data"></child>
})
export class ComponentToTest implements OnInit {
@ViewChildren(ChildComponent) children: QueryList<ChildComponent>;
private data: any;
public ngOnInit() {
this.getData();
}
private getData() {
// async fetch data from a service
}
}
spec:
describe('ComponentToTest', () => {
beforeEach(inject([ComponentToTest], (component: ComponentToTest) => {
component.ngOnInit();
}));
it('should initialise data', inject([ComponentToTest], (component: ComponentToTest, service: Service) => {
return service.getData().toPromise().then(() => {
expect(component.data).toBeDefined();
})
}));
it('should initialise children', inject([ComponentToTest], (component: ComponentToTest, service: Service) => {
return service.getData().toPromise().then(() => {
expect(component.children).toBeDefined();
})
}));
});
Test 1 passes, test 2 fails. How do you test something that is created after the View
or Content
is initialised?
Upvotes: 2
Views: 1860
Reputation: 657937
Injecting a component only creates an instance of the component class but no lifecycle callbacks will be called and no view created.
You need to use the TestComponentBuilder
instead:
describe('ComponentToTest', () => {
let component: ComponentToTest;
beforeEach(async(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
tcb.createAsync(ComponentToTest).then((fixture: ComponentFixture<ComponentToTest>) => {
fixture.detectChanges();
component = fixture.componentInstance;
// component.ngOnInit(); // called by `fixture.detectChanges()`
});
})));
it('should initialise children', () => {
expect(component.children).toBeDefined();
});
});
To ensure that the test doesn't end before all async execution is done also use async()
like already mentioned by Thierry.
Upvotes: 2
Reputation: 202286
I would leverage the async
function:
it('should initialise children', async(inject([ComponentToTest], (component: ComponentToTest, service: Service) => {
return service.getData().toPromise().then(() => {
expect(component.children).toBeDefined();
});
})));
From the documentation:
Wraps a test function in an asynchronous test zone. The test will automatically complete when all asynchronous calls within this zone are done. Can be used to wrap an inject call
Upvotes: 0