Reputation: 3504
I've a GeoLocationService
in my angular application like this.
import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Observable";
@Injectable()
export class GeoLocationService {
coordinates: any;
constructor() {}
public getPosition(): Observable<Position> {
return Observable.create(observer => {
navigator.geolocation.watchPosition((pos: Position) => {
observer.next(pos);
}),
() => {
console.log("Position is not available");
},
{
enableHighAccuracy: true
};
});
}
}
I want to unit test this service to ensure that the getPosition()
function returns me a working Observable
. Here's how my test looks like.
import { TestBed, fakeAsync } from "@angular/core/testing";
import { GeoLocationService } from "./geo-location.service";
import { take } from "rxjs/operators";
describe("GeoLocationService", () => {
let service: GeoLocationService;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [GeoLocationService]
});
service = TestBed.get(GeoLocationService);
});
it("should get observable value", fakeAsync((done: DoneFn) => {
service
.getPosition()
.subscribe(value => {
expect(value.coords).not.toBeUndefined();
expect(value.coords).not.toBeNaN();
expect(value.coords).not.toBeNull();
done();
});
}));
});
What happens here is that once I run the test the test is successful ( this is because the subscribe
block inside the test is not run yet). On the chrome browser window
that opens ( for viewing test results in karma ), I select Allow
for the application to find my location, it is at this moment the subscribe
block runs but by that time the it
spec has already finished due to this reason I get a console error
saying.
Uncaught Error: 'expect' was used when there was no current spec, this could be because an asynchronous test timed out
.
I don't know what is the recommended way to perform this test.
Upvotes: 4
Views: 9130
Reputation: 3504
I was able to get it working using the following code.
it("should get current user coordinates", (done: DoneFn) => {
let position: any;
service.getPosition().subscribe(value => {
position = value;
expect(position.coords).not.toBeUndefined();
expect(position.coords).not.toBeNaN();
expect(position.coords).not.toBeNull();
done();
});
});
For this the test waits until you Allow
the browser window to get your location. If you wait for too long, it will throw a timeOut error. Good enough for me to test what I wanted.
Upvotes: 5
Reputation: 16574
You can use tick()
which fakes the test into being synchronous-ish :-)
it("should get observable value", fakeAsync((done: DoneFn) => {
let matchValue = {coords: null};
service
.getPosition()
.subscribe(value => {
matchValue = value;
});
tick(2000); // whatever fits your needs
expect(matchValue.coords).not.toBeUndefined();
expect(matchValue.coords).not.toBeNaN();
expect(matchValue.coords).not.toBeNull();
done();
}));
Upvotes: 1