Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 6 unit testing a http get request

I have a component where I have a request in a function like:

getData():Observable<any>{
    return this._http.get('/app/data', {observe: 'response'});
}

It returns me an object array in subscription like:

[{name: 'a'}, {name: 'b'}]

or something similar.

I wanted to write a test that makes sure getData() calls http GET once with the proper url and the subscription returns something array-like.

My code:

...
    it('getData() should http GET names', () => {
        inject([HttpTestingController], (httpMock: HttpTestingController) => {

          const names = [{name: 'a'}, {name: 'b'}];

          component.getData().subscribe((res) => {
            expect(res).toEqual(names);
          });

          const req = httpMock.expectOne('/app/data');
          expect(req.request.method).toEqual("GET");
          req.flush(names);

          httpMock.verify();
        });
      });
...

I failed the test with this message: "Expected no open requests, found 1: GET /app/data"

like image 913
Bálint Réthy Avatar asked Dec 14 '22 14:12

Bálint Réthy


1 Answers

First off for good practices you should separate your component from making the request itself and use a Service instead as you will find it more cleaner in the longer run as your app grows for services to handle API requests.

This is another approach you can do for getting it to work with the HttpTestingController as I'm not quite sure why your inject of the controller is not working.

simply test the service instead or just structure your component the same approach on your component tests with this workaround.

get your data from the service by injecting it to the component.

Component:

@Component({
  selector: 'app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  constructor(private service: TestService)
}

Service:

@Injectable()
export class TestService {

  constructor(private http: HttpClient) { }

  getData(): Observable<any>{
    return this.http.get('/app/data');
  }

}

then test the service in this way instead, it's just as your component test but just using the service instead

Test:

describe('TestService', () => {

  let httpMock: HttpTestingController;
  let testService: TestService;

  beforeEach(() => {

    TestBed.configureTestingModule({
        imports: [ HttpClientTestingModule ],
        providers: [ TestService ]
    });

    testService = TestBed.get(TestService);
    httpMock = TestBed.get(HttpTestingController);

  });

  it('getData() should http GET names', () => {

    const names = [{name: 'a'}, {name: 'b'}];

    testService.getData().subscribe((res) => {
      expect(res).toEqual(names);
    });

    const req = httpMock.expectOne('/app/data');
    expect(req.request.method).toEqual("GET");
    req.flush(names);

    httpMock.verify();
  });

});

here is the test in action

like image 194
Lucho Avatar answered Dec 21 '22 19:12

Lucho