Reputation: 1839
I'm working through my test environment and am trying to get around an issue with a single user profile through oidc-client
being undefined during unit testing.
I have tried making the BeforeEach
methods async
that has not helped, and I have also tried restructuring my AuthService
as well.
This is the error that I am getting from the test components:
ResourcesCardComponent > should create
Failed: Cannot read property 'profile' of undefined
AuthService
import { Injectable } from '@angular/core';
import { UserManager, User, WebStorageStateStore } from 'oidc-client';
import { BehaviorSubject } from 'rxjs';
import { ConfigAssetLoaderService } from '../config-asset-loader.service';
@Injectable({
providedIn: 'root'
})
export class AuthService {
private _userManager: UserManager;
public _user: User;
public isLoggedInSubject$ = new BehaviorSubject<any>(this._user);
isLoggedIn = this.isLoggedInSubject$.asObservable();
constructor(private configService: ConfigAssetLoaderService) {
const config = {};
this.configService.loadConfiguration().subscribe(response => {
config['authority'] = response.authority;
config['client_id'] = response.client_id;
config['redirect_uri'] = response.redirect_uri;
config['scope'] = response.scope;
config['response_type'] = response.response_type;
config['loadUserInfo'] = response.loadUserInfo;
config['userStore'] = new WebStorageStateStore({store: window.sessionStorage});
config['metadata'] = {
issuer: response.issuer,
authorization_endpoint: response.authorization_endpoint,
userinfo_endpoint: response.userinfo_endpoint,
jwks_uri: response.jwks_uri,
end_session_endpoint: response.end_session_endpoint
};
config['signingKeys'] = response.signingKeys;
config['extraQueryParams'] = {
resource: response.claimsApiResourceId
};
this._userManager = new UserManager(config);
this._userManager.getUser().then(user => {
if (user && !user.expired) {
this._user = user;
this.isLoggedInSubject$.next(user);
}
});
});
}
}
The AuthService
is pretty standard, all the important pieces for this question are in the constructor.
The component in question using this service is the following:
import { Component, Input } from '@angular/core';
import { ActionLink } from '../../shared/models/actionlink';
import { AuthService } from '../../core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Component({
selector: 'thrive-resources-card',
templateUrl: './resources-card.component.html',
styleUrls: ['./resources-card.component.scss']
})
export class ResourcesCardComponent {
@Input() public actionLinks: ActionLink[];
public firstName$: Observable<string>;
constructor(private authService: AuthService) {
this.firstName$ = this.authService.isLoggedInSubject$.pipe(
map(response => response.profile.unique_name.replace(/\s+/, '').split(',')[1])
);
}
}
Here is the test component for the ResourceCardComponent
as well:
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ResourcesCardComponent } from './resources-card.component';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { ActivatedRoute, RouterModule } from '@angular/router';
import { ResourcesCardContainerComponent } from './resources-card-container/resources-card-container.component';
const fakeRoute = {
snapshot: {
data: {
actionLinks: []
}
}
};
describe('ResourcesCardComponent', () => {
let component: ResourcesCardComponent;
let fixture: ComponentFixture<ResourcesCardComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
ResourcesCardComponent,
ResourcesCardContainerComponent
],
imports: [
RouterModule,
HttpClientTestingModule
],
providers: [
{
provide: ActivatedRoute,
useFactory: () => fakeRoute
}
]
}).compileComponents();
}));
beforeEach(async(() => {
fixture = TestBed.createComponent(ResourcesCardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
component.actionLinks = [];
expect(component).toBeTruthy();
});
});
Upvotes: 0
Views: 858
Reputation: 6801
You initiate your service with
public isLoggedInSubject$ = new BehaviorSubject<any>(this._user)
because this._user
is undefined.
Then in your component, your want response.profile.unique_name.replace(/\s+/, '') ...
BUT this.authService.isLoggedInSubject$
return as first value undefined
. This is why you have this error.
You should either mock you service to return an observable of({profile:{unique_name:'some name'}})
Or initiate your user with better data.
spyOn(authService , 'isLoggedInSubject$').and.returnValue(of({profile:{unique_name:'some name'}}))
Upvotes: 1