Подтвердить что ты не робот

Stubbing jQuery.ajax в среде node (jQuery 2.x)

Я пытаюсь запустить несколько тестов, требующих stubbing 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 теперь undefined. Я подозреваю, потому что теперь он возвращает объект jQuery, привязанный к определенному элементу, но не полностью уверен. Кто-нибудь знает, почему и как обойти это?

EDIT Мой друг, который не находится на SO, указал, что если мы присоединяем window к глобальному, мы можем получить простой объект jquery вместо factory

    global.window = require('jsdom').jsdom().parentWindow;
    var $ = require('jquery'); // this works as $.ajax is now defined

Я не поклонник прикрепления окна к глобальному, так как это повлияет на некоторые из плагинов, которые вводят контрольное окно. Не блокатор, но мне бы хотелось посмотреть, есть ли другой способ обойти эту проблему.

4b9b3361

Ответ 1

Я мог бы поклясться, что после чтения источника jquery я попробовал это в тот день, когда задал вопрос, но это не сработало. Я попробовал еще раз, и это работает.

tl; dr jQuery присоединяет $к пространству имен окна для эмулятора браузера.

var document    = require('jsdom').jsdom(),
    window      = document.parentWindow;
require('jquery')(window);
var $ = window.$;

Надеюсь, это полезно кому-то другому.

Ответ 2

В то время как Stubs хороши, они не так хороши, как Fakes, которые не так хороши, как Mocks. Я бы посоветовал использовать более интригующие функции Sinon для создания подделок.

Вместо того, чтобы обрезать window.$, вы можете подделать XMLHttpRequest и/или XMLHttpResponse

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);
});

Вы можете получить очень креативные, Mocking таймауты, задержки, 404, 401. Поскольку вы все еще будете использовать библиотеку объектов JQuery.Ajax, в то время как инъекции шпионов, которые дополняют запросы и ответы, вы можете создавать более аутентичные и надежные тесты с меньшими усилиями, чем если бы вам пришлось заглушить все возможности.

Ответ 3

У вас есть несколько вариантов выполнения запросов в node:

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.