Search code examples
angularunit-testingtypescriptkarma-jasmineangular2-services

Angular 2 Services Unit Testing with DarkSkyApi call


I hope you can help. I search in the whole internet for answer to my questions. I new in programming with Angular 2 and all answers i find are to crypticle to me.

so thats my question. I will test a service in angular 2 with karma. And have the DarkskyApi in Use at the Service:

//imports
import DarkSkyApi from 'dark-sky-api';  

@Injectable()
export class WetterService {

  /***
   * Konstruktor
   */
  constructor() {
    this.skyApi = this.InitDarkSky();
  }

  /**
   * Die Verbindung zur API Darksky initalialisiern
   */
  private InitDarkSky(): IDarkSkyApi {
    const darksky: IDarkSkyApi = new DarkSkyApi(this.ApiKey);

    // Ansteuern der Api
    return darksky
      .units('si')
      .language('de');
  }
}

and this is the test to the service:

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

import { WetterService } from './wetter.service';
import {HttpClientModule} from '@angular/common/http';
import DarkSkyApi from 'dark-sky-api';

describe('WetterService', () => {
  let darkSkyApi: DarkSkyApi;

  beforeEach(() => {
    darkSkyApi = new DarkSkyApi();
    TestBed.configureTestingModule({
      providers: [
        WetterService
      ],
      imports: [HttpClientModule]
    });
  });

  it('should be created', inject([WetterService], (service: WetterService) => {
    expect(service).toBeTruthy();
  }));
});

When i run the test i become follow error:

TypeError: dark_sky_api_1.default is not a constructor

I hope so you can help.

Thanks, Steffen


Solution

  • The reason is that you create a new instance instead of having an DI. You could propably add DarkSkiApi via Factory. This is just blind coded.

    in app.module.ts

    providers: [{
      provide: DarkSkyApi,
      useFactory: DarkSkyApiFactory
    }]
    

    then you have a factory

    import DarkSkyApi from 'dark-sky-api';
    
    export function DarkSkyApiFactory(): JwtHelper {
     return new DarkSkyApi('API_KEY');
    }
    

    in your service it will look like this:

      export class WetterService {
         constructor(private darkSkyApi: DarkSkyApi) {
           this.darksky
               .units('si')
               .language('de');
         } 
      }
    

    and then you can easily mock the API in your test

        wetterService = new WetterService(fakeApi as DarkSkyApi);
        class fakeApi = {
         units(unit: string) {}
         language(language: string) {}
        };
    

    This is really just a basic Idea how to rewrite your code to be better testable