Sinon: fake XHR doesn't work with JSDOM because Sinon is looking at different global

Created on 27 Apr 2016  路  6Comments  路  Source: sinonjs/sinon

  • Sinon version : 1.17.3 (same error also present in 34fddc02e0af513eeb067ec981e3aeb6eaad283c which is a more recent commit)
  • Environment : Node 4.4.0
  • Other libraries you are using: JSDOM 8.4.0

What did you expect to happen?
We are using JSDOM with Sinon, but Sinon's fake xml_http_request does not intercept requests or override window.XMLHttpRequest. In 1.17.3, I can fix this issue by adding a certain line of code to fake_xml_http_request (at about line 676):

        if (sinonXhr.supportsXHR) {
            global.XMLHttpRequest = FakeXMLHttpRequest;
            global.window.XMLHttpRequest = FakeXMLHttpRequest; //Line of code that fixes issue
        }

for a proposed fix there could be a feature check for global.window, and then override global.window.XMLHttpRequest (and restore it) if it's present?

Most helpful comment

@Jokero This does not seem like a problem. You are mixing two different domains and expect it to work as one. You are loading Sinon into a server environment, but you are trying to use that to test the sandbox of a fake browser. If you load Sinon into the jsdom browser environment you will see that it is working as expected:

var jsdom = require("jsdom");
var fs = require("fs");
var sinonBrowserBuild = fs.readFileSync("sinon-1.17.3.js", "utf-8");

jsdom.env({
  url: "http://google.com/",
  src: [sinonBrowserBuild],
  done: function (err, window) {
      var orgXhr =  window.XMLHttpRequest;
      console.log( "isFake?", window.XMLHttpRequest !== orgXhr ); // false
      window.sinon.useFakeXMLHttpRequest();
      console.log( "isFake?", window.XMLHttpRequest !== orgXhr ); // true
  }
});

Not sure how you setup your tests, though.

All 6 comments

@rayvnera I think that fix seems reasonable. Would you care to create a PR?

@fatso83 After having thought about it, I am unsure whether this is a Sinon issue as I originally thought, or just caused by a misuse of JSDom. I'd rather not make the change now since I am not convinced that it is necessary or desirable -- I suspect that we're using JSDom in a way that it's not intended to be used, and that is the cause of the problem.

OK, closing. Reopen if necessary.

I also have issue with FakeXMLHttpRequest and window/global. I want to test some ajax client side code (jquery is used) on nodejs with jsdom and sinon.
The problem is that jquery uses window.XMLHttpRequest internally but sinon replaces global.XMLHttpRequest. So to work around this I should override window.XMLHttpRequest in tests:

before(function() {
    this.xhr = sinon.useFakeXMLHttpRequest();
    window.XMLHttpRequest = global.XMLHttpRequest; // replace by fake XHR
});

after(function() {
    this.xhr.restore();
    window.XMLHttpRequest = global.XMLHttpRequest; // restore original XHR
});

It can be fixed in fake_xml_http_request.js and other files in this way:

(function (sinonGlobal, global) {
// ...
}(
    typeof sinon === "object" && sinon,
    global && global.window || global || self // we check global.window first
    // typeof global !== "undefined" ? global : self
));

@Jokero This does not seem like a problem. You are mixing two different domains and expect it to work as one. You are loading Sinon into a server environment, but you are trying to use that to test the sandbox of a fake browser. If you load Sinon into the jsdom browser environment you will see that it is working as expected:

var jsdom = require("jsdom");
var fs = require("fs");
var sinonBrowserBuild = fs.readFileSync("sinon-1.17.3.js", "utf-8");

jsdom.env({
  url: "http://google.com/",
  src: [sinonBrowserBuild],
  done: function (err, window) {
      var orgXhr =  window.XMLHttpRequest;
      console.log( "isFake?", window.XMLHttpRequest !== orgXhr ); // false
      window.sinon.useFakeXMLHttpRequest();
      console.log( "isFake?", window.XMLHttpRequest !== orgXhr ); // true
  }
});

Not sure how you setup your tests, though.

I use synchronous way to get window like this

var jsdom = require("jsdom").jsdom;
var document = jsdom("hello world");
var window = document.defaultView;

global.window = window;

And all these actions are made in required by mocha file (before all tests). So when I use sinon I need a way to specify global object to it. In my case it is not global, it should be global.window.

Maybe solution can be like in jquery (example from https://www.npmjs.com/package/jquery):

require("jsdom").env("", function(err, window) {
    if (err) {
        console.error(err);
        return;
    }

    var $ = require("jquery")(window);
});

Here we can specify our own global object

Was this page helpful?
0 / 5 - 0 ratings