1

I want to test following service which return an observable :

 public getData(str:string) {
    // return an observable
    return this.http.get(‘calltoserviceapi’+str)
        .map( (responseData) => {

            return responseData.json().Abc;
        })
        .map((s: Array<any>) => {
            let result:Array<AbcModel> = [];
            if (s) {
                s.forEach((s) => {
                    result.push(
                        new AbcModel(s.Val1,
                            s.Val2,
                            ));
                });
            }
            return result;
        });
}

my spec file:

fdescribe ("my-service.spec.js", ()=> {

    beforeEachProviders(() => [
        MyService,
        BaseRequestOptions,
        MockBackend,
        provide(Http, {
            useFactory: (backend: MockBackend, defaultOptions: BaseRequestOptions) => {
                return new Http(backend, defaultOptions);
            },
            deps: [MockBackend, BaseRequestOptions]
        }),
        provide(XHRBackend, {useClass: MockBackend})
    ]);



fit('should get response',inject([XHRBackend, MyService], (mockBackend, service) => {
        console.log("inside fit");
        let response = "something returned from service";
        let responseOptions = new ResponseOptions({ body: response });

        mockBackend.connections.subscribe((connection: MockConnection) => {
                connection.mockRespond(new Response(responseOptions));
        });

        service.getData('xyz').subscribe((a: MyModel[]) => {
                    expect(a.length).toBe(11); //this is NOT failing
              expect(a).toContain(“something”);

                }); //debugger not going inside subscribe

    }));

On debugging, the subscribe method is not executed. as a result my test case is getting pass without getting executed. what am i missing ?
P.S : MyService is not being used/called inside component at the moment.

candidJ
  • 4,289
  • 1
  • 22
  • 32

2 Answers2

0

I think you need to add async(...)

fit('should get response',async(inject([XHRBackend, MyService], (mockBackend, service) => {

to make the test wait until all async tasks are done. Otherwise the http.get() tasks gets scheduled and then the test ends.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • for some reason , webstorm is throwing `TS2345: Argument of type 'Function' is not assignable to parameter of type '(done: DoneFn) => void'. Type 'Function' provides no match for the signature '(done: DoneFn): void' ` on using `inject` alone or `async(inject(..` – candidJ Jun 02 '16 at 11:36
  • i'm little confused here, why do we use `mockbackend` then if we are going to wait for service api to return something. – candidJ Jun 02 '16 at 11:38
  • 1
    What Angular2 version are you using? I don't understand your last comment. `mockbackend` is used to prevent calls to the server and to be able to provide the response from inside the test. The service API behaves the same as if the call was made to the server (even when it actually isn't). – Günter Zöchbauer Jun 02 '16 at 11:46
  • Exactly that's what i mean. But still debugger is not going into `subscribe` method. – candidJ Jun 02 '16 at 12:08
  • Because without some means to make the test wait for async calls to complete the test ends immediately after async calls (`http.get()`) are scheduled (but not yet executed). – Günter Zöchbauer Jun 02 '16 at 12:12
  • hmmm....I'm using `async(inject(..` as you said. shall i use `.delay(10000)` somwhere or any other workaround? – candidJ Jun 02 '16 at 12:21
  • You were able to get rid of the exception mentioned in your first comment? There should be no need to call `.delay()`. What Angular2 version are you using? – Günter Zöchbauer Jun 02 '16 at 12:23
  • Yes. `angular :2.0.0-rc.1`, `rxjs: ".0.0-beta.6`. – candidJ Jun 02 '16 at 12:39
  • I don't use it myself, I just follow the issues in the Angular GitHub repo. Actually I don't know what version supports what kind of async testing. This changed with almost every update the last months. From what I know the last change was that using `async(...)` should wait for all async calls to be done but this changes might not yet be included in RC.1. Probably only with the next update. – Günter Zöchbauer Jun 02 '16 at 12:44
  • @GünterZöchbauer, I'm having the same issue and tried the solution you suggested (wrapping the whole thing inside async), but still my subscribe body is not getting invoked. I noticed this post is from 2016, did anything change since then? – Aiguo Oct 01 '17 at 14:56
0

finally i figured out the solution to it. Two changes I made:

  • using async() as pointed by @Gunter
  • stringify the response passed .

here is the code :

fit('should get response',async(inject([XHRBackend, MyService], (mockBackend, service) => { //<--- wrap inside async call
    console.log("inside fit");
    let response = "something returned from service";
    let responseOptions = new ResponseOptions({ body: JSON.stringify(response) }); //<--- stringify the response

    mockBackend.connections.subscribe((connection: MockConnection) => {
            connection.mockRespond(new Response(responseOptions));
    });

    service.getData('xyz').subscribe((a) => {
                    expect(a.length).toBe(11); //will fail
                   expect(a).toContain(“something”); //will pass

                }); 

})));
candidJ
  • 4,289
  • 1
  • 22
  • 32