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

Как правильно 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 предоставляет большинство тех же возможностей из коробки.

4b9b3361

Ответ 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');