I'm creating my own angular bootstrap library, and at the moment I'm stuck writing my unit tests for the navbar.
I've distilled the troubled unit test down to the bare essentials and below is the summary:
Unit test
describe('BsNavbarDropdownComponent', () => {
let component: BsNavbarDropdownTestComponent;
let fixture: ComponentFixture<BsNavbarDropdownTestComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
RouterTestingModule.withRoutes([])
],
declarations: [
// Component to test
BsNavbarDropdownComponent,
// Mock components
BsNavbarItemMockComponent,
// Testbench
BsNavbarDropdownTestComponent
],
providers: [
{ provide: BsNavbarItemComponent, useClass: BsNavbarItemMockComponent }
]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(BsNavbarDropdownTestComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@Component({
selector: 'bs-navbar-test',
template: `
<bs-navbar-item>
<a [routerLink]='[]'>dropdown</a>
<bs-navbar-dropdown>
<bs-navbar-item>
<a [routerLink]='["/b", "c"]'>bc</a>
</bs-navbar-item>
</bs-navbar-dropdown>
</bs-navbar-item>`
})
class BsNavbarDropdownTestComponent {
}
@Component({
selector: 'bs-navbar-item',
template: `
<li>
<ng-content></ng-content>
</li>`
})
class BsNavbarItemMockComponent {
}
Unit-to-test
@Component({
selector: 'bs-navbar-dropdown',
templateUrl: './navbar-dropdown.component.html',
styleUrls: ['./navbar-dropdown.component.scss']
})
export class BsNavbarDropdownComponent {
constructor(
@Host() @Inject(forwardRef(() => BsNavbarItemComponent)) navbarItem: BsNavbarItemComponent
) {
this.navbarItem = navbarItem;
}
navbarItem: BsNavbarItemComponent;
}
In the BsNavbarDropdownTestComponent
it's blindly obvious that the bs-navbar-dropdown
(BsNavbarDropdownComponent
) has a parent tag bs-navbar-item
(BsNavbarItemMockComponent
). In the unit-to-test I'm injecting the BsNavbarItemComponent
, which is in the testing module provided as BsNavbarItemMockComponent
.
However it seems like the unit test is still not succeeding.
npm run nx run-many -- --target=test --projects=ng-bootstrap-demo --with-deps --watch=false --browsers=ChromeHeadless
Result:
FAIL xxx-ng-bootstrap libs/xxx-ng-bootstrap/src/lib/components/navbar/navbar-dropdown/navbar-dropdown.component.spec.ts
● BsNavbarDropdownComponent › should create
NG0201: No provider for BsNavbarItemComponent found in NodeInjector. Find more at https://angular.io/errors/NG0201
Again, note that the module has the following providers:
providers: [
{ provide: BsNavbarItemComponent, useClass: BsNavbarItemMockComponent }
]
So what's wrong with this? Why is the BsNavbarItemComponent
provider not found in the unit test?
CodePudding user response:
module provider is not being injected because of @Host
annotation on the injection.
so your mock component should be injectable by the original component token
@Component({
selector: 'bs-navbar-item',
template: `
<li>
<ng-content></ng-content>
</li>`,
providers: [provide: BsNavbarItemComponent, useExisting: forwardRef(() => BsNavbarItemMockComponent)]
})
class BsNavbarItemMockComponent {
}