How to inject HTTP in jasmine with a real connection - unit-testing

How to realize a jasmine test using http injection with a real backend?
I means that I would like to test my service using a real http connection
import { provide } from '#angular/core';
import{ClassCall} from 'xx.xx'
import {HTTP_PROVIDERS, XHRBackend, Http} from "#angular/http";
import {MockBackend} from "#angular/http/testing/mock_backend";
import {beforeEachProviders} from "#angular/core/testing/testing";
import {inject} from "#angular/core/testing/test_injector";
import {async} from "#angular/core/testing/async";
describe('HttpService Tests', () => {
beforeEachProviders(() => {
return [
HTTP_PROVIDERS,
Http,
ClassCall,
provide(ClassCall, {useClass: Http}),
];
})
it('should return response when subscribed to postRequest',
async(inject([ClassCall], (myCall: ClassCall) => {
myCall.Call("hey", "there")
.then((response)=>{
expect(response).toBe("anyResponse")
})
})));
});
I have not seen any topics about it....
Many thanks!!!!!

Since RC.5 you must use TestBed.configureTestingModule to configure your modules.
So in your test case in beforeEachProviders you must use it eg:
class HttpMock {
post(url, content, requestOptions) {
return {
toPromise() {
return Promise.resolve(url);
}
}
}
}
describe('HttpService Tests', () => {
let countryMock = new CountryMock();
let navigationMock = new NavigationServiceMock();
let httpMock = new HttpMock();
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
{provide: Http, useValue: httpMock},
{provide: CountryService, useValue: countryMock},
{provide: NavigationService, useValue: navigationMock},
AuthService
]
});
});
it('should check canActivate and set country de/login', inject([AuthService], (auth: AuthService) => {
expect(auth).toBeTruthy();
spyOn(countryMock, "getCountry").and.returnValue({code: 'de'});
spyOn(auth, "isLoggedIn").and.returnValue(false);
spyOn(navigationMock, "navigateByUrl").and.callThrough();
expect(auth.canActivate()).toBeFalsy();
expect(auth.isLoggedIn).toHaveBeenCalled();
expect(navigationMock.navigateByUrl).toHaveBeenCalledWith('de/login');
}));
});

EDIT: in rc.4 you need to use addProviders
Live example https://plnkr.co/edit/XhIkgR92oHRH4rIotXCj?p=preview
import {addProviders, inject} from '#angular/core/testing';
import {MyService} from './myservice';
describe('my code', () => {
beforeEach(() => {
addProviders([MyService]);
});
it('does stuff', inject([MyService], (service) => {
// actual test
}));
});

As igorzg says the correct way in rc4 is to do
beforeEach(() => {
addProviders([MyService, Http, ConnectionBackend, HTTP_PROVIDERS, XHRBackend]);
});

Related

Angular2 service testing : inject a dependency with beforeEach

I am testing services with an Http dependency. Every test looks like this :
import { TestBed, async, inject } from '#angular/core/testing';
import { ValidationService } from './validation.service';
import { HttpModule, Http, Response, ResponseOptions, RequestOptions, Headers, XHRBackend } from '#angular/http';
import { MockBackend, MockConnection } from '#angular/http/testing';
describe('DashboardService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpModule],
providers: [
ValidationService,
{ provide: XHRBackend, useClass: MockBackend }
]
});
});
it('should ...',
inject([ValidationService, XHRBackend],
(service: ValidationService, mockBackEnd: MockBackend) => {
mockBackEnd.connections.subscribe((connection: MockConnection) => {
connection.mockRespond(new Response(new ResponseOptions({
body: JSON.stringify('content')
})));
});
}));
// assertions ...
});
As you can see, I need to inject the BackEnd mock at every it.
Is it possible to use a beforeEach to inject the dependency before every test ?
Is it possible to use a beforeEach to inject the dependency before every test ?
Sure you could.
let service;
beforeEach(inject([Service], (svc) => {
service = svc;
}))
Though you could also just get the service from the TestBed, which is also an injector
let service;
beforeEach(() => {
TestBed.configureTestingModule({
...
})
service = TestBed.get(Service);
})

Angular 2 Observable Service Karma Jasmine Unit Test not working

