Как проверить события JQuery AJAX с помощью Jasmine? - PullRequest
112 голосов
/ 12 января 2011

Я пытаюсь использовать Jasmine для написания некоторых спецификаций BDD для базовых запросов jQuery AJAX. В настоящее время я использую Жасмин в автономном режиме (т.е. через SpecRunner.html). Я настроил SpecRunner для загрузки jquery и других файлов .js. Есть идеи, почему следующее не работает? has_returned не стал правдой, даже подумал "яппи!" предупреждение отображается нормально.

describe("A jQuery ajax request should be able to fetch...", function() {

  it("an XML file from the filesystem", function() {
    $.ajax_get_xml_request = { has_returned : false };  
    // initiating the AJAX request
    $.ajax({ type: "GET", url: "addressbook_files/addressbookxml.xml", dataType: "xml",
             success: function(xml) { alert("yuppi!"); $.ajax_get_xml_request.has_returned = true; } }); 
    // waiting for has_returned to become true (timeout: 3s)
    waitsFor(function() { $.ajax_get_xml_request.has_returned; }, "the JQuery AJAX GET to return", 3000);
    // TODO: other tests might check size of XML file, whether it is valid XML
    expect($.ajax_get_xml_request.has_returned).toEqual(true);
  }); 

});

Как проверить, что колбэк был вызван? Будем весьма благодарны за любые ссылки на блоги / материалы, связанные с тестированием асинхронного jQuery с Jasmine.

Ответы [ 6 ]

230 голосов
/ 01 июня 2011

Я думаю, вы можете сделать два типа тестов:

  1. Модульные тесты, которые подделывают запрос AJAX (с использованием шпионов Jasmine), позволяя вам протестировать весь ваш код, который запускает непосредственно перед запросом AJAX и сразу после . Вы даже можете использовать Жасмин, чтобы подделать ответ от сервера. Эти тесты были бы быстрее - и им не нужно было бы обрабатывать асинхронное поведение - так как никакого реального AJAX не происходит.
  2. Интеграционные тесты, которые выполняют реальные запросы AJAX. Они должны быть асинхронными.

Жасмин может помочь вам выполнить оба вида тестов.

Вот пример того, как вы можете подделать AJAX-запрос, а затем написать модульный тест, чтобы убедиться, что поддельный AJAX-запрос шел по правильному URL:

it("should make an AJAX request to the correct URL", function() {
    spyOn($, "ajax");
    getProduct(123);
    expect($.ajax.mostRecentCall.args[0]["url"]).toEqual("/products/123");
});

function getProduct(id) {
    $.ajax({
        type: "GET",
        url: "/products/" + id,
        contentType: "application/json; charset=utf-8",
        dataType: "json"
    });
}

Для Жасмин 2.0 используйте вместо:

expect($.ajax.calls.mostRecent().args[0]["url"]).toEqual("/products/123");

как отмечено в этом ответе

Вот аналогичный модульный тест, который проверяет, что ваш обратный вызов был выполнен после успешного выполнения AJAX-запроса:

it("should execute the callback function on success", function () {
    spyOn($, "ajax").andCallFake(function(options) {
        options.success();
    });
    var callback = jasmine.createSpy();
    getProduct(123, callback);
    expect(callback).toHaveBeenCalled();
});

function getProduct(id, callback) {
    $.ajax({
        type: "GET",
        url: "/products/" + id,
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: callback
    });
}

Для Жасмин 2.0 используйте вместо:

