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
Я не поклонник прикрепления окна к глобальному, так как это повлияет на некоторые из плагинов, которые вводят контрольное окно. Не блокатор, но мне бы хотелось посмотреть, есть ли другой способ обойти эту проблему.
Ответы
Ответ 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.