Angular HttpClient unit tests won't fail when comparing data inside of an asynchronous function

Issue

I’m trying to unit test a few simple GET requests and no matter what I do, I can’t get the tests to fail.

If I change the ('GET') to ('POST') it will fail, but all of the api data passes no matter what.

import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';

import { mockPhoneNumbers } from '../mocks/data/phoneNumbers.mock';
import { PhoneNumberApiService } from './phone-number-api.service';

describe('PhoneNumberApiService', () => {
  let service: PhoneNumberApiService;
  let httpTestingController: HttpTestingController;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [PhoneNumberApiService],
    });

    service = TestBed.get(PhoneNumberApiService);
    httpTestingController = TestBed.get(HttpTestingController);
  });

  afterEach(() => {
    // After every test, assert that there are no more pending requests.
    httpTestingController.verify();
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });

  it('should get the phone numbers successfully', () => {
    service
      .getPhoneNumbers()
      .subscribe(phoneNumbers => {
        expect(phoneNumbers).toEqual('bob');
        expect(phoneNumbers[0].id).toEqual('b8bfea4d-a26f-9e4e-cbd4-39eb69cdaa58');
        expect(phoneNumbers[1].friendlyName).toEqual('Dev Test');
      });

    const req = httpTestingController.expectOne('phoneNumbers');

    expect(req.request.method).toEqual('GET');

    req.flush(mockPhoneNumbers);
  });

  it('should get the phone number details successfully', () => {
    const { id: phoneNumberId } = mockPhoneNumbers[0];

    service
      .getPhoneNumberDetails(phoneNumberId)
      .subscribe(phoneNumber => expect(phoneNumber).toEqual(mockPhoneNumbers[0]));

    const req = httpTestingController.expectOne(`phoneNumbers/${phoneNumberId}`);

    expect(req.request.method).toEqual('GET');

    req.flush('bob');
  });
});

Surely flushing the request with the mock data and then expecting the mock data to be bob is wrong. In the bottom test, flushing the request with bob and expecting the data to be equal to the first phone number in the array should fail.

Solution

The problem about your tests is that you make your “it” functions and expects asynchronous without explicit telling jasmine that .

You need to use the done function in other to tell for the test waiting for something (check out in here a good tutorial about async test on jasmine)

Follows an example based on your code:

...
//Receive the done function like this
it('should get the phone numbers successfully', (done) => {
    service
      .getPhoneNumbers()
      .subscribe(phoneNumbers => {
        expect(phoneNumbers).toEqual('bob');
        expect(phoneNumbers[0].id).toEqual('b8bfea4d-a26f-9e4e-cbd4-39eb69cdaa58');
        expect(phoneNumbers[1].friendlyName).toEqual('Dev Test');
        //Tell the test that only in here all the work was done
        done();
      });
    const req = httpTestingController.expectOne('phoneNumbers');

    expect(req.request.method).toEqual('GET');

    req.flush(mockPhoneNumbers);
});
....

Also, to answer your guess, jest is a test runner and is build on top of jasmine framework (meaning the jest syntax is similar to jasmin, but not equal). But for this case I guess that usage of the done will solve your problem.

Answered By – Ricardo Rocha

Answer Checked By – Mary Flores (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.