I am trying to write unit test for the login component below. This component has a constructor with @Inject. How do we test an angular component with @Inject in constructor? Can someone help? Thanks!
LoginComponent.ts
import { Component, Inject, OnInit } from '@angular/core';
import { OKTA_AUTH } from '@okta/okta-angular';
import { OktaAuth } from '@okta/okta-auth-js';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
isAuthenticated!: boolean;
userName?: string;
error?: Error;
constructor(@Inject(OKTA_AUTH) public oktaAuth: OktaAuth) {
}
async ngOnInit() {
this.isAuthenticated = await this.oktaAuth.isAuthenticated();
if (this.isAuthenticated) {
const userClaims = await this.oktaAuth.getUser();
this.userName = userClaims.name;
}
}
async login() {
try {
await this.oktaAuth.signInWithRedirect();
} catch (err: any) {
console.error(err);
this.error = err;
}
}
async logout() {
await this.oktaAuth.signOut();
}
}
LoginComponent.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { LoginComponent } from './login.component';
import { OktaAuth } from '@okta/okta-auth-js';
describe('LoginComponent', () => {
let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>;
let authService: OktaAuth;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [LoginComponent],
providers: [OktaAuth]
}).compileComponents();
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
authService = TestBed.inject(OktaAuth);
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Here is the error
Chrome Headless 114.0.5735.133 (Windows 10) LoginComponent should create FAILED
Error: NG0204: Can't resolve all parameters for OktaAuth: (?).
error properties: Object({ code: 204 }) at getUndecoratedInjectableFactory (node_modules/@angular/core/fesm2022/core.mjs:9227:15) at injectableDefOrInjectorDefFactory (node_modules/@angular/core/fesm2022/core.mjs:9217:16)
at providerToFactory (node_modules/@angular/core/fesm2022/core.mjs:9263:52)
at providerToRecord (node_modules/@angular/core/fesm2022/core.mjs:9247:25)
at R3Injector.processProvider (node_modules/@angular/core/fesm2022/core.mjs:9144:24)
at fn (node_modules/@angular/core/fesm2022/core.mjs:8975:59)
at forEachSingleProvider (node_modules/@angular/core/fesm2022/core.mjs:9318:13)
at forEachSingleProvider (node_modules/@angular/core/fesm2022/core.mjs:9315:13)
at new R3Injector (node_modules/@angular/core/fesm2022/core.mjs:8975:9)
at createInjectorWithoutInjectorInstances (node_modules/@angular/core/fesm2022/core.mjs:10591:12)
I must miss something. Please let me know what I am missing. Thanks in advance.
tried to import both import { OKTA_AUTH } from '@okta/okta-angular'; import { OktaAuth } from '@okta/okta-auth-js';
This is where I ended up finding the answer: https://github.com/okta-samples/okta-angular-quickstart/blob/main/src/app/app.component.spec.ts
...
import { OktaAuthStateService, OKTA_AUTH } from '@okta/okta-angular';
describe('AppComponent', () => {
const authStateSpy = jasmine.createSpyObj('OktaAuthStateService', [], {
authState$: of({
isAuthenticated: false
})
});
const authSpy = jasmine.createSpyObj('OktaAuth', ['login']);
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
providers: [
{ provide: OktaAuthStateService, useValue: authStateSpy },
{ provide: OKTA_AUTH, useValue: authSpy } // <-- see how you can provide the token, but provide your own stub/mock?
]
}).compileComponents();
});