This is an interesting problem: I'm trying to test a Service, that uses the Ionic BarcodeScanner.
I have a repo based on the ionic unit-testing repository in order to try testing.
I'm mocking the BarcodeScanner.scan method via spyOn(..).and.callFake(..)
The Problem: It works when I call the scan method from a component. It throws a timeout when I do the exact same thing in a service.
Component test code:
it("should be able to set a spy on the scanner and test the component", done => {
const testBC = "123456";
const spy = spyOn(TestBed.get(BarcodeScanner), "scan");
spy.and.callFake(() => {
return new Promise((resolve, reject) => {
resolve(testBC);
})
});
component.testScanner().then(res => {
expect(res).toBe(testBC);
done();
}, reason => {
expect(true).toBe(false);
done();
})
});
Service test code:
it("should be able to set a spy on the scanner and test the service", done => {
const testBC = "123456";
const spy = spyOn(TestBed.get(BarcodeScanner), "scan");
spy.and.callFake(() => {
return new Promise((resolve, reject) => {
resolve(testBC);
})
});
inject([TestService], (service) => {
service.testScanner().then(res => {
expect(res).not.toBe(testBC);
done()
}, reason => {
expect(true).toBe(false);
done();
})
})
});
Is there any known problem of testing services in Angular 2 that way? Any help appreciated!
tl;dr. In almost all cases, they can be used interchangeably, but using fakeAsync()/tick() combo is preferred unless you need to make an XHR call, in which case you MUST use async()/whenStable() combo, as fakeAsync() does not support XHR calls. For the most part they can be used interchangeably.
async and whenStable We place the tests we need to run after the isAuthenticated promise resolves inside this function. This async function executes the code inside its body in a special async test zone. This intercepts and keeps track of all promises created in its body.
The tick() function simulates the asynchronous passage of time for the timers in the fakeAsync zone in Angular test.
The problem was to not call the inject function.
The test code for the service now looks like this:
it("should be able to set a spy on the scanner and test the service", done => {
const testBC = "123456";
const spy = spyOn(TestBed.get(BarcodeScanner), "scan");
spy.and.callFake(() => {
return new Promise((resolve, reject) => {
resolve(testBC);
})
});
inject([TestService], (service) => {
service.testScanner().then(res => {
expect(res).not.toBe(testBC);
done()
}, reason => {
expect(true).toBe(false);
done();
})
})(); //<-- do not forget these braces!!
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With