spyOn($, "ajax").and.callFake(function(options) {

как отмечено в этом ответе

Наконец, в другом месте вы намекнули, что вы можете захотеть написать интеграционные тесты, которые делают реальные запросы AJAX - для целей интеграции. Это можно сделать с помощью асинхронных функций Жасмин: waits (), waitsFor () и run ():

it("should make a real AJAX request", function () {
    var callback = jasmine.createSpy();
    getProduct(123, callback);
    waitsFor(function() {
        return callback.callCount > 0;
    });
    runs(function() {
        expect(callback).toHaveBeenCalled();
    });
});

function getProduct(id, callback) {
    $.ajax({
        type: "GET",
        url: "data.json",
        contentType: "application/json; charset=utf-8"
        dataType: "json",
        success: callback
    });
}
13 голосов
/ 12 января 2011

Посмотрите на проект jasmine-ajax: http://github.com/pivotal/jasmine-ajax.

Это вспомогательный помощник, который (для jQuery или Prototype.js) заглушает слой XHR, так что запросы никогда не отправляются.После этого вы можете ожидать от запроса все, что вы хотите.

Затем он позволяет вам предоставить ответы на вопросы для всех ваших дел, а затем написать тесты для каждого ответа, который вы хотите: успех, сбой, несанкционированный и т. Д.

Он забирает вызовы Ajax из области асинхронных тестов и предоставляет вам большую гибкость для тестирования того, как должны работать ваши фактические обработчики ответов.

7 голосов
/ 01 февраля 2013

вот простой пример тестового набора для приложения JS, как это

var app = {
               fire: function(url, sfn, efn) {
                   $.ajax({
                       url:url,
                       success:sfn,
                       error:efn
                   });
                }
         };

пример тестового набора, который будет вызывать обратный вызов на основе URL-выражения regexp

describe("ajax calls returns", function() {
 var successFn, errorFn;
 beforeEach(function () {
    successFn = jasmine.createSpy("successFn");
    errorFn = jasmine.createSpy("errorFn");
    jQuery.ajax = spyOn(jQuery, "ajax").andCallFake(
      function (options) {
          if(/.*success.*/.test(options.url)) {
              options.success();
          } else {
              options.error();
          }
      }
    );
 });

 it("success", function () {
     app.fire("success/url", successFn, errorFn);
     expect(successFn).toHaveBeenCalled();
 });

 it("error response", function () {
     app.fire("error/url", successFn, errorFn);
     expect(errorFn).toHaveBeenCalled();
 });
});
5 голосов
/ 22 мая 2011

Когда я указываю код ajax с помощью Jasmine, я решаю проблему, следя за любой зависимой функцией, инициирующей удаленный вызов (например, $ .get или $ ajax). Затем я извлекаю обратные вызовы, установленные на нем, и проверяю их дискретно.

Вот пример, который я привел недавно:

https://gist.github.com/946704

0 голосов
/ 17 июля 2016

Я чувствую, что мне нужно предоставить более актуальный ответ, поскольку Jasmine сейчас находится в версии 2.4, а некоторые функции изменились по сравнению с версией 2.0.

Итак, чтобы убедиться, что функция обратного вызовавызван в вашем AJAX-запросе, вам нужно создать шпиона, добавить к нему функцию callFake, а затем использовать шпиона в качестве функции обратного вызова.Вот как это происходит:

describe("when you make a jQuery AJAX request", function()
{
    it("should get the content of an XML file", function(done)
    {
        var success = jasmine.createSpy('success');
        var error = jasmine.createSpy('error');

        success.and.callFake(function(xml_content)
        {
            expect(success).toHaveBeenCalled();

            // you can even do more tests with xml_content which is
            // the data returned by the success function of your AJAX call

            done(); // we're done, Jasmine can run the specs now
        });

        error.and.callFake(function()
        {
            // this will fail since success has not been called
            expect(success).toHaveBeenCalled();

            // If you are happy about the fact that error has been called,
            // don't make it fail by using expect(error).toHaveBeenCalled();

            done(); // we're done
        });

        jQuery.ajax({
            type : "GET",
            url : "addressbook_files/addressbookxml.xml",
            dataType : "xml",
            success : success,
            error : error
        });
    });
});

Я сделал трюк для функции успеха, а также для функции ошибок, чтобы убедиться, что Jasmine запустит спецификации как можно скорее, даже если ваш AJAX вернет ошибку.

Если вы не укажете функцию ошибки и ваш AJAX вернет ошибку, вам придется подождать 5 секунд (интервал ожидания по умолчанию), пока Жасмин не выдаст ошибку Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL..Вы также можете указать свой тайм-аут, например:

it("should get the content of an XML file", function(done)
{
    // your code
},
10000); // 10 seconds
0 голосов
/ 24 июля 2012

Попробуйте jqueryspy.com Он предоставляет элегантный синтаксис, похожий на jquery, для описания ваших тестов и позволяет выполнять обратные вызовы после завершения ajax. Он отлично подходит для тестирования интеграции, и вы можете настроить максимальное время ожидания AJAX в секундах или миллисекундах.

...