Angular 5 unit testing http response

10,415

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.

Share:
10,415
ganders
Author by

ganders

I'm a software developer in Des Moines, IA. I love what I do, but wish I had more time to do it. Those darn kids get in the way...

Updated on June 04, 2022

Comments

  • ganders
    ganders almost 2 years

    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?