2

I am trying to test a fairly simple JavaScript function in Jasmine, however the first statement is throwing an error for being undefined.

myClass.prototype.functiontoBeTested = function() {
var x = this.method()
...
}

The above throws an error in Jasmine as method is not a function and is undefined. The prototype is altered earlier to have this method, and out of curiosity I assigned this method to my test object in the spec itself as such:

myObject.method = function(){return mockResults;};

So I decided to log this to the console and instead of it being my object, I see Window {top: Window, location: Location, document: document, window: Window, external: Object…} which doesn't seem right. I've had this issue before with testing a function in Jasmine that used this but just changed the source code to refer to the object by name since the function was being assigned to something within the closure. I can't do that in this case, and I'm curious why this is referring to something unexpected (at least to me).

Edit: Some details on what the test case looks like as requested:

it("updates the control count", function(){
    var mockResults = { ... };
    myObject.method = function() {return mockResults;};
    expect(myObject.method).not.toThrow();
});

Right now I'm just trying to get the method to execute to completion during the test. The function to be tested updates the text on some HTML components, I'll work on verifying those once I can get it to actually run. The method that is causing an error is the first line of the function, and is simply an accessor method for the object being called. In actual execution, var x = this.method() runs without issue. When testing in jasmine var x = this.method() throws an error because method() is undefined for this. Instead of this referring to the calling object, it is referring to the window. This doesn't happen live, but only during testing with Jasmine. This method is undefined even when I forcibly define it for the test object just prior to execution in the test as above. That's when I decided to log this to console in the source code and realized it isn't referring to what I would have expected it to refer to.

Michael
  • 668
  • 5
  • 13
  • Could you please post some code how you test your class? – Michael Radionov Jun 12 '15 at 10:18
  • Sure, I'll add it to the original question. – Michael Jun 12 '15 at 13:38
  • Here is how I see it should work http://plnkr.co/edit/wYhw9d0PdtppLrsbZqQb?p=preview from the description. Are there any specific differences in comparison with your original test? – Michael Radionov Jun 12 '15 at 14:00
  • That is how I would expect it to work, I just want to clarify that I'm only mocking the method as a troubleshooting step in the test. I would prefer not to be overriding it in my test case. Your Plunker example is essentially what is happening in my code, except the function to be tested throws an error as method is undefined for `this` at run time. – Michael Jun 12 '15 at 14:08
  • @JamesThorpe Your ordering probably makes more sense, but it still had an issue with coming out undefined. What Michael Radinov posted ended up solving the issue for me. I think the bigger lesson here for me is that I shouldn't be relying on `toThrow` for my unit tests so much. – Michael Jun 12 '15 at 14:38

1 Answers1

0

In JavaScript this for a method depends on the context it was called from. When you do a call myObject.method(), then method was called from the context of myObject, therefore this is myObject.

When you pass your function to Jasmine toThrow matcher, it calls it as it was passed (see source code):

try {
    actual();
} catch (e) {
   // ....
}

Here, actual() is a call of your method. It has no any specific context, so by default it will be called from window context.

Solution is to explicitly bind you method to myObject like the following:

expect(myObject.method.bind(myObject)).not.toThrow();

Credits to questions, you can find more details there:

Community
  • 1
  • 1
Michael Radionov
  • 12,859
  • 1
  • 55
  • 72
  • This was it, thank you. I'm going to add this to my team's wiki for unit testing with Jasmine, I doubt I'll be the only person to ever get caught by this. – Michael Jun 12 '15 at 14:34