Reputation: 989
I am trying to write a unit test for a component which has child components and are injected in using ng-content
. I am trying to get the queryList of components in my test so I can test this function below but can't seem to populate the QueryList
variable in my unit test.
@ContentChildren(TabsContentComponent, { descendants: true, read: TabsContentComponent }) tabContent: QueryList<TabsContentComponent>;
onTabChange($event) {
this.tabContent.toArray().forEach((tab, index) => {
tab.isActive = false;
if ($event.value === tab.value) {
tab.isActive = true;
}
});
}
Here is my components: I have a component called TabsContentContainer which holds another component called Tabs. Which looks like this:
<div class="flex flex-direction-column tabs-container">
<app-tabs (tabChange)='onTabChange($event)' [tabs]="tabs"></app-tabs>
<ng-content></ng-content>
How I use the TabsContentContainer
component I do this (This is just a mock version of it minus the app-tabs component):
<app-tabs-container>
<app-tabs-content>content goes here</app-tabs-content>
<app-tabs-content>content goes here</app-tabs-content>
<app-tabs-content>content goes here</app-tabs-content>
I have tried following another answer to figure out what to do as it is fairly old answer but I can't seem to get my mock component to return my QueryList
of app-tabs-content
.
Here is my spec file:
@Component({
selector: 'app-tabs-container-mock-component',
template: `<app-tabs-container>
<app-tabs-content></app-tabs-content>
<app-tabs-content></app-tabs-content>
<app-tabs-content></app-tabs-content>
</app-tabs-container>`
})
export class TabsContainerMockComponent { }
fdescribe('TabsContainerComponent', () => {
let component: TabsContainerComponent;
let component2: TabsContainerMockComponent;
console.log(component2);
let fixture: ComponentFixture<TabsContainerComponent>;
let fixture2: ComponentFixture<TabsContainerMockComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [TabsContainerComponent, TabsContainerMockComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TabsContainerComponent);
fixture2 = TestBed.createComponent(TabsContainerMockComponent);
console.log(fixture2);
component = fixture.componentInstance;
component2 = fixture2.componentInstance;
fixture.detectChanges();
fixture2.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
expect(component2).toBeTruthy();
});
it('should show the correct content when changing tabs', () => {
const container = fixture.debugElement.children[0].componentInstance;
debugger;
console.log(container);
});
What I have tried:
I have tried mocking my component and trying to access it but that didn't seem to work as I get an error complaining Component 'TabsContainerMockComponent' is not included in a module and will not be available inside a template. Consider adding it to a NgModule declaration
That led me to adding a mock NgModule
but that also didn't work and didn't seem right.
I am lost for what to try as I cant seem to get component.tabContent
to equal a QueryList
of app-tabs-content
.
Upvotes: 5
Views: 11337
Reputation: 8306
The issues is that right now your TabsContainerMockComponent
is actually a wrapper on top of your TabsContainerComponent
. In order to access your TabsContainerComponent
inside of your TabsContainerMockComponent
(which should probably be renamed to something like TestHostTabsContainerComponent
), you'll need to get a hold of the DebugElement
and one of it's children (probably the first child) will be your TabsContainerComponent
.
You'll need a variable at the top to hold your TabsContainerComponent
:
let tabsContainerComponent: TabsContainerComponent;
Do this in your beforeEach
:
tabsContainerComponent = fixture2.debugElement.children[0].componentInstance;
Then you can access your QueryList
as it is a public property on the TabsContainerComponent
:
tabsContainerComponent.tabContent
Read more about DebugElement
here: https://angular.io/api/core/DebugElement
Upvotes: 4