I have created angular 2 a project and a service with angular-cli and tried to test my service.
But API does not fail in async function although it should fail ;moreover, it just ignores those exceptions.
/* tslint:disable:no-unused-variable */
import {
beforeEach, beforeEachProviders, describe, xdescribe,
expect, it, xit, async, inject, injectAsync
} from '#angular/core/testing';
import { SearchService } from './search.service';
import {provide} from '#angular/core';
import {MockBackend, MockConnection} from '#angular/http/testing';
import {XHRBackend, Response, ResponseOptions, HTTP_PROVIDERS} from '#angular/http';
describe('Search Service', () => {
let searchService: SearchService;
let mockBackend: MockBackend;
beforeEachProviders(() => [
HTTP_PROVIDERS,
MockBackend,
provide(XHRBackend, { useClass: MockBackend }),
SearchService
]);
beforeEach(injectAsync([SearchService, MockBackend], (s, m) => {
searchService = s;
mockBackend = m;
}));
it('async test', () => {
setTimeout(() => {
expect(2).toBe(1);
}, 3000);
});
It just ignores those minimal test case.
Then I have read some doc and updated my code as follow.
it('async test with done', (done) => {
setTimeout(() => {
expect(1).toBe(1);
done();
}, 1000);
});
But this time, the test fails although it should pass. The error is as follow.
Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
I change default timeout value to bigger value but it is no effect.
injectAsync will not work, use async (stopped working for me after rc2)
angular2 change log beta 16
injectAsync is now deprecated. Instead, use the async function to wrap any asynchronous tests.
You will also need to add the dependency 'node_modules/zone.js/dist/async-test.js' as a served file in your Karma or other test configuration.
Before:
it('should wait for returned promises', injectAsync([FancyService], (service) => {
return service.getAsyncValue().then((value) => { expect(value).toEqual('async value'); });
}));
it('should wait for returned promises', injectAsync([], () => {
return somePromise.then(() => { expect(true).toEqual(true); });
}));
After:
it('should wait for returned promises', async(inject([FancyService], (service) => {
service.getAsyncValue().then((value) => { expect(value).toEqual('async value'); });
})));
// Note that if there is no injection, we no longer need `inject` OR `injectAsync`.
it('should wait for returned promises', async(() => {
somePromise.then(() => { expect(true).toEqual(true); });
}));
Related
In my React Redux app, I tried to do some tests to one of my function that has settimeout in it
// MyFunc.js
export function updateSomething(id, data) {
return (dispatch, getState) => {
dispatch({type: 'dispatch1'})
settimeout(() => {
axios.get('/data')
.then((res) => {
dispatch({type: 'timeoutted_dispatch', data: res.data})
})
.catch(error => {
dispatch({type: 'dispatch_error'});
})
},3000);
dispatch({type: 'dispatch_end'});
}
}
// MyTest.js
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';;
import MockAdapter from 'axios-mock-adapter';
import axios from 'axios';
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
describe('Lets do some tests', () => {
it('Should dispatch timeoutted function', () => {
const store = mockStore({});
// Get all the dispatches for testing purpose
store.dispatch(updateSomething(1, {test: 'test'}))
.then(() => {
const actionList = store.getAction();
expect(actionList).toEqual(allDispatches);
// At this point, I won't be able to get anything inside timeout function
})
});
})
How do I set some kind of Await so I can wait for the timeout before trying to retrieve the data ?
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);
})
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?
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]);
});
I have found many examples online of unit testing Angular 2 with a http call. However when I make my own test and run it Jasmine it gives me an error:
http Http .request() should accept a fully-qualified request as its only parameter
Failed: Cannot read property 'getXHR' of null
import {
afterEach,
beforeEach,
ddescribe,
describe,
expect,
iit,
inject,
injectAsync,
it,
xit
} from "angular2/testing";
import {Injector, provide} from "angular2/core";
import {MockBackend, MockConnection} from "angular2/src/http/backends/mock_backend";
import {
BaseRequestOptions,
ConnectionBackend,
Request,
RequestMethod,
RequestOptions,
Response,
ResponseOptions,
URLSearchParams,
JSONP_PROVIDERS,
HTTP_PROVIDERS,
XHRBackend,
JSONPBackend,
Http,
Jsonp
} from "angular2/http";
import {Observable} from "rxjs/Observable";
import {Subject} from "rxjs/Subject";
describe("http", () => {
let url = "http://foo.bar";
let http: Http;
let injector: Injector;
let backend: MockBackend;
let baseResponse;
let jsonp: Jsonp;
beforeEach(() => {
injector = Injector.resolveAndCreate([
BaseRequestOptions,
MockBackend,
provide(
Http,
{
useFactory: function(backend: ConnectionBackend, defaultOptions: BaseRequestOptions) {
return new Http(backend, defaultOptions);
},
deps: [MockBackend, BaseRequestOptions]
}),
provide(
Jsonp,
{
useFactory: function(backend: ConnectionBackend, defaultOptions: BaseRequestOptions) {
return new Jsonp(backend, defaultOptions);
},
deps: [MockBackend, BaseRequestOptions]
})
]);
http = injector.get(Http);
jsonp = injector.get(Jsonp);
backend = injector.get(MockBackend);
baseResponse = new Response(new ResponseOptions({body: "base response"}));
});
afterEach(() => backend.verifyNoPendingRequests());
describe("Http", () => {
describe(".request()", () => {
it("should return an Observable",
() => { expect(http.request(url)).toBeAnInstanceOf(Observable); });
it("should accept a fully-qualified request as its only parameter",
inject([injectAsync], (async) => {
backend.connections.subscribe(c => {
expect(c.request.url).toBe("https://google.com");
c.mockRespond(new Response(new ResponseOptions({body: "Thank you"})));
async.done();
});
http.request(new Request(new RequestOptions({url: "https://google.com"})))
.subscribe((res) => {});
}));
});
});
});
Any thoughts what I am doing wrong here?
You currently (beta.1) need to set the BrowserDomAdapter before running a unit test in Angular 2.
Using karma-test.shim.js
That can be done by adding karma-test.shim.js to your project, which contains the appropriate initialization:
System.import('angular2/src/platform/browser/browser_adapter')
.then(function(browser_adapter) {
browser_adapter.BrowserDomAdapter.makeCurrent();
})
Note that this should be done for you if you are using angular-cli.
Directly in the unit-test
Or directly in the unit test, by adding an import:
import {BrowserDomAdapter} from 'angular2/src/platform/browser/browser_adapter';
And later setting the DOM Adapter
BrowserDomAdapter.makeCurrent();