Search code examples
javascriptangulartypescriptjasminekarma-jasmine

Create list of imports service provider on unit testing


I'm new to Angular, and I have a new team that told me to implement unit testing on an old project with Angular 8. So after investigating that, I decided to use Karma + Jasmine, and I created .spect.ts document like this:

describe("CashFlowSalariesComponent", () => {
      let fixture: ComponentFixture < CashFlowSalariesComponent > ;
      let instance;
      let profile: ProfileModel;

      beforeEach(async() => {
        TestBed.configureTestingModule({
          schemas: [CUSTOM_ELEMENTS_SCHEMA],
          imports: [
            RouterTestingModule,
            FormsModule,
            ReactiveFormsModule,
            BrowserModule,
            HttpClientModule,
            ToastrModule.forRoot({
              positionClass: "toast-bottom-right",
            }),
          ],
          declarations: [CashFlowSalariesComponent],
          providers: [
             ApiService,
    UserService,
    ProfileService,
    VettingStatusService,
    SkillService,
    ApplicationRoleService,
    SeniorityLevelService,
    PlacementStatusService,
    EducationLevelService,
    UtilsService,
    ShirtSizeService,
    GenderService,
    TimeZoneService,
    CountryService,
    CityService,
    PostalCodeService,
    StateService,
    ClientSectorService,
    JobService,
    ClientService,
    PulsecheckQuestionService,
    PulsecheckMasterService,
    ExchangeRateService,
    DepartmentService,
    ExpenseService,
    ProfileRoleService,
    SkillCategoriesService,
    ProfileActivityService,
    ProfileSalaryActivityService,
    TimeSheetService,
    HolidayService,
    RequestTimeOffService,
    TimeOffTypeService,
    InvoiceService,
    PulsecheckDetailService,
          ],
        }).compileComponents();

        fixture = TestBed.createComponent(CashFlowSalariesComponent);
        instance = fixture.componentInstance;

        fixture.detectChanges();

        profile = new ProfileModel();
        (instance as any).exchangeRate = 18.92;
      });

      afterEach(() => {
        fixture.destroy();
      });

      it("To test instance creation of component", () => {
        expect(instance).toBeTruthy();
      });

As you can see, I had to import many services from providers because my ApiService had injected them, so if I no add them, it returned an error like this:

NullInjectorError: No provider for {serviceName}!

So each time I call the ApiService on each component, developers should copy and paste from this component all the services. So my question is: is this a way to create a class or something to import all providers in once without copying and pasting code each time? How can I achieve this?


Solution

  • There are 2 things that could help you with your issue:

    • You can define your services as providedIn: 'root' in this case you don't need to provide them in any module or test. Angular would resolve them automatically.

    example:

    @Injectable({ providedIn: 'root' })
    export class UserService {}
    
    • You could also define global providers in your test.ts file.

    example:

    @NgModule({ 
        imports: [RouterTestingModule, HttpClientTestingModule], 
        providers: [...],
    })
    class GlobalTestingSetupModule {}
    
    
    TestBed.initTestEnvironment([BrowserDynamicTestingModule, GlobalTestingSetupModule], platformBrowserDynamicTesting());
    

    Also, instead of HttpClientModule it is preferable to use HttpClientTestingModule in unit tests.