Reputation: 87
I recently started using Jasmine for testing a Angular application and, while most of the tests are working fine, I'm having trouble with a specific one.
So this is the test for the AppComponent, which looks like this:
app.component.ts
import { Component, OnDestroy } from '@angular/core';
import { Idle, DEFAULT_INTERRUPTSOURCES } from 'ng2-idle-core';
import { Store } from '@ngxs/store';
import { OAuthService, JwksValidationHandler } from 'angular-oauth2-oidc';
import {
authConfig,
LoginSuccess,
CriticalErrorHandler,
CriticalLogoutRequest } from './core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
idleState = 'Not started.';
timedOut = false;
lastPing?: Date = null;
// Important to keep the "CriticalErrorHandler" here, because it is an injectable "service" and must be
// instancied at the beginning of the app
constructor(
private idle: Idle,
private store: Store,
private criticalErrorHandler: CriticalErrorHandler,
private oauthService: OAuthService) {
// Idle time
this.idle.setIdle(3600);
this.idle.setTimeout(30);
this.idle.setInterrupts(DEFAULT_INTERRUPTSOURCES);
this.idle.onIdleStart.subscribe(() => {
this.store.dispatch(new CriticalLogoutRequest());
});
this.login();
}
private login() {
this.oauthService.configure(authConfig);
this.oauthService.tokenValidationHandler = new JwksValidationHandler();
this.oauthService.loadDiscoveryDocumentAndLogin({
onTokenReceived : () => {
this.oauthService.setupAutomaticSilentRefresh();
this.store.dispatch(new LoginSuccess());
}
});
}
}
As can be seen, the constructor calls the login() function, which in turn uses a config object called authConfig and that looks like this:
auth.config.ts
import { AuthConfig } from "angular-oauth2-oidc";
import { environment } from "environments/environment";
export const authConfig: AuthConfig = {
silentRefreshRedirectUri : window.location.origin + '/assets/silent-refresh.html',
issuer: environment.endpoints.identity,
redirectUri: window.location.origin + '/index.html',
clientId: 'ID',
scope: 'openid user permissions My.WebApp',
responseType: "id_token token",
requireHttps: environment.requireHttps,
sessionChecksEnabled : true
};
This calls another config object called environment, which has requireHttps set to true. So when I do a simple create test like this:
app.component.spec.ts
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { async, TestBed, ComponentFixture } from '@angular/core/testing';
import { RouterModule } from '@angular/router';
import { SharedModule } from 'primeng/primeng';
import { AppComponent } from './app.component';
import { CoreModule } from './core/core.module';
fdescribe('AppComponent', () => {
let component: AppComponent;
let fixture: ComponentFixture<AppComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
CoreModule,
SharedModule,
RouterModule.forRoot([])
],
declarations: [AppComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
}).compileComponents();
}));
it('should create the app', async(() => {
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
expect(component).toBeTruthy();
}));
});
I get a "issuer must use https, or config value for property requireHttps must allow http". So what I want to do is, for the scope of the test, change this requireHttps property in the config object to false. But I'm not really sure how to do this... any help is appreciated!
Upvotes: 0
Views: 2273
Reputation: 3511
What if you were to pass the AuthConfig
as an argument to your component's login()
instead? This will allow you to mock your AuthConfig
again in your unit test.
app.component.ts
import { authConfig } from './core';
...
this.login(authConfig);
...
private login(_authConfig:AuthConfig) {
this.oauthService.configure(_authConfig);
this.oauthService.tokenValidationHandler = new JwksValidationHandler();
this.oauthService.loadDiscoveryDocumentAndLogin({
onTokenReceived : () => {
this.oauthService.setupAutomaticSilentRefresh();
this.store.dispatch(new LoginSuccess());
}
});
}
And in your test suite, you will be mocking (creating a new instance of it for the sake of this test) the AuthConfig
object
app.component.spec.ts
beforeEach(() => async(() => {
...
let mockAuthConfig: AuthConfig;
...
}))
beforeEach(() => {
...
mockAuthConfig = {
silentRefreshRedirectUri : window.location.origin + '/assets/silent-refresh.html',
issuer: environment.endpoints.identity,
redirectUri: window.location.origin + '/index.html',
clientId: 'ID',
scope: 'openid user permissions My.WebApp',
responseType: "id_token token",
requireHttps: false, // <== CHANGED
sessionChecksEnabled : true
}
...
fixture.detectChanges();
})
...
it(`testing login()`, fakeAsync(() => {
component.login(mockAuthConfig);
//your tests here
//expect(...).toBe(...);
}))
Essentially, the invocation of login() in app.component.ts will use the authConfig
that you have predefined and exported out. However, in your unit test case, you will mock(recreate) a new AuthConfig
object that has different properties which you then pass into login()
via component.login(mockAuthConfig)
.
Hope this works for you!
Upvotes: 1