Can't use sinon.useFakeServer()

2,738 views
Skip to first unread message

Timothy Washington

unread,
Oct 14, 2011, 12:19:57 PM10/14/11
to sin...@googlegroups.com
Hey all, 

I'm trying to do headless development with Node(v0.5.10-pre) and Sinon(1.2.0). But in my .js file, I can't call 1) or 2), as the 'fakeServer' object is not defined on sinon. The best I can do is 3), but I'd like to start outside of the sandbox. 

  1. sinon.useFakeServer(); 
  2. sinon.fakeServer.create();
  3. sinon.sandbox.useFakeServer();


---> $ node spec/my_spec.js
var   vows = require('vows'),
      assert = require('assert'),
      sinon = require('sinon');

var requirejs = require('js/r.js'); 
...


# these lines work 
sinon.spy();
sinon.stub();
sinon.sandbox.useFakeServer();


# these lines fail 
var server = sinon.fakeServer.create();
sinon.useFakeServer();


Is there something I'm missing here? 


Thanks 
Tim 

Christian Johansen

unread,
Oct 14, 2011, 12:55:06 PM10/14/11
to sin...@googlegroups.com
Hi,

The fake XMLHttpRequest implementation is not included by default on Node, because Node doesn't natively provide that object. You can require it manually:

require("sinon/lib/sinon/util/fake_xml_http_request");
var fakeServer = require("sinon/lib/sinon/util/fake_server").fakeServer;

Then; fakeServer.create();

In order for this to work, XMLHttpRequest has to be defined up-front, so you might want:

global.XMLHttpRequest = function () {}

before those calls to require.

I realize that none of this is exactly ideal, but to be honest I hadn't considered the use-case for loading these things on Node. I'll look into providing a better API for it in 1.3.0.

Christian
--
MVH
Christian

Timothy Washington

unread,
Oct 14, 2011, 1:45:56 PM10/14/11
to sin...@googlegroups.com
Hey Christian, thanks for the feedback. 

I see what's going on, but the call to require 'fake_xml_http_request' fails in this case. 


---> CODE 
  1 
  2 var   vows = require('vows'),
  3       assert = require('assert');
  4 
  5 global.XMLHttpRequest = function () {}
  6 var sinon = require('sinon');
  7 var xhr = require("sinon/lib/sinon/util/fake_xml_http_request"); 
  8 var fakeServer = require("sinon/lib/sinon/util/fake_server").fakeServer;
  9 
 10 var requirejs = require('js/r.js');
 11 requirejs.config({
 12   nodeRequire: require,
 13   baseUrl: 'js',
 14 });



---> Exec ERROR 
$ node spec/storydesk_spec.js 

node.js:203
        throw e; // process.nextTick error, or 'error' event on first tick
              ^
ReferenceError: sinon is not defined
    at Object.<anonymous> (/usr/local/lib/node_modules/sinon/lib/sinon/util/fake_xml_http_request.js:20:1)
    at Module._compile (module.js:432:26)
    at Object..js (module.js:450:10)
    at Module.load (module.js:351:31)
    at Function._load (module.js:310:12)
    at Module.require (module.js:357:17)
    at require (module.js:368:17)
    at Object.<anonymous> (/var/www/<my_app>/spec/storydesk_spec.js:7:11)
    at Module._compile (module.js:432:26)
    at Object..js (module.js:450:10)




****>   If my code, line 6, reads "sinon = require('sinon');", I get a bit further... 
$ node spec/storydesk_spec.js 

ReferenceError: window is not defined
    at /usr/local/lib/node_modules/sinon/lib/sinon/util/fake_server.js:47:16
    at Object.<anonymous> (/usr/local/lib/node_modules/sinon/lib/sinon/util/fake_server.js:189:1)
    at Module._compile (module.js:432:26)
    ... 
    at Object.<anonymous> (/var/www/storydesk/editor/templates/spec/storydesk_spec.js:8:18)
    at Module._compile (module.js:432:26)



