I am struggling to unit test Angular2 service which has async Http call in the constructor (now I wonder should it be here in the first place).
Example code below - the mocked call never seems to have been executed and I am not sure where should I put it in. The test fails as the property I am asserting is undefined at the time of execution. I tried with fakeAsync and tick() but that didnt work neither.
Service class:
#Injectable
export class Service {
private data: any; //some object that will be returned from server
constructor(private http: Http) {
this.http.get('url')
.map( (res: Response) => res.json())
.subscribe(res => this.data = res);
}
getId() {
return data.id;
}
}
The unit test:
describe('service test...', () => {
let service: Service;
let backend: MockBackend;
let result = { id: 123 };
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpModule],
providers: [
Service,
{
provide: Http,
useFactory: (mockBackend, options) => {
return new Http(mockBackend, options);
},
deps: [MockBackend, BaseRequestOptions]
},
MockBackend,
BaseRequestOptions
]
});
});
beforeEach(inject([Service, MockBackend], (s, mb) => {
service = s;
backend = mb;
backend.connections.subscribe((conn) => {
conn.mockRespond(new Response(new ResponseOptions({body: result})));
});
}));
describe('test...', () => {
it('should have id of 123...', async(() => {
expect(service.getId()).toEqual(123);
}));
});
});
Related
I am trying to test my router event this is what te code in the TS file look like:
constructor(
private router: Router
) {
router.events.subscribe(route => {
// I removed the code because it doesn`t matter for the solution
});
}
unittest:
describe('MainComponent', () => {
let methodSpy: jasmine.Spy;
const eventSubject = new ReplaySubject<RouterEvent>(1);
const routerMock = {
navigate: jasmine.createSpy('navigateByUrl'),
navigateByUrl: jasmine.createSpy('navigateByUrl'),
events: eventSubject.asObservable(),
url: 'test/url',
createUrlTree: (commands, navExtras = {}) => {},
serializeUrl: (commands, navExtras = {}) => {}
}
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule, FormsModule],
declarations: [],
providers: [
{ provide: Router, useValue: routerMock},
{ provide: ActivatedRoute, useValue: routerMock},
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MainComponent);
component = fixture.componentInstance;
methodSpy = spyOn(component, 'AdminPanelStarted');
//fixture.detectChanges();
});
it('should trigger the router event and hit the function "Panel"', () => {
eventSubject.next(new NavigationEnd(1, 'test', 'routeUrl'));
expect(methodSpy).toHaveBeenCalled();
});
});
this is the error I am getting:
I can`t find the solution. The only thing I want to test is if the correct function have been called after entering the router.events subscription. The observable is triggered but gives the error that startsWith can not be done on undefined. But what is undefined?
Thx a Lot!
I am trying to write a unit test of an angular 6 component which is initializing the bootstrap-daterangepicker in the ngAfterViewInit() method. When I run my unit test it gives the following error:
TypeError: $(...).daterangepicker is not a function
this is the code from the actual component(EmployeeComponent):
ngAfterViewInit(): void {
this.initializeDatePicker(this);
}
initializeDatePicker(that: any) {
const start = moment().subtract(7, 'days');
const end = moment();
$('#reportrange').daterangepicker({
startDate: start,
endDate: end,
maxDate: moment(),
ranges: {
'Today': [moment(), moment()],
'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')]
}
}, cb);
cb(start, end);
}
this is the code from my test class:
describe('EmployeeComponent', () => {
let component: EmployeeComponent;
let fixture: ComponentFixture<EmployeeComponent>;
let messageService: NotificationService;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [EmployeeComponent]
})
.overrideComponent(EmployeeComponent, {
set: {
template: '',
providers: [
{ provide: NotificationService, useValue: messageService },
{ provide: ActivatedRoute, useValue: { queryParams: of({ emp: "123" }) } }
]
}
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(EmployeeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
You don't need to handle it in your test cases. That component should be initialized in a separate service and you can simply mock that method from the service. In the way you can avoid this error.
let say you move all the code of the initializeDatePicker() in a method in some service let say common-service.ts and you can simply call that service from this method like
this.commonServiceObj.initializeDatePicker();
Now after doing this, you can simply mock initializeDatePicker() from the service object and error should be gone.
I have a DataService and I want to assert that the year is getting set in the query string correctly. Is there a way to spyOn the http.get call or to access it? I don't know the correct approach to testing this. I'm using Angular 2.2.0.
The DataService
constructor(private http: Http) { }
public getEnergyData(option: string): Promise<EnergyDataDto[]> {
return this.http.get(this.getEnergyDataApiUrl(option)).toPromise().then((response) => {
this.energyDataCache = this.parseEnergyDataResponse(response);
return this.energyDataCache;
}).catch(this.handleError);
}
protected getEnergyDataApiUrl(option: string) {
return `/api/solar?year=${option}`;
}
protected parseEnergyDataResponse(response: Response) {
return response.json().data;
}
dataservice.spec.ts
describe('Given the DataService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpModule],
providers: [DataService, { provide: XHRBackend, useClass: MockBackend }],
});
});
describe('When getting the energy data', () => {
let backend: MockBackend;
let service: EnergyDataService;
let fakeEnergyData: EnergyDataDto[];
let response: Response;
const makeEnergyData = () => {
let data = [];
let one = new EnergyDataDto();
one.year = 2007;
one.countryName = 'Denmark';
one.quantity = '100000';
data.push(one);
return data;
};
beforeEach(inject([Http, XHRBackend], (http: Http, be: MockBackend) => {
backend = be;
service = new EnergyDataService(http);
fakeEnergyData = makeEnergyData();
let options = new ResponseOptions({ status: 200, body: { data: fakeEnergyData } });
response = new Response(options);
}));
it('should return fake values', async(inject([], () => {
backend.connections.subscribe((c: MockConnection) => c.mockRespond(response));
service.getEnergyData('all').then(data => {
expect(data.length).toBe(1);
expect(data[0].countryName).toBe('Denmark');
});
})));
it('should use year in query string', async(inject([], () => {
spyOn(service, 'getEnergyDataApiUrl').and.callThrough();
backend.connections.subscribe((c: MockConnection) => c.mockRespond(response));
service.getEnergyData('2007').then(data => {
// I was hoping to use backendend somehow instead, but it's not in scope when I debug it.
expect((<any>service).getEnergyDataApiUrl).toHaveBeenCalledWith('/api/solar?year=2007');
});
})));
You should do this in the mockBackend.connections subscription. This is when you have access to the URL from the MockConnection
backend.connections.subscribe((c: MockConnection) => {
expect(c.request.url).toBe(...)
c.mockRespond(response)
});
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?
I need to unit test this part of my code in MyService
social(someUrl){
let intervalTimer = Observable.interval(1000);
let authWindow = window.open(someUrl);
let pingWindow = intervalTimer.subscribe(()=>{
if(authWindow.closed){
pingWindow.unsubscribe();
return this.http.get(...)
}
})
}
it pops up with some Url which calls to execute some function in my backend and once it's done, it will be redirected to an empty page which closes the pop up (so just window.close() in the script)
So basically the code above checks every second if the pop up is still open, if not it unsubscribes and returns a http.get request as Observable.
I have two major questions:
How to stub the window.open and test, that someUrl is being used, I've read that so far you can only use jasmine? In Sinon you have sinon.stub(window, 'open',()=>{})
how to test the http.get inside the interval? I'm getting this error
1 periodic timer(s) still in the queue.
this is my test.spect setup
const mockHttpProvider = {
deps: [MockBackend, BaseRequestOptions],
useFactory: (backend: MockBackend, defaultOptions: BaseRequestOptions) => {
return new Http(backend, defaultOptions)
}
};
describe('my Test', () => {
beforeEachProviders(() => {
return [
MyService,
MockBackend,
BaseRequestOptions,
provide(Http, mockHttpProvider)
]
});
it('should...', inject([MyService, MockBackend], fakeAsync((myService: MyService, backend: MockBackend) => {
backend.connections.subscribe((connection: MockConnection) => {
???
});
myService.social().subscribe(res => {
???
});
})))
thanks!