1

I'm working on building out tests for my services in Angular 2. Building out the mock backends is proving to be a real trial. I have been able to test the services with it making actual HTTP requests successfully but I would like to keep these segregated from the third part.

I've combed through the two main articles I have been able to find (first, second as well as the angular docs.

When I was making successful http requests to actual third party services, I had to use done(); to ensure that the test waited for the request to complete. It seems that the case is the same here. If I do not use it, the test will be a success even with expect(1).toBe(2);. When I do use it, it times out waiting for the call to complete. Error:

Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.

Here's my code:

import {
    it,
    inject,
    describe,
    beforeEachProviders,
    expect,
} from '@angular/core/testing';
import { BaseRequestOptions, Response, ResponseOptions, Http } from '@angular/http';
import { MockBackend, MockConnection } from '@angular/http/testing';

import { AccountService } from './../../source/scripts/services/account.service';
import { provide } from '@angular/core';

describe('AccountService', () => {
    // let service;

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

    beforeEach(<any>inject([MockBackend], (backend: MockBackend) => {
        const baseResponse = new Response(new ResponseOptions({ body: 'got response' }));
        backend.connections.subscribe((c: MockConnection) => c.mockRespond(baseResponse));
    }));

    // We use 'done' for async callbacks (http calls)    
    it('should return mocked response', (done) => {

        inject([AccountService], (testService: AccountService) => {
            testService.getUsers().subscribe((res: Response) => {
                expect(res.text()).toBe('got response');
                expect(1).toBe(2);
                done();
            });
        });
    });
});

How do I properly test http calls with a mockbackend? I suspect that either the links I referenced above are out of date or they didn't confirm that the test was actually testing rather than just giving false positives without the async of done();.

1 Answer 1

2

You were very close. Only the async done is not appropriate here because inject has to replace this anonymous callback. So here is the fixed version:

it('should return mocked response', inject([AccountService], (testService: AccountService) => {
  testService.getUsers().subscribe((res: Response) => {
    expect(res.text()).toBe('got response');
    expect(1).toBe(2);
  });
}));

Another problem is missing beforeEach import:

import {
    it,
    inject,
    describe,
    beforeEach, // <-- this one was missing
    beforeEachProviders,
    expect,
} from '@angular/core/testing';

So there was a Jasmine's beforeEach instance which doesn't allow to use inject.

Sign up to request clarification or add additional context in comments.

10 Comments

Answered by the blog author himself! Changing my assertion to match what you have above gives a different error. I think it's a problem with how it's parsing it? It happened when I tried to inject the service into the beforeEach section as well. The trace is something like this: _instantiateProvider@C:/sites/Scratch/prototype_ui/config/karma-test-shim.js:18060:38 <- webpack:///~/@angular/core/src/di/reflective_injector.js:626:0. Any ideas?
Ok, theres no beforeEach in imports as well. I'll update the answer :)
Hmm, that is odd, you're right. I'm using it here and in all my other tests and it hasn't ever said anything about there not being a beforeEach from imports.
It will work with Jasmine's beforeEach until you want to use inject there.
Ohh, that's why I have to declare <any> before injecting, it's using the wrong beforeEach. That makes sense but I'm still getting the same error after adding beforeEach and removing the <any>.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.