****>   based on the last error, if I instantiate a 'window = {}', I get a bit further, but it still fails with...
$ node spec/storydesk_spec.js 

TypeError: Cannot read property 'protocol' of undefined
    at /usr/local/lib/node_modules/sinon/lib/sinon/util/fake_server.js:48:41
    at Object.<anonymous> (/usr/local/lib/node_modules/sinon/lib/sinon/util/fake_server.js:189:1)
    ... 
    at Object.<anonymous> (/var/www/storydesk/editor/templates/spec/storydesk_spec.js:10:18)
    at Module._compile (module.js:432:26)


... It looks like fake_server is expecting a 'window' and 'window.location'. Is there something else that should be included? Am I on the right track here? 


Thanks
Tim 

Christian Johansen

unread,
Oct 15, 2011, 7:24:03 PM10/15/11
to sin...@googlegroups.com
This seems to be a bug in Sinon. This code fails in Node:

if (typeof sinon == "undefined") {
    this.sinon = {};
}

sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };

I'll have to make an effort of making the fake XHR stuff working properly on Node and do a release. Not quite sure when I get the time, feel free to submit patch.

Christian
--
MVH
Christian

Timothy Washington

unread,
Oct 16, 2011, 4:20:02 PM10/16/11
to sin...@googlegroups.com
Thanks again for the help Christian. I included 'zombiejs' and did the following to get past that point. Maybe it's a hint as to how that 'window' and 'xhr' object should work. I DID have to set the 'browser.window.location' in order to get the browser.window object instantiated / vivified / whatever. 


----> 
//** Hack to get a Window object for JQuery and Sinon
var zombie = require("zombie");
var browser = new zombie.Browser;
browser.window.location = "http://localhost:3000";
window = browser.window;


//** Hack to get Sinon working with NodeJS
sinon = require('sinon');
var xhr = require("sinon/lib/sinon/util/fake_xml_http_request");
var fakeServer = require("sinon/lib/sinon/util/fake_server").fakeServer;


HTH 
Tim 

Timothy Washington

unread,
Oct 16, 2011, 4:42:13 PM10/16/11
to sin...@googlegroups.com
But while I'm at it. I am still having trouble trying to get the fakeServer to respond to a backbone.Collection.fetch() call. I've tried binding to sync, fetch, but to no avail. 

Am I using a spy correctly? Perhaps there's something else I should be binding to? I'd love any ideas you have. 


----> 
var callback = sinon.spy();
fakeServer.respondWith( "GET", "/fu/bar", 
                        [ 200, { "Content-Type": "application/json" }, { "fu" : "bar" } ]);

var pages = new storydesk.models.Pages();
pages.bind('sync', callback); 
pages.fetch();

fakeServer.respond();


Cheers 
Tim 

Christian Johansen

unread,
Oct 18, 2011, 4:58:35 PM10/18/11
to sin...@googlegroups.com
The only error I see is that the last entry in the response array should be a string, not an object. In your case, slapping a JSON.stringify on it will help.

Christian
--
MVH
Christian

Timothy Washington

unread,
Oct 18, 2011, 7:59:37 PM10/18/11
to sin...@googlegroups.com
I tried that (with vows - A), but am still getting a connection refused B). Somehow Sinon's fakeServer is not binding to backbone's 'fetch'. Perhaps the node environment is futzing things up. I'll try stepping through this in a Chrome debugger. 


A) 
        topic: function() { 
    
          var callback = sinon.spy();
          var pages = new myapp.models.Pages();
          pages.bind('fetch', callback); 
          fakeServer.respondWith( "GET", "/story/getPages", 
                                  [ 200, { "Content-Type": "application/json" },
'{ "success": true, "pages": [ { "pageID": "B0237DC6-F038-11E0-8E5A-EF1C4824019B", "parentID": "root", "type": "cover", "layout": "1 Column", "title": "(This is the cover page)" }, { "pageID": "7998AC58-F039-11E0-BF5F-2E1E4824019B", "parentID": "B0237DC6-F038-11E0-8E5A-EF1C4824019B", "type": "tableOfContents", "layout": "1 Column", "title": "(This is the table of contents page)" }, ] }' ]);
    
          pages.fetch();
          fakeServer.respond();

          return pages;
        },


