Search code examples
angularjasmine

Jasmine spy object can't match calls with Date object


I am writing a test to mock some data being returned by my service. The call takes in a Date object as an argument since it returns data over a period of time. I am making this service call multiple times with different dates and would like to return a specific response for each date.

My current structure is something like this:

mockMyService = jasmine.createSpyObj<MyService>('mockMyService', ['getData']);
...
mockMyService.getData.withArgs(dateObj1, ...).and.returnValue(response);
mockMyService.getData.withArgs(dateObj2, ...).and.returnValue(response);
etc...

My issue is that even after verifying that the calls to my service use the same dates as I am expecting, I get an error saying that my spy received calls that didn't have an assigned strategy.

I'm using a describeWithDate to ensure that the Date objects are consistent between my tests. From my research I feel like the issue is related to the spy not being able to match the Date objects correctly. (All solutions to matching Date objects point to having to make a custom function to verify the dates in ISO string form). Is there a way for me to define a custom matcher to be used by the withArgs() call so it can use my mocked responses?

First post! Any help appreciated :)


Solution

  • I am thinking the withArgs only works with primitives (number, string, booleans) and not object types because they don't get a match because object equality of objects that are equal but in different areas of memory, returns false (new Date() === new Date(); (false), {} === {}; (false), [] === [] (false)).

    What I would do if I were you, I would use the callFake.

    mockMyService.getData.and.callFake((date, other, args) => {
       if (date.toISOString() === .....) {
          return thisResponse;
       } else {
          return thatResponse;
       }
    });
    

    callFake assigns a new function to the spy and based on the arguments, we can return different values.

    Looking at your case, you always return response so I think you can even get by with:

    mockMyService.getData.and.returnValue(response);
    

    That way, we will return response regardless of the arguments.