在节点环境中存根 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);
);

您可以获得非常有创意的模拟超时、延迟、404401。因为您仍将使用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提交

jQuery ajax url 参数 drupal 服务器

HTTP 错误 405.0 - 不允许使用 Jquery ajax get 的方法

从节点 JavaScript 返回到 jQuery 的 Ajax 调用落在错误函数上

仅在 Firefox 中的 JQuery AJAX 异常:“无法在层次结构中的指定点插入节点”(HierarchyRequestError)