Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating Test Case for Angular Service with Dependencies Using TestBed

Good Day.

Currently running a project in angular framework. I am attempting to write a test case for a service with dependencies, but obviously do not understand the how to scaffold it. Below are the two classes in question.

This is the LoginService

@Injectable({
  providedIn: 'root'
})
export class LoginService implements CanActivate, OnInit {

  constructor(private router: Router,
              private httpClient: HttpClient,
              private cookieService: CookieService) { }

This is the test class for LoginService:

import {Router} from '@angular/router';
import {CookieService} from 'angular2-cookie/core';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {LoginService} from './login.service';
import {HttpClient} from '@angular/common/http';

describe('Service: LoginService', () => {

  let router: Router;
  let httpClient: HttpClient;
  let cookieService: CookieService;
  let service: LoginService;
  let fixture: ComponentFixture<LoginService>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [LoginService],
      providers: [Router, HttpClient, CookieService]
    });

    fixture = TestBed.createComponent(LoginService);
    service = fixture.componentInstance;
    router = TestBed.get(Router);
    httpClient = TestBed.get(HttpClient);
    cookieService = TestBed.get(CookieService);
  });

  it('should return true from isLoggedIn when token is set', function () {
    spyOn(cookieService, 'get').and.returnValue('true');
    expect(service.isLoggedIn()).toBeTruthy();
  });
});

It is simple as I am trying it out. The error I am getting is :

Error: Unexpected value 'LoginService' declared by the module 'DynamicTestModule'. Please add a @Pipe/@Directive/@Component annotation.
    at syntaxError (http://localhost:9876/node_modules/@angular/compiler/fesm5/compiler.js?:2547:1)

Basically my intention is to have the LoginService's dependencies injected and then use the spyOn method within the individual tests to disrupt flow as I deem fit.

A nudge in the right direction would be appreciated. If the solution is documented please do link.

Are services treated in a different way compared to the Components when using the TestBed? If I am honest I am not sure how to interpret the error as why would a Service have those annotations?

EDIT after reading @Dream88

The solution to my problem:

import {Router} from '@angular/router';
import {CookieService} from 'angular2-cookie/core';
import {LoginService} from './login.service';
import {HttpClient, HttpClientModule} from '@angular/common/http';
import {AppRoutingModule} from '../../app-routing.module';
import {TestBed} from '@angular/core/testing';
import {AppModule} from '../../app.module';

describe('Service: LoginService', () => {

  let router: Router;
  let httpClient: HttpClient;
  let cookieService: jasmine.SpyObj<CookieService>;
  let service: LoginService;

  beforeEach(() => {
    const cookieServiceSpy = jasmine.createSpyObj('CookieService', ['get']);
    TestBed.configureTestingModule({
      imports: [
        AppModule,
        AppRoutingModule,
        HttpClientModule
      ],
      providers: [LoginService, {
        provide: CookieService, useValue: cookieServiceSpy
      }]
    });

    router = TestBed.get(Router);
    httpClient = TestBed.get(HttpClient);
    cookieService = TestBed.get(CookieService);
    service = new LoginService(router, httpClient, cookieService);
  });

  it('should return true from isLoggedIn when token is set', function () {
    cookieService.get.and.returnValue('true');
    expect(service.isLoggedIn()).toBeTruthy();
  });
});

Long story short - I had no idea what I was typing. After understanding the underlying implementation it was straight forward. Thanks for the nudge. Marking Dream88 correct.

I asked my self how the prod code works. HHow are Services injected. What demarcates a service(@Injectable). That hinted to what should be in imported and providers.

Regards.

like image 985
Nilo Avatar asked Oct 17 '22 10:10

Nilo


1 Answers

This won't work as: fixture = TestBed.createComponent(LoginService); is supposed to create a component i.e something with annotation @component. With @service it is not meant to render a UI. Hence, the error.

Testing a service should be a case of simple testing functionality, no need for TestBed. You will only need to do this when you want to test a component which uses the said service, in which case you will need to add this to providers list.

For just testing Services, have a look on Angular Doc.

like image 104
dream88 Avatar answered Oct 30 '22 14:10

dream88