dimanche 26 janvier 2020

Angular 8 unit test service with forkjoin multiple parallel API calls

I am trying to write unit tests (Jasmine and Karma) for a service and a component whose aim is to perform two API calls to the Star Wars API (more info at https://swapi.co/) with two different URLS, to get people and starships data. Both calls are returned simultaneously with a forkJoin.

My App component calls the ApiService to perform two calls as follows:

APP COMPONENT:

import {Component, OnInit} from '@angular/core';
import {ApiService} from '../services/api.service';

export class AppComponent implements OnInit {

  constructor(private apiService: ApiService) {}

onGetData() {
    this.apiService.getData().subscribe((data: any) => {

      this.peopleData = data[0];
      this.starshipData = data[1];

     });

  }

API SERVICE:

import {HttpClient} from '@angular/common/http';

export class ApiService {
  constructor(private http: HttpClient) {}

  getData(): Observable<any[]> {
    const randomPeoplePage = Math.floor(Math.random() * 9) + 1;
    const peopleUrl = `https://swapi.co/api/people/?page=${randomPeoplePage}`;

    const randomStarshipsPage = Math.floor(Math.random() * 4) + 1;
    const starshipsUrl = `https://swapi.co/api/starships/?page=${randomStarshipsPage}`;

    const peopleProm = this.http.get(peopleUrl);
    const starshipProm = this.http.get(starshipsUrl);

    return forkJoin([peopleProm, starshipProm]);

  }
}

I am fairly inexperienced with testing, especially on how to test API calls properly. I have been trying different solutions for the past couple of days, something like this:

 it('should return an Observable', () => {
    const randomPeoplePage = Math.floor(Math.random() * 9) + 1;
    const randomStarshipsPage = Math.floor(Math.random() * 4) + 1;


    const dummyData = [
      {
        count: 87,
        next: `https://swapi.co/api/people/?page=${randomPeoplePage + 1}` || null,
        previous: `https://swapi.co/api/people/?page=${randomPeoplePage - 1}` || null,
        results: new Array(87)
      },
      {
        count: 37,
        next: `https://swapi.co/api/starships/?page=${randomStarshipsPage + 1}` || null,
        previous: `https://swapi.co/api/starships/?page=${randomStarshipsPage - 1}` || null,
        results: new Array(37)
      }
    ];

    service.getData().subscribe(data => {
      expect(data.length).toBe(2);
      expect(data).toEqual(dummyData);

      const peopleReq = httpMock.expectOne(`https://swapi.co/api/people/?page=${randomPeoplePage}`);
      const starshipReq = httpMock.expectOne(`https://swapi.co/api/starships/?page=${randomStarshipsPage}`);

      forkJoin([peopleReq, starshipReq]).subscribe(() => {
        expect(peopleReq.request.method).toBe('GET');
        expect(starshipReq .request.method).toBe('GET');
      })

      peopleReq.flush(dummyData[0]);
      starshipReq.flush(dummyData[1]);

    });


  });
});

but this test isn't passing and I am really not sure why or what should I look into. Do I need to test the API calls in the api.service.spec.ts or in the app.component.spec.ts? How do I simulate the return? Should I test them singularly? This is an 'academic' test, therefore any hint for best practice is welcome.

Thanks a lot!

Aucun commentaire:

Enregistrer un commentaire