I am a newbie to Angular 2 and Karma + Jasmine unit tests. I cannot figure out what semantic error I have made in order to make this unit test use the mocked response. In the console, when "expect(items[0].itemId).toBe(2);" is run, it says items[0].itemId is undefined.
Would someone be able to help me out or point me in the right direction? Please let me know if you need any additional information. Thanks!
item.ts
export class Item {
itemId: number;
itemName: string;
itemDescription: string;
}
item.service.ts
import { Injectable, Inject } from '#angular/core';
import { Headers, Http } from '#angular/http';
import { Observable } from 'rxjs/Rx';
import { Item } from './item';
#Injectable()
export class ItemService {
private headers = new Headers({'Content-Type': 'application/json'});
constructor(
private http: Http)
{
}
getItems(listOptions: Object): Observable<Item[]> {
return this.http.post('/listItems', listOptions, {headers:this.headers})
.map(response => response.json() as Item[])
}
}
item.service.spec.ts
import { TestBed, fakeAsync, inject, tick } from '#angular/core/testing';
import { MockBackend } from '#angular/http/testing';
import { Http, BaseRequestOptions, Response, ResponseOptions } from '#angular/http';
import { Observable } from 'rxjs/Rx';
import { ItemService } from './item.service';
import { Item } from './item';
describe('ItemService', () => {
let mockResponse, matchingItem, connection;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
ItemService,
MockBackend,
BaseRequestOptions,
{
provide: Http,
useFactory: (backend, defaultOptions) => new Http(backend, defaultOptions),
deps: [MockBackend, BaseRequestOptions]
},
// { provide: XHRBackend, useClass: MockBackend }
]
});
const items = [
{
"itemId":2,
"itemName":"test item1",
"itemDescription":"hello hello"
},
{
"itemId":1,
"itemName":"name2124111121",
"itemDescription":"description212412112"
}
];
mockResponse = new Response(new ResponseOptions({body: {data: items}, status: 200}));
});
describe('getItems', () => {
//Subscribing to the connection and storing it for later
it('should return all the items',inject([ItemService, MockBackend], (service: ItemService, backend: MockBackend) => {
backend.connections.subscribe(connection => {
connection.mockRespond(mockResponse);
});
service.getItems({isActive: true, sortColumn: "lastModifiedDateUtc", sortOrder: "desc"})
.subscribe((items: Item[]) => {
expect(items.length).toBe(2);
});
}));
});
});
Plunkr: https://plnkr.co/edit/m7In2eVh6oXu8VNYFf9l?p=preview
(There are some errors with the Plunkr I need help with as well but the main files are there)
The mockResponse body did not match the actual response body, that is why I was getting the error.
mockResponse = new Response(new ResponseOptions({body: {data: items}, status: 200})); should be mockResponse = new Response(new ResponseOptions({body: items, status: 200}));

mockRespond method inside beforeEach invokes later than XHR to backend inside test

I am trying to write Jasmine tests using MockBackend from Angular2.
Here is the code that I write to test a service which communicate with backend:
import { inject, TestBed } from '#angular/core/testing';
import {VehicleCategoryService} from './VehicleCategoryService';
import { BaseRequestOptions, Response, ResponseOptions, Http } from '#angular/http';
import { MockBackend, MockConnection } from '#angular/http/testing';
import {HttpService} from "../../api/HttpService";
import {ApplicationService} from "../../api/ApplicationService";
describe('VehicleCategoryService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [VehicleCategoryService,BaseRequestOptions, MockBackend, ApplicationService, {
provide: HttpService,
useFactory: (backend, options, applicationService) => {
return new HttpService(backend, options, applicationService);
},
deps: [MockBackend, BaseRequestOptions, ApplicationService],
}],
});
});
beforeEach(inject([MockBackend], (backend: MockBackend) => {
const baseResponse = new Response(new ResponseOptions({ body: '{"Name":"MiniVan"}' }));
backend.connections.subscribe((c: MockConnection) => c.mockRespond(baseResponse));
}));
it('should be defined', inject([VehicleCategoryService], (vehicleCategoryService: VehicleCategoryService) => {
expect(vehicleCategoryService).toBeDefined();
}));
it('should return response when querying vehicleCategories', inject([VehicleCategoryService], (vehicleCategoryService: VehicleCategoryService) => {
vehicleCategoryService.query().subscribe((res: Response) => {
expect(res['Name']).toBe('MiniVan');
});
}));
});
http://stackoverflow.com/questions/ask#
HttpService here is a service that extends from built-in Http Angular2 service. query() method returns Observable as a usual Http do.
Debugging issue demonstarte that mockRespond() method inside subscription invokes later than actual call to backend that is why I receive undefined response. How can I solve this problem?

