8

I'm trying to test a basic angular 2 component that Includes a service. When I run my test I'm getting the following errors. The component, service and test are pretty small, they run fine in the browser as well. I'm not sure what I am missing from the test in order for it to work.

Any help is appreciated.

Uncaught Error: Cannot set base providers because it has already been called(…)

Uncaught Error: Error in ./TestComponent class TestComponent - inline template:0:0 caused by: No provider for Http!
Error: No provider for Http!
    at NoProviderError.BaseError [as constructor] (http://localhost:9876/base/karma-shim.js:4006:34)
    at NoProviderError.AbstractProviderError [as constructor] (http://localhost:9876/base/karma-shim.js:33221:16)
    at new NoProviderError (http://localhost:9876/base/karma-shim.js:33252:16)
    at ReflectiveInjector_._throwOrNull (http://localhost:9876/base/karma-shim.js:57969:19)
    at ReflectiveInjector_._getByKeyDefault (http://localhost:9876/base/karma-shim.js:57997:25)
    at ReflectiveInjector_._getByKey (http://localhost:9876/base/karma-shim.js:57960:25)
    at ReflectiveInjector_.get (http://localhost:9876/base/karma-shim.js:57769:21)
    at TestBed.get (http://localhost:9876/base/karma-shim.js:5778:67)
    at ElementInjector.get (http://localhost:9876/base/karma-shim.js:58133:48)
    at _View_TestComponent0.createInternal (TestComponent.ngfactory.js:21:68)
    at _View_TestComponent0.AppView.create (http://localhost:9876/base/karma-shim.js:58492:21)
    at _View_TestComponent0.DebugAppView.create (http://localhost:9876/base/karma-shim.js:58704:44)
    at _View_TestComponent_Host0.createInternal (TestComponent_Host.ngfactory.js:18:14)
    at _View_TestComponent_Host0.AppView.create (http://localhost:9876/base/karma-shim.js:58492:21)
    at _View_TestComponent_Host0.DebugAppView.create (http://localhost:9876/base/karma-shim.js:58704:44)
    at ComponentFactory.create (http://localhost:9876/base/karma-shim.js:33751:36)
    at initComponent (http://localhost:9876/base/karma-shim.js:5816:53)
    at ZoneDelegate.invoke (http://localhost:9876/base/karma-shim.js:48531:26)
    at ProxyZoneSpec.onInvoke (http://localhost:9876/base/karma-shim.js:48195:39)
    at ZoneDelegate.invoke (http://localhost:9876/base/karma-shim.js:48530:32)
    at Object.onInvoke (http://localhost:9876/base/karma-shim.js:22909:37)
    at ZoneDelegate.invoke (http://localhost:9876/base/karma-shim.js:48530:32)
    at Zone.run (http://localhost:9876/base/karma-shim.js:48413:43)
    at NgZone.run (http://localhost:9876/base/karma-shim.js:22799:62)
    at TestBed.createComponent (http://localhost:9876/base/karma-shim.js:5819:62)
    at Function.TestBed.createComponent (http://localhost:9876/base/karma-shim.js:5634:33)
    at Object.<anonymous> (http://localhost:9876/base/karma-shim.js:63273:41)
    at ZoneDelegate.invoke (http://localhost:9876/base/karma-shim.js:48531:26)
    at ProxyZoneSpec.onInvoke (http://localhost:9876/base/karma-shim.js:48195:39)
    at ZoneDelegate.invoke (http://localhost:9876/base/karma-shim.js:48530:32)
    at Zone.run (http://localhost:9876/base/karma-shim.js:48413:43)
    at Object.<anonymous> (http://localhost:9876/base/karma-shim.js:47910:34)
    at ZoneQueueRunner.jasmine.QueueRunner.ZoneQueueRunner.execute (http://localhost:9876/base/karma-shim.js:47940:42)
    at ZoneQueueRunner.jasmine.QueueRunner.ZoneQueueRunner.execute (http://localhost:9876/base/karma-shim.js:47940:42)
    at ZoneDelegate.invokeTask (http://localhost:9876/base/karma-shim.js:48564:35)
    at Zone.runTask (http://localhost:9876/base/karma-shim.js:48453:47)
    at drainMicroTaskQueue (http://localhost:9876/base/karma-shim.js:48700:35)

!-- the component

import { Component, OnInit } from '@angular/core';
import { TestService } from '../components/service/TestService';
@Component({
  selector: 'my-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.scss'],
  providers: [TestService]
})
export class HomeComponent implements OnInit {

  constructor(private testService: TestService) {
    // Do stuff
  }

  ngOnInit() {
    console.log('Hello Home', this.testService.getUsers());
  }

}

!-- the service

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';

@Injectable()
export class TestService {
  constructor(public http: Http) {}

  getUsers() {
    return this.http.get('http://foo.bar');
  }
}

!-- the test

import { inject, TestBed } from '@angular/core/testing';

import {BaseRequestOptions, Response, ResponseOptions, Http} from '@angular/http';
import { MockBackend, MockConnection } from '@angular/http/testing';

import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
import {TestService} from './TestService';

TestBed.initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());

describe('Http', () => {

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        TestService,
        BaseRequestOptions,
        MockBackend,
        {
          provide: Http,
          useFactory: (backend: MockBackend, defaultOptions: BaseRequestOptions) => {
            return new Http(backend, defaultOptions);
          },
          deps: [MockBackend, BaseRequestOptions],
        },
      ],
    });
  });

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

  it('should return response when subscribed to getUsers', inject([TestService], (testService: TestService) => {
    testService.getUsers().subscribe((res: Response) => {
      expect(res.text()).toBe('got response');
    });
  }));

});
Jimi
  • 1,867
  • 7
  • 31
  • 55
  • I don't see where you are trying to test the component. Are you sure you're showing us the correct test. I don't see the code above causing this error. – Paul Samsotha Oct 30 '16 at 01:17
  • 4
    Also, if you are going to call `TestBed.initTestEvironment`, then you should call `TestBed.resetTestEnvironment` before it. `initTestEnvironment` should only be called once if it is not reset. So in other test files if you are also calling it, then you should reset it for other tests before initializing it – Paul Samsotha Oct 30 '16 at 01:34
  • hi @peeskillet, this is the correct test that I'm showing. I've not tried to remove the initTestEnvironment call. I'll give it a try and let you know if this has an effect. – Jimi Oct 30 '16 at 01:54
  • 1
    I didn't say to remove it. Normally this is called once in a test-shim file. If you are not using the test-shim, then you _need_ to call it. But you need to _reset_ it first, as you would be trying to call it in all the files. You don't know which file is going to be called first. so just add it to all the test files, but you need to reset it also – Paul Samsotha Oct 30 '16 at 01:56
  • Ok, I've reset the TestBed.resetTestEnvironment(); then initialised it inside the beforeEach of my test. Now i'm receiving a no provider error from the test for http. >> zone.js:158Uncaught Error: Error in ./TestComponent class TestComponent - inline template:0:0 caused by: No provider for Http! Error: No provider for Http! – Jimi Oct 30 '16 at 03:18
  • I told you, you are not showing the correct test. The test you are showing does not have the `TestComponent` (which the error is about), nor does the test show anything about a `HomeComponent`, so I am not sure why you are showing that. – Paul Samsotha Oct 30 '16 at 03:22
  • Yes, you're absolutely right. Good to have a second pair of eyes.... Thanks for your help. – Jimi Oct 30 '16 at 05:57

2 Answers2

15

I've fixed this problem doing the following:

move TestBed.initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting()); to the beforeAll function, so it look like this

describe('Http', () => {
    beforeAll( ()=> {
        TestBed.initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
    });
    beforeEach( () => {
       TestBed.configureTestingModule({
           providers : [...]
       }
    });
    it('your tests...', inject([Provider], (provider:Provider)=>{});
11

You might also get this message Cannot set base providers because it has already been called(…)

Because you do have a setupFilesAfterEnv in your jest config file.

And one of those setupFiles runs code which set base providers before you do.

Example:

jest.config.js

{
  setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'],
}

setup-jest.ts

# remove this line
`import 'jest-preset-angular/setup-jest';`
Flavien Volken
  • 19,196
  • 12
  • 100
  • 133