2

I am trying to write a unit test where I want to verify that a ajax call has been made. The code is simple :

it('test spycall',()=>{
spyOn($,"ajax");
//my method call which in turns use     ajax
MyFunc();
expect($.ajax.calls.mostRecent().args[0]["url"].toEqual("myurl");
});

The error that I get :

Property 'calls' doesn't exist on type '{settings:jqueryAjaxSettings):jQueryXHR;(url:string, settings?:JQueryAjaxSettings}

rrauenza
  • 6,285
  • 4
  • 32
  • 57
TypeScripter
  • 879
  • 2
  • 10
  • 23
  • It seems that your typescript definition file of JQuery doesn't fully describe $.ajax. What version of JQuery are you using and what kind of .d.ts file are you referencing for its type definitions? – Georg Grab Jun 23 '16 at 18:20
  • It says for jQuery 1.10.x /2.0.x. I have it installed via tsd. – TypeScripter Jun 23 '16 at 18:25

2 Answers2

1

$.ajax.calls, among others, is part of the Jasmine testing framework, not JQuery itself (As you know, Jasmine (or rather, Jasmine-Jquery, the plugin you're using) is adding certain debugging functions to JQuery's prototype in order to, well, be able to test ajax calls).

The bad part is that your .d.ts typescript definition file, the file that acts as an interface between typescript and pure JS libraries isn't aware of Jasmine's functions.

There are several ways you could approach fixing this, like

  • looking if someone has adjusted the JQuery .d.ts file for Jasmine's functions or
  • creating the new .d.ts file yourself by modifying the original one or, (what I would be doing)
  • overwriting the typescript definition by declaring $.ajax as any, or not including the typescript definition at all in your testing codebase and declaring $ as any.
Georg Grab
  • 2,271
  • 1
  • 18
  • 28
  • I did use the dirty way of overriding it (had to use $, $.ajax:any is not allowed) but wanted to have a proper syntax. I am quite amazed to see that no one has faced this issue before because I coukd nt find a matching .d.ts file yet. – TypeScripter Jun 23 '16 at 19:43
  • 1
    And there probably never will be. I like your question because it demonstrates a significant difference between JS and TS. Type-aware languages just don't expect something like this (a library monkey-patching the prototype of another libraries objects) to happen, even though this is a valid pattern in JS, which is why things like this will always happen when interfacing typescript and javascript. What Jasmine is doing here violates the Liskov subsitution principle on so many different levels! :) – Georg Grab Jun 23 '16 at 22:45
1

There are 2 ways to get rid of the error:

// 1
expect(($.ajax as any).calls.mostRecent().args[0].url).toEqual("myurl");

// 2
let ajaxSpy = spyOn($,"ajax");
expect(ajaxSpy.calls.mostRecent().args[0].url).toEqual("myurl");

You can also use partial matching:

expect(($.ajax as any).calls.mostRecent().args).toEqual([
  jasmine.objectContaining({url: "myurl"})
]);
alexeibs
  • 535
  • 3
  • 7