Reputation: 197
I am having issues mocking attachClickHandler function of gauth. The following is my code. I am unable to mock the attachClickHander onSuccess and onFailure callbacks. Thus, unable to test the prepareLoginButton method.
export class GoogleSignInButtonComponent implements OnInit {
auth2: any;
constructor(
private socialSignInController: SocialSignInControllerService,
private ngZone: NgZone,
private toastr: ToastrService,
private authenticationService: AuthenticationService) { }
ngOnInit(): void {
this.googleSDK();
}
googleSDK() {
window['googleSDKLoaded'] = () => {
window['gapi'].load('auth2', () => {
this.auth2 = window['gapi'].auth2.init({
client_id: environment.social.google.clientId,
cookiepolicy: 'single_host_origin',
scope: 'profile email'
});
this.prepareLoginButton();
});
}
(function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) { return; }
js = d.createElement(s); js.id = id;
js.src = "https://apis.google.com/js/platform.js?onload=googleSDKLoaded";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'google-jssdk'));
}
prepareLoginButton() {
this.auth2.attachClickHandler(document.getElementById('googleBtn'), {},
(googleUser) => {
this.ngZone.run(() => {
const token = googleUser.getAuthResponse().id_token;
this.socialSignInController.googleTokenSignIn(token).subscribe(res => {
this.authenticationService.onSocialLoginSuccess(res.token);
window.location.href = '/dashboard'
});
}, (error) => {
this.toastr.error('An error occurred. Please try again', 'Could not sign you in')
console.log(error);
});
})
}
}
Upvotes: 0
Views: 1154
Reputation: 197
The goal was to implement google sign in. And The code needed to be 100% tested. Since it was difficult mocking the auth2 attachClickHandler success function, I removed that and used a library angularx-social-login link to GitHub repo
I created a CustomHRefService, because router.navigate did not work, inside the promise then function. I later found that wrapping the promise to become Observable solved this.
The code and test is as follows:
The Button html
<a #googlebtn (click)="signInWithGoogle()" class="social_bt google" id="googleBtn">Login with google</a>
The Button Ts
import { Component, OnInit, Inject } from '@angular/core';
import { AuthService, GoogleLoginProvider } from 'angularx-social-login';
import { SocialSignInControllerService } from 'dd-core-api-sdk';
import { CustomHrefService } from 'src/app/services/custom-href.service';
@Component({
selector: 'app-google-btn',
templateUrl: './google-btn.component.html',
styleUrls: ['./google-btn.component.css'],
})
export class GoogleBtnComponent implements OnInit {
constructor(private authService: AuthService,
private socialSignInController: SocialSignInControllerService,
private authenticationService: AuthenticationService,
private customeHref: CustomHrefService
) { }
ngOnInit(): void {
}
signInWithGoogle(): void {
this.authService.signIn(GoogleLoginProvider.PROVIDER_ID).then(googleUser => {
this.socialSignInController.googleTokenSignIn({ token: googleUser.idToken }).subscribe(res => {
this.authenticationService.onSocialLoginSuccess(res.token);
this.customeHref.jumpTo('/dashboard')
})
})
}
}
The Button Test
import { async, ComponentFixture, TestBed, tick, fakeAsync } from '@angular/core/testing';
import { GoogleBtnComponent } from './google-btn.component';
import { provideConfig } from '../authentication.module';
import { AuthenticationServiceImpl } from 'src/app/services/authentication.service';
import { AuthService, AuthServiceConfig, SocialUser } from 'angularx-social-login';
import { of } from 'rxjs';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { ToastrModule } from 'ngx-toastr';
import { CustomHrefService } from 'src/app/services/custom-href.service';
import { WindowToken } from 'src/app/injector/window';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
const MockWindow = {
location: {
_href: '',
set href(url: string) { this._href = url },
get href() { return this._href }
}
};
describe('GoogleBtnComponent', () => {
let component: GoogleBtnComponent;
let fixture: ComponentFixture<GoogleBtnComponent>;
let authService: AuthService;
let socialSignInService: SocialSignInControllerService;
let socialSignInSpy: jasmine.Spy;
let authSpy: jasmine.Spy;
let service: CustomHrefService;
let setHrefSpy: jasmine.Spy;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule,
RouterTestingModule.withRoutes([{ path: 'dashboard', component: DummyComponent }]),
ToastrModule.forRoot(),
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useValue: new FakeLoader()
}
}),
],
declarations: [GoogleBtnComponent],
providers: [{
provide: AuthenticationService,
useClass: AuthenticationServiceImpl,
}, AuthService, { provide: AuthServiceConfig, useFactory: provideConfig },
{ provide: CustomHrefService, useClass: CustomHrefService, deps: [WindowToken]},
{ provide: WindowToken, useValue: MockWindow }]
})
.compileComponents();
}));
beforeEach(() => {
//mock response
socialSignInService = TestBed.get(SocialSignInControllerService);
service = TestBed.get(CustomHrefService);
authService = TestBed.get(AuthService);
socialSignInSpy = spyOn(socialSignInService, "googleTokenSignIn").and.returnValue(of({ token: '2323' } as any))
setHrefSpy = spyOnProperty(MockWindow.location, 'href', 'set');
const googleUser: SocialUser = {
name: 'godwin', firstName: 'ish',
lastName: 'dako', idToken: '1009',
provider: 'google',
id: '2', email: '[email protected]',
photoUrl: 'null',
authToken: '2323', authorizationCode: '232'
};
authSpy = spyOn(authService, 'signIn').and.returnValue(Promise.resolve(googleUser));
fixture = TestBed.createComponent(GoogleBtnComponent);
authService = TestBed.get(AuthService);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should sign with google', fakeAsync(() => {
component.signInWithGoogle();
fixture.detectChanges();
tick(3);
expect(setHrefSpy).toHaveBeenCalledWith('/dashboard');
}))
});
CustomHrefService
import { Injectable, Inject } from '@angular/core';
import { WindowToken } from '../injector/window';
@Injectable({
providedIn: 'root'
})
export class CustomHrefService {
constructor(@Inject(WindowToken) private window: Window) {}
jumpTo(url: string) {
this.window.location.href = url;
}}
WindowToken
import { InjectionToken } from '@angular/core';
export const WindowToken = new InjectionToken('Window');
export function windowProvider() { return window; }
Using the InjectionToken
@NgModule({
declarations: [
//components],
imports: [
//other modules
],
providers: [{
{ provide: WindowToken, useFactory: windowProvider }
]
})
export class AuthenticationModule { }
The CustomHrefService Test
import { TestBed } from '@angular/core/testing';
import { CustomHrefService } from './custom-href.service';
import { Injector } from '@angular/core';
import { WindowToken } from '../injector/window';
import { AuthenticationModule } from '../modules/authentication/authentication.module';
const MockWindow = {
location: {
_href: '',
set href(url: string) { this._href = url },
get href() { return this._href }
}
};
describe('CustomHrefService', () => {
let service: CustomHrefService;
let setHrefSpy: jasmine.Spy;
beforeEach(() => {
setHrefSpy = spyOnProperty(MockWindow.location, 'href', 'set');
const injector = Injector.create({
providers: [
{ provide: CustomHrefService, useClass: CustomHrefService, deps: [WindowToken]},
{ provide: WindowToken, useValue: MockWindow}
]
});
service = injector.get(CustomHrefService);
});
it('should be registered on the AppModule', () => {
service = TestBed.configureTestingModule({ imports: [AuthenticationModule] }).get(CustomHrefService);
expect(service).toEqual(jasmine.any(CustomHrefService));
});
describe('#jumpTo', () => {
it('should modify window.location.href', () => {
const url = 'http://localhost:8080';
service.jumpTo(url);
expect(setHrefSpy).toHaveBeenCalledWith(url);
});
});
});
Upvotes: 1