B) 
ubuntu@ubuntu-server:/var/www/storydesk/editor/static/presentation$ node spec/myapp_spec.js 
The "sys" module is now called "util". It should have a similar interface.
executing trial 1
BEFORE > Pages length > 0
AFTER > Pages length > 0
try 1 result[[]]
·teardown 1
 ✓ OK » 1 honored (0.007s)
XHR error { [Error: connect ECONNREFUSED]
  code: 'ECONNREFUSED',
  errno: 'ECONNREFUSED',
  syscall: 'connect' }
error: Loading resource: connect ECONNREFUSED - More:
Error: connect ECONNREFUSED
connect ECONNREFUSED Error: connect ECONNREFUSED
    at errnoException (net_uv.js:569:11)
    at Object.afterConnect [as oncomplete] (net_uv.js:560:18)


Thanks so far 
Tim 

Christian Johansen

unread,
Oct 19, 2011, 2:22:03 PM10/19/11
to sin...@googlegroups.com
I still spot a JSON error, try http://jsonlint.com/ There's a trailing comma. That may not be the problem, but it sure won't help you debug :)
--
MVH
Christian

Travis Kaufman

unread,
Jul 29, 2012, 11:47:59 PM7/29/12
to sin...@googlegroups.com, chri...@cjohansen.no
Hey I don't know if this is dead now but I just stumbled across this problem and this got useFakeXMLHttpRequest working for me without ZombieJS or anything else:

First in your project directory:
$ npm install xmlHttpRequest

then in your code:
var xmlHttpRequest = require('xmlHttpRequest');
var xhr = require('sinon/lib/sinon/util/fake_xml_http_request');

Thanks for the informative thread. Cheers!

Travis Kaufman

unread,
Jul 29, 2012, 11:51:17 PM7/29/12
to sin...@googlegroups.com, chri...@cjohansen.no
sorry, before you declare xhr put
var sinon = require('sinon')

Kevin Lamping

unread,
Aug 9, 2012, 12:16:44 PM8/9/12
to sin...@googlegroups.com, chri...@cjohansen.no
I think it needs to be:
npm install xmlhttprequest

I tried xmlHttpRequest and it says it's not in the NPM registry.

Devin Weaver

unread,
Jan 25, 2014, 11:30:41 PM1/25/14
to sin...@googlegroups.com, chri...@cjohansen.no
Do we really have to install a whole XMLHttpRequest module just to have it faked? How come FakeXMLHttpRequest can't stand on it's own?

I develop in Titanium and run my mocha tests via node against the titanium code who's API is mocked out by the mockti package. We have a method called Ti.Network.createHTTPClient which has the same object signature and behavior as the normal XMLHttpRequest object we love on the browser. However, sinon can not use this because it isn't called global.XMLHttpRequest. Again I am curious why sinon.FakeXMLHttpRequest is so tightly cupled to an XMLHttpRequest implementation and why it can not be included in the node package as a stand alone. A simple stub function could expose this:

sinon.stub(Ti.Network, "createHTTPClient").returnsFakeXMLHttpRequest();

And with the power of the fakeServer we could do some great mocked out testing.

If I wanted to add the above feature how would I best approach this? What parts of the XMLHttpRequest spec are tightly coupled to the FakeXMLHttpRequest? Is it even possible to have the FakeXMLHttpRequest ignore supportsXHR, or workingXHR variables?

Christian Johansen

unread,
Jan 27, 2014, 11:46:33 AM1/27/14
to sin...@googlegroups.com
Well, I'm all for loosening the coupling here so that this object could be
used regardless of the existence of a native XMLHttpRequest. What is
important however, is that when we are mirroring a native implementation we
mimic its behavior (including flaws) as much as possible.
Reply all
Reply to author
Forward
0 new messages