Search code examples
angularionic3angular2-servicesangular-services

Testing async (Promise) methods in Angular 2 Services


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!


Solution

  • 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!!
    });