UnitTest Mock Http response in Angular2 (2.1.0) Service

I am very confused by the different sources online about testing Angular2, mainly due to differences in versions. I am using Angular 2.1.0 final and I don't understand how to mock a simple http response for my service test class below:
import { TestBed, async, inject } from '#angular/core/testing';
import { PersonService } from '../services/person.service';
import { Person} from '../models/Person';
import { MOCK_DATA_PERSON } from '../test/mocks/mock-data-person';
// HTTP mocking imports
import { Http, BaseRequestOptions, Response, HttpModule, ResponseOptions } from '#angular/http';
import { MockBackend, MockConnection } from '#angular/http/testing';
describe('PersonService', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
providers: [
PersonService,
MockBackend,
BaseRequestOptions,
{
provide: Http,
useFactory: (backend: MockBackend, options: BaseRequestOptions) => {
return new Http(backend, options);
},
deps: [MockBackend, BaseRequestOptions],
}
],
imports: [
HttpModule
]
});
TestBed.compileComponents();
}));
it('returns a list of persons', async(inject([MockBackend, PersonService], (backend: MockBackend, service) => {
backend.connections.subscribe(
(connection: MockConnection) => {
connection.mockRespond(new Response(
new ResponseOptions({
body: JSON.stringify({name: "Bob", surname : "Jones"})
})));
});
service.getPersons()
.subscribe(persons=> {
expect(persons.length).toBeDefined();
expect(persons.length).toBe(1);
}).catch(error => console.log(error));
})));
});
given the getPersons method looks like:
getPersons (): Observable<Person[]> {
return this.http.get(this.getAllUrl)
.map(res.json().data)
.catch(this.handleError);
}
i am getting the error "Failed: this.http.get(...).map is not a function"
Test is good, but the Observable.map operator isn't found. Try to just import it
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';

How to use MockBackend in Angular2

I have this service I need to test:
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
#Injectable()
export class LoginService {
private baseUrl: string = 'http://localhost:4000/';
constructor (private http: Http) {}
public getBaseUrl() {
return this.baseUrl;
}
getLogin() {
return this.http.get(this.baseUrl + 'api/auth/octopus')
.map(res => res.json().redirect);
}
}
To test the getLogin() function I have this code:
import {
async,
describe,
it,
expect,
beforeEach,
addProviders,
inject
} from '#angular/core/testing';
import { provide} from '#angular/core';
import { LoginService } from './login.service';
import {
Http,
BaseRequestOptions,
} from '#angular/http';
import {MockBackend} from '#angular/http/testing';
describe('Service: LoginService', () => {
beforeEach(() => addProviders([
LoginService,
BaseRequestOptions,
MockBackend,
provide(Http, {
useFactory: (backend: MockBackend, defaultOptions: BaseRequestOptions) => {
return new Http(backend, defaultOptions);
},
deps: [MockBackend, BaseRequestOptions]
})
]));
it('should return data.',
async(inject([LoginService], (loginService: LoginService) => {
loginService.getLogin().subscribe(
data => console.log(data)
);
})
));
});
However, the data doesn't get logged.
I tried various solutions that I found on SO or on the internet.
One of them was to make a http call to the mockbackend but that just gave me data = undefined.
You need to inject MockBackend and subscribe for connection, like this:
UPDATE
async(inject([LoginService, MockBackend], (loginService: LoginService, mockBackend:MockBackend) => {
let mockResponse = new Response(new ResponseOptions({body: {'redirect': 'some string'}}))
mockBackend.connections.subscribe(c => c.mockRespond(mockResponse));
loginService.getLogin().subscribe(
data => console.log(data)
);
})
For more details go here:
https://angular.io/docs/ts/latest/api/http/testing/index/MockBackend-class.html