aRtoo
aRtoo

Reputation: 1892

Angular testing not invoking expectation resulting to "Spec has no expectation"

I have service that makes an HTTP call to my backend, I'm trying to test if it will get a users response, upon running the test I get a Spec has no expectation even though I have one inside a subscription. All of these test passes but 2 has an output of SPEC HAS NO EXPECTATION

here's my code:

describe('Auth Service Testing', () => {
  let httpClientSpy: { get: jasmine.Spy };
  let authServ: AuthService;
  let authAct: AuthActions;
  let userAct: UserActions;
  let checkoutAct: CheckoutActions;
  let productAct: ProductActions;
  let store: Store<any>;
  let localStorageServ: LocalStorageService;
  let authResponse;
  const expectedUserResponse = {
    users: [],
    count: 25,
    current_page: 1,
    pages: 2
  };

  beforeEach(() => {
    httpClientSpy = jasmine.createSpyObj('HttpClient', ['get']);
    authServ = new AuthService(
      <any>httpClientSpy,
      authAct,
      userAct,
      checkoutAct,
      productAct,
      store,
      localStorageServ
    );
  });

  it('should get users response', () => {
    httpClientSpy.get.and.returnValue(asyncData(expectedUserResponse));

    authServ.authorized().subscribe((users) => {
      authResponse = users;
      expect(users).toEqual(jasmine.objectContaining({ users: [] }));
    });

  });

  it('should equal to expected users response', () => {
    expect(authResponse).toEqual(expectedUserResponse);
  });

  it('should return null if theres an error', () => {
    httpClientSpy.get.and.returnValue(asyncError(expectedUserResponse));
    authServ
      .authorized()
      .subscribe(() => {}, (error) => expect(error).toBe(null));
  });
});

also, I followed the angular HTTP testing guide angular test I'm wondering if this is a bug or something else.

karma results:

Auth Service Testing
SPEC HAS NO EXPECTATIONS should return null if there's an error
SPEC HAS NO EXPECTATIONS should get users response
should equal to expected users response

UPDATE

The code that is missing is this expect(httpClientSpy.get.calls.count()).toBe(1); this is weird, I thought this call makes an http get request httpClientSpy.get.and.returnValue(asyncError(expectedUserResponse));

but on the error test on the guide, they don't have this though. Can someone shed light on this one?

much love from North Korea. <3

Upvotes: 2

Views: 2995

Answers (1)

Reactgular
Reactgular

Reputation: 54771

It's really difficult to unit test an observable using a subscription. There are many edge cases where the unit test will pass, but should have failed. Even if you use the done() callback with a finiazlier or error handler.

Whenever an observable emits only one expected result, then you should use a promise instead.

  it('should get users response', async () => {
    httpClientSpy.get.and.returnValue(asyncData(expectedUserResponse));

    const users = await = authServ.authorized().toPromise();

    expect(users).toEqual(jasmine.objectContaining({ users: [] }));
  });

Whenever an observable emits multiple values, then you can convert to an array and still use a promise.

  it('should get users response', async () => {
    httpClientSpy.get.and.returnValue(asyncData(expectedUserResponse));

    const users = await = authServ.authorized().pipe(
        toArray()
    ).toPromise();

    expect(users).toEqual(jasmine.objectContaining([{ users: [] }]));
  });

The advantage of toPromise() is that it always resolves. Even if no values are emitted by the observable, and it fails the unit test if any uncaught errors are thrown inside the observable.

Upvotes: 3

Related Questions