Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jasmine mock window object

How do I mock window object? I'm doing firefox extension and I want to use jasmine for javascript testing.

In my javascript I have

  function submit() { ... var url = window.arguments[0]; ... }  

Obviously, I have to mock window.arguments[0] in jasmine because that object doesn't exists if not passing any parameter from window.openDialog

This is my attempt to mock it with "with"

  it("should submit to server", function() {          var localContext = {             "window": {                 arguments: ["http://localhost"]             }          }          with(localContext);  

But I still get this error TypeError: Cannot read property '0' of undefined, it's like when the test is run window.arguments[0] gets wiped out with the real window, because if I do

window.arguments[0]

inside the test, it prints out "http://localhost" correctly. but when it comes to submit() method it shows the error that window.argument is undefined.

like image 483
toy Avatar asked Jan 19 '12 00:01

toy


2 Answers

The problem is that you just overwrite a property of the window object. And if you can do that, the browser can do that as well. So mocking a function or property of a global object that everyone can access isn't a good idea in general, because you can never be sure that your changes will be there when you try to access them.

Which brings me to dependency injection. Its a common pattern to make your code unit testable, with a focus on unit. Whats does it mean. When ever you create a new object or access a global object, you're not only testing your unit functionality, but also the functionality of your newly created or global object. To prepend that, you not create the new objects in your unit, but pass them into. Normally you would to this in the constructor, but as in JavaScript function are objects with the function body as constructor, you can also pass the dependencies simply into your function.

So in your case, the function depends on the global window object. So instead of trying to access the global window object, pass it as a parameter into your function. Doing it this way you can pass in the window object in your production code and a simple JavaScript object with an arguments atribute into your test:

function youWannaTest(w){     console.log(w.arguments[0]); } 

In your extension call the function like this:

youWannaTest(window); 

In your test call the function like this:

youWannaTest({arguments: ['someValue']}); 
like image 68
Andreas Köberle Avatar answered Nov 15 '22 22:11

Andreas Köberle


I also think dependency injection is the cleanest solution.

Your JS:

function submit(_window) {     _window = _window || window     ...     var url = _window.arguments[0];     ... } 

Your unit tests:

it('works like a dream', function () {     var _window = { arguments: ['url'] }     expect(submit(_window)).toBeTotallyAwesome() }) 
like image 20
A.Williams Avatar answered Nov 15 '22 22:11

A.Williams