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

1

0

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.

Boyla answered 21/1, 2019 at 18:6 Comment(3)
The assertion in the subscription only happens after the test has passed. Read up on the DoneFn, it's covered in angular.io/guide/testingLeukocyte
This is example is basically the same as the one used in the Angular docs for testing HttpClient. Did they forget to include something?Boyla
Okay, so adding done seems to cause the tests to fail. I wonder if this has something to do with using jest vs karma.Boyla
F
2

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.

Fluor answered 21/1, 2019 at 18:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.