Did My Jasmine Expect Method Get Called?

Inspecting expectations in Jasmine

When unit testing with Jasmine, expect() calls are not mandatory. That is, calling expect() at least once is not enforced by Jasmine. I recently ran into a problem which caused me to ask myself “did that expect method get called?”. I couldn’t count on Jasmine for this – in fact, my tests pass whether I include the expect() call or comment it out! So I went digging..

I determined that I could simply create spies for my expect() calls. This is an easy way to leverage Jasmine to inspect your tests. Simply create your spy:

const expectSpy: jasmine.Spy =
   spyOn(window,'expect').and.callThrough();

I am using TypeScript for my unit tests. Since the expect() method is global and I am running my tests in a browser, I use the window object directly. There are ways to obtain the global object without this sort of hard-coding but, that is besides the point.

Moving on, the expect() calls must work properly so and.callThrough() is called. This is important. Without including and.callThrough(), your tests will fail because, rather than Jasmine’s expect() execution, you will be limited to a jasmine.Spy.

Here is a more complete example of a test with an expect spy – slightly modified from a sample Angular 2 application I have been working on:

it('should trigger on selection change', async(() => {
  const expectSpy: jasmine.Spy =
    spyOn(window,'expect').and.callThrough();

  const triggerSpy = spyOn(component, 'triggerThemeChanged');

  const select =
    fixture.debugElement.query(By.css('select.theme-selector'));

  dispatchEvent(select.nativeElement, 'change');

  fixture.whenStable().then(() => {
    expect(triggerSpy).toHaveBeenCalledTimes(1);
  }).then(() => {
    expect(expectSpy).toHaveBeenCalledTimes(2);
  });
}));

There are a few things about this test that are not the point of this article – what the heck is async() and the apparent improper use of dispatchEvent()? The important bits are the use of Promises as implied by the use of then() callbacks, the creation of the expect spy, and the inspection of the expect spy.

The test creates the expect spy and then uses expect() as usual within the test until it finally inspects the expect spy. Remember, the inspection of the expect spy counts as an expect() call! This is why expect(expectSpy).toHaveBeenCalledTimes(2) is called with 2 rather than 1.

I stopped at the call count. This test could be extended to further leverage the Jasmine API by looking at expectSpy.calls with other handy methods to make sure the expect() calls were made properly. I’ll leave that for an exercise for the reader. Just make sure your testing, at a minimum, covers the scope of your problem.

If you have had similar issues or have explored this in more depth I would be very interested in hearing about your journey! Comments are welcomed and appreciated.