Как правильно unit test jQuery.ajax() promises использовать Jasmine и/или Sinon?
У меня есть довольно простая функция, которая возвращает jQuery.ajax() как таковое:
CLAW.controls.validateLocation = function(val, $inputEl) {
return $.ajax({
url: locationServiceUrl + 'ValidateLocation/',
data: {
'locationName': val
},
beforeSend: function() {
$inputEl.addClass('busy');
}
}).done(function(result) {
// some success clauses
}).fail(function(result) {
// some failure clauses
}).always(function() {
// some always clauses
});
}
По большей части этот новый интерфейс promises работает как сон и устраняет пирамиды обратного вызова при использовании jQuery.ajax() отлично. Тем не менее, я не могу для жизни понять, как правильно тестировать эти promises с помощью Jasmine и/или Sinon:
-
Вся документация Sinon предполагает, что вы используете старую школу
обратные вызовы; Я не вижу ни одного примера того, как использовать его с
promises/deferreds
-
При попытке использовать шпионаж Jasmine или Sinon для шпионажа на $.ajax,
шпион эффективно переписывает обещание, поэтому его done
, fail
,
и always
больше не существует в функции ajax, поэтому обещание никогда не решает и вместо этого бросает ошибку
Мне бы очень понравился пример или два из того, как проверить эти новые jQuery.ajax() promises с вышеупомянутыми тестовыми библиотеками. Я довольно сильно искал "сеть" и на самом деле ничего не сделал. Один ресурс, который я нашел, упоминается с помощью Jasmine.ajax, но я хотел бы избежать этого, если это возможно, потому что Sinon предоставляет большинство тех же возможностей из коробки.
Ответы
Ответ 1
На самом деле это не так сложно. Достаточно вернуть обещание и решить его в соответствии с вашим делом.
Например:
spyOn($, 'ajax').andCallFake(function (req) {
var d = $.Deferred();
d.resolve(data_you_expect);
return d.promise();
});
для успеха, или
spyOn($, 'ajax').andCallFake(function (req) {
var d = $.Deferred();
d.reject(fail_result);
return d.promise();
});
для отказа.
Для Jasmine 2.0 синтаксис слегка изменился:
spyOn($, 'ajax').and.callFake(function (req) {});
метод .andCallFake() не существует в Jasmine 2.0
Ответ 2
что-то вдоль этих строк/с синонами и jQuery отложенными
ajaxStub = sinon.stub($, "ajax");
function okResponse() {
var d = $.Deferred();
d.resolve( { username: "testuser", userid: "userid", success: true } );
return d.promise();
};
function errorResponse() {
var d = $.Deferred();
d.reject({},{},"could not complete");
return d.promise();
};
ajaxStub.returns(okResponse());
ajaxStub.returns(errorResponse());
Ответ 3
Здесь более простой подход с помощью только javascript.
quoteSnapshots: function (symbol, streamId) {
var FakeDeferred = function () {
this.error = function (fn) {
if (symbol.toLowerCase() === 'bad-symbol') {
fn({Error: 'test'});
}
return this;
};
this.data = function (fn) {
if (symbol.toLowerCase() !== 'bad-symbol') {
fn({});
}
return this;
};
};
return new FakeDeferred();
}
Операторы if внутри каждого обратного вызова - это то, что я использую в своем тесте для успешного выполнения или выполнения ошибки.
Ответ 4
Решение, данное @ggozad, не будет работать, если вы используете такие вещи, как .complete()
.
Но, ура, жасмин сделал плагин, чтобы сделать именно это: http://jasmine.github.io/2.0/ajax.html
beforeEach(function() {
jasmine.Ajax.install();
});
afterEach(function() {
jasmine.Ajax.uninstall();
});
//in your tests
expect(jasmine.Ajax.requests.mostRecent().url).toBe('/some/cool/url');