I'm trying to cover my service call in the component with test case as described below.
But getting error while running ng test as shown below:
Failed: this.monthService.getMonthView(...).then is not a function
TypeError: this.monthService.getMonthView(...).then is not a function
Service: (MonthService.ts)
getMonthView is the service call inside MonthService
getMonthView(forecastMonth: string): Promise<any[]> {
const options = new RequestOptions({ headers: this.headers });
const url = this.BaseUrl + forecastMonth;
return this.http.get(url, options)
.toPromise()
.then(response => response.json() as any[])
.catch(this.handleError);
}
Component: (MonthComponent.ts)
MonthService is imported and injected into MonthComponent.ts
loadDataOnMonthViewClicked(forecastMonth) {
this.monthService.getMonthView(forecastMonth)
.then(response =>
this.result = response
);
}
Test Suite :
beforeEach(() => {
/**
* Ref:https://angular.io/guide/testing#!#component-fixture
*/
fixture = TestBed.createComponent(MonthComponent);
component = fixture.componentInstance;
myService = TestBed.get(MonthService );
//fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
fit('should test loadDataOnMonthViewClick', async(() => {
let data=["10","20","30"];
spyOn(component.monthService, 'getMonthView').and.returnValue(result);
component.loadDataOnMonthViewClicked('Jan');
fixture.detectChanges();
expect(component.result).toBe(data);
}));
Here's what I did to make it work.
// the component
import { Component, OnInit } from "#angular/core";
import { MonthService } from "./month.service";
#Component({
selector: "app-root",
template: "",
})
export class AppComponent {
result = undefined;
constructor(private monthService: MonthService) { }
loadDataOnMonthViewClicked(forecastMonth) {
this.monthService
.getMonthView(forecastMonth)
.then(response => (this.result = response));
}
}
and the service
// the service
import { Injectable } from "#angular/core";
import { Http } from "#angular/http";
import "rxjs/add/operator/toPromise";
#Injectable()
export class MonthService {
constructor(private http: Http) { }
getMonthView(_forecastMonth: string) {
return this.http
.get("http://jsonplaceholder.typicode.com/posts/1")
.toPromise()
.then(response => response.json())
.catch(console.error);
}
}
and the test
import { TestBed, async, ComponentFixture } from "#angular/core/testing";
import { AppComponent } from "./app.component";
import { MonthService } from "./month.service";
import { HttpModule } from "#angular/http";
import { Observable } from "rxjs/Observable";
import "rxjs/add/observable/of";
describe("AppComponent", () => {
let fixture: ComponentFixture<AppComponent>;
let component: AppComponent;
let myService;
beforeEach(
async(() => {
TestBed.configureTestingModule({
providers: [MonthService],
declarations: [AppComponent],
imports: [HttpModule],
}).compileComponents();
}),
);
beforeEach(() => {
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
myService = fixture.debugElement.injector.get(MonthService);
fixture.detectChanges();
});
it(
"should test loadDataOnMonthViewClick",
async(() => {
let data = ["10", "20", "30"];
spyOn(myService, "getMonthView").and.callFake(() =>
Promise.resolve(data),
);
component.loadDataOnMonthViewClicked("Jan");
fixture.whenStable().then(() => {
expect(component.result).toBe(data);
});
}),
);
});
But I suggest to mock the service altogether, with something like
providers: [
{ provide: FetchDataService, useClass: FetchDataServiceMock }
],
Related
This is my code in angular, the functionality is working all fine but the test cases are getting failed. Please tell me what i am doing wrong in the code?
The error I am getting
HeadlessChrome 83.0.4103 (Windows 10.0.0) AboutComponent should create FAILED
TypeError: Cannot read property 'getAboutInfo' of undefined
at **
at AboutComponent.ngOnInit (http://localhost:9876/karma_webpack/src/app/about/about.component.ts:44:28)
at callHook (http://localhost:9876/karma_webpack/node_modules/#angular/core/ivy_ngcc/fesm2015/core.js:3937:1)
at callHooks (http://localhost:9876/karma_webpack/node_modules/#angular/core/ivy_ngcc/fesm2015/core.js:3901:1)
at executeInitAndCheckHooks (http://localhost:9876/karma_webpack/node_modules/#angular/core/ivy_ngcc/fesm2015/core.js:3842:1)
at refreshView (http://localhost:9876/karma_webpack/node_modules/#angular/core/ivy_ngcc/fesm2015/core.js:11795:1)
at renderComponentOrTemplate (http://localhost:9876/karma_webpack/node_modules/#angular/core/ivy_ngcc/fesm2015/core.js:11903:1)
at tickRootContext (http://localhost:9876/karma_webpack/node_modules/#angular/core/ivy_ngcc/fesm2015/core.js:13379:1)
at detectChangesInRootView (http://localhost:9876/karma_webpack/node_modules/#angular/core/ivy_ngcc/fesm2015/core.js:13413:1)
at RootViewRef.detectChanges (http://localhost:9876/karma_webpack/node_modules/#angular/core/ivy_ngcc/fesm2015/core.js:15093:22)
at ComponentFixture._tick (http://localhost:9876/karma_webpack/node_modules/#angular/core/ivy_ngcc/fesm2015/testing.js:323:1)
import { async, ComponentFixture, TestBed} from '#angular/core/testing';
import { AboutComponent } from './about.component';
import { AboutService } from './about.service';
import { HttpClientTestingModule, HttpTestingController } from '#angular/common/http/testing';
import { Observable, of } from 'rxjs';
import { I18nService } from 'src/utils/i18n.service';
import { MatDialogRef, MAT_DIALOG_DATA } from '#angular/material/dialog';
import { AppModule } from './../app.module';
describe('AboutComponent', () => {
let component: AboutComponent;
let fixture: ComponentFixture<AboutComponent>;
let dialogSpy: jasmine.Spy;
let app: any;
const mockDialogRef = {
close: jasmine.createSpy('close')
};
let service: any;
const data = '20/04/2019';
let getAboutInfoSpy: any;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [AboutComponent],
imports: [HttpClientTestingModule , AppModule],
providers: [{ provide: AboutService, useValue: service },
I18nService,
{ provide: MAT_DIALOG_DATA, useValue: {} },
{ provide: MatDialogRef, useValue: mockDialogRef}]
}).compileComponents();
}));
beforeEach(async () => {
fixture = TestBed.createComponent(AboutComponent);
component = fixture.componentInstance;
await fixture.whenStable();
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('infoList should be empty array', () => {
expect(app['dataList'].length).toBe(0);
});
it('when OnInit invoked through service data will return to infoList ', async(() => {
service = fixture.debugElement.injector.get(AboutService);
spyOn(service, 'getAboutInfo').and.returnValue(of(data));
app.ngOnInit();
expect(app['dataList'].length).toBe(3);
}));
it('onCancel should close the dialog', async( () => {
component.closePopup();
expect(mockDialogRef.close).toHaveBeenCalled();
}));
});
import { Component, OnInit, Inject } from '#angular/core';
import { AboutService } from './about.service';
import { Subscription } from 'rxjs';
import { MatDialogRef} from '#angular/material/dialog';
import { I18nService } from 'src/utils/i18n.service';
#Component({
selector: 'app-about',
templateUrl: './about.component.html',
styleUrls: ['./about.component.scss']
})
export class AboutComponent implements OnInit {
private aboutServiceSubscription: Subscription;
dataList: any;
locales: any = {};
translator: any;
constructor(
private dialogRef: MatDialogRef<AboutComponent>,
public aboutService: AboutService,
private i18Service: I18nService) {}
ngOnInit() {
this.translator = this.i18Service.getTranslator();
this.translator.translateObject.subscribe((item: any) => {
this.locales = item;
});
this.aboutServiceSubscription = this.aboutService.getAboutInfo().subscribe((data: any) => {
if (data) {
data = data.split('/');
this.dataList = data;
}
});
}
/**
* Closes the poup
* #memberof AboutComponent
*/
closePopup() {
this.dialogRef.close();
}
}
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class AboutService {
constructor(private http: HttpClient) {
}
getAboutInfo() {
return this.http.get('/assets/aboutInfo.txt', {responseType: 'text'})
}
}
The error message indicates that you did not mock AboutService correctly, you passed an undefined to useValue, so the AboutService obtained through the Injector is undefined. You can't use spyOn to a undefined value.
Here is a working example, with irrelevant code removed:
about.component.ts:
import { Component, OnInit } from '#angular/core';
import { AboutService } from './about.service';
import { Subscription } from 'rxjs';
#Component({
selector: 'app-about',
})
export class AboutComponent implements OnInit {
private aboutServiceSubscription: Subscription;
dataList: any;
locales: any = {};
translator: any;
constructor(public aboutService: AboutService) {}
ngOnInit() {
this.aboutServiceSubscription = this.aboutService
.getAboutInfo()
.subscribe((data: any) => {
if (data) {
data = data.split('/');
this.dataList = data;
}
});
}
}
about.service.ts:
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root',
})
export class AboutService {
constructor(private http: HttpClient) {}
getAboutInfo() {
return this.http.get('/assets/aboutInfo.txt', { responseType: 'text' });
}
}
about.component.spec.ts:
import { HttpClientTestingModule } from '#angular/common/http/testing';
import { ComponentFixture, TestBed } from '#angular/core/testing';
import { of } from 'rxjs';
import { AboutComponent } from './about.component';
import { AboutService } from './about.service';
fdescribe('62700708', () => {
let component: AboutComponent;
let fixture: ComponentFixture<AboutComponent>;
let aboutServiceSpy: jasmine.SpyObj<AboutService>;
const data = '20/04/2019';
beforeEach(() => {
aboutServiceSpy = jasmine.createSpyObj('AboutService', ['getAboutInfo']);
aboutServiceSpy.getAboutInfo.and.returnValue(of(data));
TestBed.configureTestingModule({
declarations: [AboutComponent],
imports: [HttpClientTestingModule],
providers: [{ provide: AboutService, useValue: aboutServiceSpy }],
}).compileComponents();
});
beforeEach(async () => {
fixture = TestBed.createComponent(AboutComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('when OnInit invoked through service data will return to infoList ', () => {
expect(aboutServiceSpy.getAboutInfo).toHaveBeenCalledTimes(1);
expect(component.dataList).toEqual(['20', '04', '2019']);
});
});
unit test result:
can anyone help me please? I'm trying to test a function that call a firebase functions, but when I call the main function and start to run a firebase functions, I got a error
err TypeError: Cannot read property 'emailPasswordLoginAsPromise' of null
i don't know what is happen, follow my code:
fdescribe('UserLoginContentComponent', () => {
let component: UserLoginContentComponent;
let fixture: ComponentFixture<UserLoginContentComponent>;
let loginComponent = new UserLoginContentComponent(null,null,null,null,null,null,null);
beforeAll(
async(() => {
TestBed.configureTestingModule({
imports: [
SharedModule,
AngularFireModule.initializeApp(environment.firebase),
RouterTestingModule,
BrowserAnimationsModule
],
declarations: [UserLoginContentComponent],
providers: [
AuthService,
AngularFireAuth,
AngularFirestore,
LogService,
LogPublishersService,
HttpClient,
HttpHandler
]
}).compileComponents();
fixture = TestBed.createComponent(UserLoginContentComponent);
component = fixture.componentInstance;
fixture.detectChanges();
spyOn(loginComponent, 'onSubmit').and.callThrough();
loginComponent.loginModel.email = 'correct email';
loginComponent.loginModel.password = 'correct password';
})
);
it('component should be create', () => {
expect(component).toBeTruthy();
});
it('Correct login',function(){
loginComponent.onSubmit().then((x) => {
console.log('ok:',x)
//expect something ..
}).catch((err) => {
console.log('err',err)
})
});
});
my Function that I'm calling:
onSubmit() {
//i'm setting my loginModel in the test with email and password
console.log('this.loginModel',this.loginModel)
return new Promise((res,rej) => {
this.authService.emailPasswordLoginAsPromise(this.loginModel).then(userCredential => {
// do something..
this.authService.createOrUpdateUserDataFirestore(userCredential, null, avaliacaoChecklist, null, null).then(s =>
//updating my user or create one
}).catch(e => {
//catch if this doesn't update or create
});
});
res('login OK')
}).catch(e => {
//open a diaglog if happen something wrong...
rej('login Fail')
});
})
}
in my authService, my emailloginasPromise is like that :
emailPasswordLoginAsPromise(login) {
return new Promise((resolveEPL, rejectEPL) => {
this.angularFireAuth.auth.signInWithEmailAndPassword(login.email, login.password)
.then(credential => {
this.updateUserWithAuth(credential.user);
resolveEPL(credential.user);
}).catch(e => {
console.error('emailPasswordLogin', e);
rejectEPL(e);
});
});
}
it's my first time with testing jasmine, I studied, but i don't know how I can solve this problem, how call a async func and getting the return.
i founded the problem, follow the fix:
The authService isn't provide when i'm creating a stance of my class, so now i'm using the component:
component = fixture.componentInstance;
with this component now I'm calling my method and all providers is working.
Follow my describe:
import { ComponentFixture, TestBed } from '#angular/core/testing';
import { SharedModule } from '../../shared/shared.module';
import { UserLoginContentComponent } from './user-login-content.component';
import { AngularFireModule } from '#angular/fire';
import { environment } from 'src/environments/environment';
import { RouterTestingModule } from '#angular/router/testing';
import { AuthService } from 'src/app/core';
import { AngularFireAuth } from '#angular/fire/auth';
import { AngularFirestore } from '#angular/fire/firestore';
import { LogService } from 'src/app/shared/logger/log.service';
import { LogPublishersService } from 'src/app/shared/logger/log-publishers.service';
import { HttpClient, HttpHandler } from '#angular/common/http';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
fdescribe('UserLoginContentComponent', () => {
let component: UserLoginContentComponent;
let fixture: ComponentFixture<UserLoginContentComponent>;
beforeAll(function(){
TestBed.configureTestingModule({
imports: [
SharedModule,
AngularFireModule.initializeApp(environment.firebase),
RouterTestingModule,
BrowserAnimationsModule
],
declarations: [UserLoginContentComponent],
providers: [
AuthService,
AngularFireAuth,
AngularFirestore,
LogService,
LogPublishersService,
HttpClient,
HttpHandler
]
}).compileComponents();
fixture = TestBed.createComponent(UserLoginContentComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
});
and how to test this component?
I'm using the follow tests:
it('COrrect login',(async(done) => {
component.loginModel.email = 'correctemail#gmail.com';
component.loginModel.password = 'correctpassword';
await component.onSubmitTest().then((x) => {
expect(x).toBe('login OK');
});
done();
}));
it('Wrong login (email)',(async(done) => {
component.loginModel.email = 'wrongemail#gmail.com';
component.loginModel.password = 'correctpassword';
await component.onSubmitTest().then(() => {})
.catch((err) => {
expect(err).toBe('login Fail');
})
done();
}));
My class follow:
onSubmitTest() {
return new Promise((res,rej) => {
this.authService.emailPasswordLoginAsPromise(this.loginModel).then(() => {
res('login OK')
}).catch(e => {
rej('login Fail')
});
})
}
and my authService:
emailPasswordLoginAsPromise(login) {
return new Promise((resolveEPL, rejectEPL) => {
this.angularFireAuth.auth.signInWithEmailAndPassword(login.email, login.password)
.then(credential => {
resolveEPL(credential.user);
}).catch(e => {
rejectEPL(e);
});
});
}
And now all my testing is working with asynchronous method with firebase methods
I am trying to test component in angular .following thing I need to test
service function is called or not
how to mock the response
here is my code
https://stackblitz.com/edit/angular-testing-w9towo?file=app%2Fapp.component.spec.ts
spec.ts
import { ComponentFixture,TestBed, async,getTestBed } from '#angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '#angular/common/http/testing';
import { HttpClientModule, HttpClient } from '#angular/common/http';
import { AppComponent } from './app.component';
import { AppService } from './app.service';
describe('AppComponent', () => {
let fixture:ComponentFixture<AppComponent>,
component:AppComponent,
injector:TestBed,
service:AppService,
httpMock:HttpTestingController,
el:HTMLElement;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
declarations: [
AppComponent
],
providers: [ AppService ]
}).compileComponents();
}));
afterEach(() => {
//httpMock.verify();
});
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
// injector = getTestBed();
// service = injector.get(AppService);
// httpMock = injector.get(HttpTestingController);
spyOn('appService',getData);
describe('AppComponent onit test', () => {
it('should create the app', async(() => {
expect(true).toBe(true);
}));
it('should called appService getData method', async(() => {
expect(appService.getData).toHaveBeenCalled();
}));
})
});
getting error
cannot read property 'injector' of null
you can mock the service that way:
const mockPosts: Posts = {
userId: 10,
id: 10,
title: "post",
body: "post"};
class MockAppService extends AppService{
public getData() {
return Observable.of(mockPosts)
}
}
and use that mock class in your providers instead of the service
{ provide: AppService, useClass: MockAppService },
and add this:
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
appservice = TestBed.get(AppService); // this line
you can spyOn that service and return a value like this
spyOn(appservice , 'getData').and.returnValue("your value")
final file
import { ComponentFixture,TestBed, async,getTestBed } from '#angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '#angular/common/http/testing';
import { HttpClientModule, HttpClient } from '#angular/common/http';
import { AppComponent } from './app.component';
import { AppService } from './app.service';
import { Observable } from 'rxjs/Observable';
import { Posts } from './post.interface';
import 'rxjs/add/observable/of';
const mockPosts: Posts =
{userId: 10,
id: 10,
title: "post",
body: "post",};
class MockAppService extends AppService {
public getData(){
return Observable.of(mockPosts)
}
}
describe('AppComponent', () => {
let fixture:ComponentFixture<AppComponent>,
component:AppComponent,
injector:TestBed,
service:AppService,
httpMock:HttpTestingController,
el:HTMLElement;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
declarations: [
AppComponent
],
providers: [
{ provide: AppService, useClass: MockAppService }
]
}).compileComponents();
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
service = TestBed.get(AppService)
// injector = getTestBed();
// service = injector.get(AppService);
// httpMock = injector.get(HttpTestingController);
spyOn(service,'getData');
}));
afterEach(() => {
//httpMock.verify();
});
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
service = TestBed.get(AppService)
// injector = getTestBed();
// service = injector.get(AppService);
// httpMock = injector.get(HttpTestingController);
spyOn(service,'getData');
describe('AppComponent onit test', () => {
it('should create the app', async(() => {
expect(true).toBe(true);
}));
it('should called appService getData method', async(() => {
fixture.detectChanges();
expect(service.getData).toHaveBeenCalled();
}));
})
});
could you please tell me why I am getting this error Cannot read property 'getData' of undefined
I am trying to test my service when I try to run my test it gives me above error
here is my code
https://stackblitz.com/edit/angular-testing-w9towo?file=app%2Fapp.service.spec.ts
import { TestBed, ComponentFixture, async, inject } from '#angular/core/testing';
import {HttpClientTestingModule, HttpTestingController} from '#angular/common/http/testing';
import {Posts} from './post.interface';
import { AppService } from './app.service';
describe('AppService', () => {
let service:AppService,
httpMock:HttpTestingController;
beforeEach(() => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [AppService]
}).compileComponents();
service =TestBed.get(AppService);
httpMock =TestBed.get(HttpTestingController);
}));
afterEach(()=>{
httpMock.verify();
})
})
describe('Service is truty', () => {
it('should return an Observable<User[]>', () => {
const dummyUsers :Posts[]= [{
userId: 10,
id: 10,
title: 'post',
body: 'post'
}];
service.getData().subscribe(users => {
console.log(users)
expect(users.length).toBe(1);
expect(users).toEqual(dummyUsers);
});
const req= httpMock.expectOne('https://jsonplaceholder.typicode.com/posts')
expect(req.method).toBe('GET');
req.flush(dummyUsers);
});
})
})
After trying more I am getting Cannot read property 'getData' of undefined
Why do you use nested beforeEach() and compileComponents()? Your beforeEach() statement should look like this:
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [AppService]
});
service = TestBed.get(AppService);
httpMock = TestBed.get(HttpTestingController);
});
Try this:
import { TestBed, ComponentFixture, async, inject } from '#angular/core/testing';
import {HttpClientTestingModule, HttpTestingController} from '#angular/common/http/testing';
import {Posts} from './post.interface';
import {HttpModule} from '#angular/http';
import { AppService } from './app.service';
describe('AppService', () => {
let service:AppService,
httpMock:HttpTestingController;
let fixture;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule,
HttpModule],
providers: [
AppService
]
}).compileComponents().then( () => {
service = TestBed.get(AppService);
httpMock =TestBed.get(HttpTestingController);
})
}));
afterEach(()=>{
httpMock.verify();
})
describe('Service is truty', () => {
it('should return an Observable<User[]>', () => {
const dummyUsers :Posts[]= [{
userId: 10,
id: 10,
title: 'post',
body: 'post'
}];
service.getData().subscribe(users => {
console.log(users)
expect(users.length).toBe(1);
expect(users).toEqual(dummyUsers);
});
const req= httpMock.expectOne('https://jsonplaceholder.typicode.com/posts')
//expect(req.method).toBe('GET');
req.flush(dummyUsers);
});
})
})
Live Demo:
https://stackblitz.com/edit/angular-testing-oqrffm?file=app%2Fapp.service.spec.ts
In my Angular2 app which uses AngularFire2, I have an AuthService which tries to authenticate anonymously with Firebase.
I am trying to write a test that expects AngularFireAuth's signInAnonymously to return a rejected promise; for authState to be null and an error to be thrown.
I an new to Jasmine and testing in general but I think I may need to be using asynchronous tests but I'm getting quite stuck.
Here is a simplified AuthService:
import { Injectable } from '#angular/core';
import { AngularFireAuth } from 'angularfire2/auth';
import * as firebase from 'firebase/app';
import { Observable } from 'rxjs/Rx';
#Injectable()
export class AuthService {
private authState: firebase.User;
constructor(private afAuth: AngularFireAuth) { this.init(); }
private init (): void {
this.afAuth.authState.subscribe((authState: firebase.User) => {
if (authState === null) {
this.afAuth.auth.signInAnonymously()
.then((authState) => {
this.authState = authState;
})
.catch((error) => {
throw new Error(error.message);
});
} else {
this.authState = authState;
}
}, (error) => {
throw new Error(error.message);
});
}
}
And here are my test specs:
import { TestBed, inject } from '#angular/core/testing';
import { AngularFireAuth } from 'angularfire2/auth';
import 'rxjs/add/observable/of';
import { Observable } from 'rxjs/Rx';
import { AuthService } from './auth.service';
import { environment } from '../environments/environment';
describe('AuthService', () => {
const mockAngularFireAuth: any = {
auth: jasmine.createSpyObj('auth', {
'signInAnonymously': Promise.resolve('foo'),
// 'signInWithPopup': Promise.reject(),
// 'signOut': Promise.reject()
}),
authState: Observable.of(null)
};
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
{ provide: AngularFireAuth, useValue: mockAngularFireAuth },
{ provide: AuthService, useClass: AuthService }
]
});
});
it('should be created', inject([ AuthService ], (service: AuthService) => {
expect(service).toBeTruthy();
}));
//
//
//
//
//
describe('when we can’t authenticate', () => {
beforeEach(() => {
mockAngularFireAuth.auth.signInAnonymously.and.returnValue(Promise.reject('bar'));
});
it('should thow', inject([ AuthService ], (service: AuthService) => {
expect(mockAngularFireAuth.auth.signInAnonymously).toThrow();
}));
});
//
//
//
//
//
});
Thank you for your help!
It turns out I was mocking mockAngularFireAuth correctly. I needed to reject mockAngularFireAuth.auth signInAnonymously()'s promise with an error and expect it to be caught, a la:
import { TestBed, async, inject } from '#angular/core/testing';
import { AngularFireAuth } from 'angularfire2/auth';
import 'rxjs/add/observable/of';
import { Observable } from 'rxjs/Rx';
import { AuthService } from './auth.service';
import { MockUser} from './mock-user';
import { environment } from '../environments/environment';
describe('AuthService', () => {
// An anonymous user
const authState: MockUser = {
displayName: null,
isAnonymous: true,
uid: '17WvU2Vj58SnTz8v7EqyYYb0WRc2'
};
const mockAngularFireAuth: any = {
auth: jasmine.createSpyObj('auth', {
'signInAnonymously': Promise.reject({
code: 'auth/operation-not-allowed'
}),
// 'signInWithPopup': Promise.reject(),
// 'signOut': Promise.reject()
}),
authState: Observable.of(authState)
};
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
{ provide: AngularFireAuth, useValue: mockAngularFireAuth },
{ provide: AuthService, useClass: AuthService }
]
});
});
it('should be created', inject([ AuthService ], (service: AuthService) => {
expect(service).toBeTruthy();
}));
describe('can authenticate anonymously', () => {
describe('AngularFireAuth.auth.signInAnonymously()', () => {
it('should return a resolved promise', () => {
mockAngularFireAuth.auth.signInAnonymously()
.then((data: MockUser) => {
expect(data).toEqual(authState);
});
});
});
});
describe('can’t authenticate anonymously', () => {
describe('AngularFireAuth.auth.signInAnonymously()', () => {
it('should return a rejected promise', () => {
mockAngularFireAuth.auth.signInAnonymously()
.catch((error: { code: string }) => {
expect(error.code).toEqual('auth/operation-not-allowed');
});
});
});
});
…
});
I solved this problem by doing the following:
describe('should reject promise', () => {
let resolved: boolean;
let rejected: boolean;
let _e: any;
beforeEach(function (done) {
resolved = false;
rejected = false;
// ensure conditions here are such that myFn() should return a rejected promise
service.myFn().then(() => {
resolved = true;
done();
}).catch((e) => {
rejected = true;
_e = e;
done();
});
})
it('should reject', () => {
expect(resolved).toEqual(false);
expect(rejected).toEqual(true);
expect(_e.name).toEqual("MyCustomErrorName");
});
});