how to write unit test in angular service that call http in constructor and fill property?

246 Views Asked by At

I am new in angular unit testing; I want to write a unit test for the service that is injected in constructor and is called http in it . but I don't know why globalConfig property is undefined:

@Injectable({
  providedIn: "root",
})
export class GlobalConfigService {
  globalConfig: GlobalConfig= new GlobalConfig();

  constructor(private http: HttpClient, private configService: ConfigService) {    
      if (configService.getData() == undefined){
       let data:any;
       http.get('./assets/config/config.json').subscribe(
         ok => {
           data = ok;
           http.get<any>(data.baseUrl + 'config/app').subscribe(
             response => {
               response.baseUrl = data.baseUrl;
               configService.setData(response);
               this.globalConfig = <GlobalConfig>{
                baseUrl: configService.getData()["baseUrl"],
                language: configService.getData()["language"],
          };
             },
             error => {
               console.log(error);
             }
         )
         },
         error => {
           console.log(error);
         }
     )
      }
      else{
        this.globalConfig = <GlobalConfig>{
          baseUrl: configService.getData()["baseUrl"],
          language: configService.getData()["language"],         
    };
  }
  }
  get Config(): Promise<GlobalConfig> {
    return new Promise((resolve, reject) => {
      resolve(this.globalConfig);
    });
  }

  get appConfig(): GlobalConfig {
    return this.globalConfig;
  }
}

The unit test I've written is:

describe('GlobalConfigService', () => {
    let httpTestingController: HttpTestingController;
    let ConfigServiceSpy: ConfigService;
    let mockGlobalConfig: GlobalConfigService;

    beforeEach(() => {
        ConfigServiceSpy = jasmine.createSpyObj('ConfigService', ['getData','setData']);
        TestBed.configureTestingModule({
            imports: [HttpClientTestingModule],
            providers: [GlobalConfigService, {provider: ConfigService, useValue: ConfigServiceSpy}]
        });       
        httpClient = TestBed.inject(HttpClient);
        httpTestingController = TestBed.inject(HttpTestingController);
        mockGlobalConfig = TestBed.inject(GlobalConfigService);
        ConfigServiceSpy = TestBed.inject(ConfigService);

    });
 it('should return config ', () => {

        let response = {
            baseUrl: "http://localhost:8080/",
            language: "fa",         
        };      
        const req = httpTestingController.expectOne(
            "./assets/config/config.json"
        );
        expect(req.request.method).toEqual("GET");
        req.flush(response);
        expect(mockGlobalConfig.appConfig.baseUrl).toBe(response.baseUrl);
    });

but this error occurs : Expected undefined to be 'http://localhost:8080/ what should I do ?

2

There are 2 best solutions below

0
On

Your logic is called in the constructor, my guess is that it's too late when you flush. You should try to spy/mock your service dependencies, not use testBed nor HttpClientTestingModule and create a new instance of your service with your mocks as parameters.Then you should be able to assert as your value mocks would be there during subscription in the constructor.

https://angular.io/guide/testing-services#testing-http-services

Also you should clean your code in your constructor: encapsulate parts of logic in methods to be more readable, and try not to nest subscribes but use rxjs operators https://rxjs.dev/guide/overview

0
On

thanks Grogu I changed service to :

 http.get('./assets/config/config.json').pipe(mergeMap(data =>
      http.get<any>(data.baseUrl + 'config/app').pipe(map(m => {
         m.baseUrl == data.baseUrl;
         configService.setData(m);
         this.globalConfig = <GlobalConfig>{
         baseUrl: configService.getData()["baseUrl"],
         language: configService.getData()["language"]}
                })))).subscribe();

and unit test to :

    mockGlobalConfig = new GlobalConfigService(httpClientSpy, ConfigServiceSpy);  
 expect(httpClientSpy.get.calls.count()).withContext('two call').toBe(2);

and error changed to : Cannot read properties of undefined (reading 'pipe')