Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 5 unit testing http response

I'm trying to unit test my http.get/post/etc responses.

I found this tutorial that was extremely helpful: https://medium.com/spektrakel-blog/angular-testing-snippets-httpclient-d1dc2f035eb8

Going through and following that, I've configured my unit tests and I'm able to get everything working, but there's one part that I have that is inconsistent with the tutorial...

In the tutorial, it shows to test the service login function like this:

 it(`should emit 'true' for 200 Ok`, async(inject([HttpClientFeatureService, HttpTestingController],
    (service: HttpClientFeatureService, backend: HttpTestingController) => {
      service.login('foo', 'bar').subscribe((next) => {
        expect(next).toBeTruthy();
      });

      backend.expectOne('auth/login').flush(null, { status: 200, statusText: 'Ok' });
  })));

And here's the actual method on the service that is being tested:

login(user: string, password: string): Observable<boolean> {
    const body = new HttpParams()
      .set(`user`, user)
      .set(`password`, password);
    const headers = new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' });

    return this.http.post(`auth/login`, body.toString(), { headers, observe: 'response' })
      .map((res: HttpResponse<Object>) => res.ok)
      .catch((err: any) => Observable.of(false));
  }

Here's my login function:

login(username: string, password: string): Observable<any> {
    this.loggingService.log('LoginService | login | username: ' + username + '; password: xxxxx');

    return this.http.post(this.loginUrl, { username: username, password: password })
        .map((response: any) => {
            console.log('response: ' + JSON.stringify(response));

            if (response && response.length > 0) {
                return response;
            } else {
                return this.parseErrorResponse(response);
            }
        });
}

And here's my unit test:

it('login should return a valid JWT', async(inject([LoginService, HttpTestingController], (service: LoginService, backend: HttpTestingController) => {
    service.login('user', 'password').subscribe((next) => {
        expect(next).toEqual('asdfasdfasdf');
    });

    backend.expectOne(environment.authenticationServiceBaseUrl + 'api/login')
        .flush('asdfasdfasdf', { status: 200, statusText: 'Ok' });
})));

You'll notice the difference here is in the map response section. My version is getting back just a string from the unit test's http.post call, while the example shows that it's returning an HttpResponse object and is just checking that the statusText property is equal to 'Ok'.

Why is my version returning just the string, while the examples version is returning the actual HttpResponse (which includes status and statusText)? I WANT the tutorial version here...

The example shows that it returns null in the body of the response via the flush function call, while I had to add my dummy JWT value in there in order to get my test to pass. Even when I specify that as null to be like the test, then the response that I get in the unit test is null.

Where am I going wrong here?

like image 563
ganders Avatar asked Dec 21 '17 16:12

ganders


1 Answers

The tutorial uses observe: 'response', which means that events emitted by the returned observable are responses, and not just the body.

This is covered in the http guide.

like image 146
JB Nizet Avatar answered Nov 18 '22 04:11

JB Nizet