在节点环境中存根 jQuery.ajax (jQuery 2.x)
Posted
技术标签:
【中文标题】在节点环境中存根 jQuery.ajax (jQuery 2.x)【英文标题】:Stubbing jQuery.ajax in node environment (jQuery 2.x) 【发布时间】:2015-07-08 19:35:42 【问题描述】:我正在尝试运行一些需要存根 jQuery.ajax
的测试。我正在使用 SinonJS 来做到这一点,它曾经可以在旧版本的 jQuery (1.x) 上正常工作
var $ = require('jquery');
var sinon = require("sinon");
sinon.stub($, "ajax"); // this worked because $.ajax is defined
但是,在升级到 jQuery 2.x 之后,当我需要模块中的 jquery 才能运行时,我必须包含一个窗口环境。我正在使用jsdom
来完成此操作:
var document = require('jsdom').jsdom(),
window = document.parentWindow,
$ = require('jquery')(window);
问题 $.ajax
现在未定义。我怀疑是因为现在它返回绑定到特定元素但不完全确定的 jQuery 对象。有谁知道为什么以及如何解决这个问题?
编辑我的一个不在 SO 上的朋友指出,如果我们将 window
附加到全局,我们可以获得普通的 jquery 对象而不是工厂
global.window = require('jsdom').jsdom().parentWindow;
var $ = require('jquery'); // this works as $.ajax is now defined
我不喜欢将窗口附加到全局,因为它会影响某些类型检查窗口的插件。不是阻止程序,但我很想看看是否有其他方法可以解决这个问题。
【问题讨论】:
JSDom 适用于 io.js 而不是“已弃用”的环境(如节点),所以也许更新你的后端会解决它。 @BenjaminGruenbaum 我很想成为我现在必须坚持使用节点。我将jsdom
固定到 3.x,所以这应该不是问题。
你看到***.com/a/8916217/1348195了吗?
@BenjaminGruenbaum 我做到了。该问题已定义$.ajax
。它只是不工作。我没有将此函数绑定到我的 jQuery 对象。
为什么要使用 jquery ajax ? Request 更简单。
【参考方案1】:
我可以发誓,在阅读 jquery 源代码后,我在提出问题的那天尝试了这个,但它没有用。我刚才又试了一次,它正在工作。
tl;dr jQuery 将 $ 附加到浏览器模拟器的窗口命名空间。
var document = require('jsdom').jsdom(),
window = document.parentWindow;
require('jquery')(window);
var $ = window.$;
希望它对其他人有用。
【讨论】:
【参考方案2】:虽然 Stubs 很好,但它们不如 Fakes,而 Fakes 不如 Mocks。我建议使用 Sinon 更有趣的功能来创建 Fakes。
您可以伪造XMLHttpRequest
和/或XMLHttpResponse
,而不是存根window.$
var xhr, requests;
before(function ()
xhr = sinon.useFakeXMLHttpRequest();
requests = [];
xhr.onCreate = function (req) requests.push(req); ;
);
after(function ()
// Like before we must clean up when tampering with globals.
xhr.restore();
);
it("makes a GET request for todo items", function ()
getTodos(42, sinon.spy());
assert.equals(requests.length, 1);
assert.match(requests[0].url, "/todo/42/items");
);
或者你甚至可以模拟一个服务器
var server;
before(function () server = sinon.fakeServer.create(); );
after(function () server.restore(); );
it("calls callback with deserialized data", function ()
var callback = sinon.spy();
getTodos(42, callback);
// This is part of the FakeXMLHttpRequest API
server.requests[0].respond(
200,
"Content-Type": "application/json" ,
JSON.stringify([ id: 1, text: "Provide examples", done: true ])
);
assert(callback.calledOnce);
);
您可以获得非常有创意的模拟超时、延迟、404、401。因为您仍将使用JQuery.Ajax
对象库,同时注入增强请求和响应的间谍,您可以创建更真实、更健壮的测试,而不是必须存根所有可能性。
【讨论】:
谢谢!我确实在代码的其他地方使用了假和模拟服务器。对于更简单的测试,我只是将它们存根。这样更快:) @LimH.,啊哈。在那种情况下,我的回答是不必要的。您的需求只是语法上的。 公平地说,这个问题写得有点糟糕。我与 Sinon 中的存根无关,也与 jQuery 如何在 2.x 中更改其导出接口有关:D 但我非常感谢您抽出时间来写下您的答案。它确实解决了这个问题,虽然不是我一直在寻找的方式^ ^【参考方案3】:你有几个选择在节点中做请求:
1) 使用 jquery
var $ = require('jquery')(require("jsdom").jsdom().parentWindow);
// now $.ajax works well
2) 使用 npm 请求 https://www.npmjs.com/package/request
3) 使用原生对象 XHR
我测试了这三个选项,最后我使用了包请求(以避免像 jquery + jsdom 这样的额外包)和原生 XHR。
【讨论】:
嘿,谢谢,但我正在使用在节点上运行的工具测试客户端代码。我不是在测试服务器代码。你的选择1也是错误的。请阅读问题以上是关于在节点环境中存根 jQuery.ajax (jQuery 2.x)的主要内容,如果未能解决你的问题,请参考以下文章
laravel 4持续数据正在进行 - jquery ajax提交
laravel 4持续数据正在进行 - jquery ajax提交
HTTP 错误 405.0 - 不允许使用 Jquery ajax get 的方法
从节点 JavaScript 返回到 jQuery 的 Ajax 调用落在错误函数上
仅在 Firefox 中的 JQuery AJAX 异常:“无法在层次结构中的指定点插入节点”(HierarchyRequestError)