webentwicklung-frage-antwort-db.com.de

Wie überprüfe ich jQuery? AJAX Veranstaltungen mit Jasmin?

Ich versuche, Jasmine zu verwenden, um einige BDD-Spezifikationen für grundlegende jQuery-Anforderungen AJAX zu schreiben. Ich verwende Jasmine derzeit im Standalone-Modus (d. H. Über SpecRunner.html). Ich habe SpecRunner so konfiguriert, dass Jquery und andere JS-Dateien geladen werden. Irgendwelche Ideen, warum das Folgende nicht funktioniert? has_returned wird nicht wahr, dachte sogar "Yuppi!" Alarm wird gut angezeigt.

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

});

Wie teste ich, dass der Rückruf angerufen wurde? Alle Hinweise auf Blogs/Material, die sich auf das Testen von asynchroner jQuery mit Jasmine beziehen, werden sehr geschätzt.

112
mnacos

Ich denke, es gibt zwei Arten von Tests, die Sie durchführen können:

  1. Unit-Tests, die die AJAX Anforderung (unter Verwendung von Jasmines Spionen) vortäuschen, sodass Sie den gesamten Code testen können, der kurz davor die AJAX Anforderung und gleich danach. Sie können Jasmine sogar verwenden, um eine Antwort vom Server zu fälschen. Diese Tests wären schneller - und sie müssten nicht mit asynchronem Verhalten umgehen -, da es keine realen AJAX Schritte gibt.
  2. Integrationstests, die echte AJAX Anforderungen ausführen. Diese müssten asynchron sein.

Jasmine kann Ihnen bei beiden Tests helfen.

Hier ein Beispiel, wie Sie die AJAX Anforderung fälschen können, und schreiben Sie anschließend einen Komponententest, um zu überprüfen, ob die gefälschte AJAX Anforderung an die richtige URL ging:

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

Für Jasmine 2.0 verwenden Sie stattdessen:

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

wie in diese Antwort erwähnt

Hier ist ein ähnlicher Komponententest, der bestätigt, dass Ihr Callback ausgeführt wurde, nachdem eine AJAX Anforderung erfolgreich abgeschlossen wurde:

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

Für Jasmine 2.0 verwenden Sie stattdessen:

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

wie in diese Antwort erwähnt

Schließlich haben Sie an anderer Stelle angedeutet, dass Sie Integrationstests schreiben möchten, die echte AJAX Anforderungen - für Integrationszwecke machen. Dies kann mit den asynchronen Funktionen von Jasmine geschehen: waits (), waitsFor () und runs ():

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
    });
}
230
Alex York

Schauen Sie sich das Jasmin-Ajax-Projekt an: http://github.com/pivotal/jasmine-ajax .

Es ist ein Drop-In-Helfer, der (für jQuery oder Prototype.js) auf der XHR-Ebene abbricht, sodass Anforderungen nie ausgehen. Sie können dann alles erwarten, was Sie von der Anfrage erwarten.

Dann können Sie für alle Ihre Fälle Fixture-Antworten bereitstellen und dann für jede gewünschte Antwort Tests schreiben: Erfolg, Fehler, Unbefugte usw.

Es nimmt Ajax-Aufrufe aus dem Bereich der asynchronen Tests heraus und bietet Ihnen viel Flexibilität, um zu testen, wie Ihre tatsächlichen Antworthandler funktionieren sollten.

13
user533109

hier ist ein einfaches Beispiel für eine Testsuite für eine App wie diese

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

eine Beispieltestsuite, die Callback basierend auf der URL regexp aufrufen wird

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

Wenn ich mit Jasmine einen Ajax-Code spezifiziere, löse ich das Problem, indem ich ausspioniere, auf welche Funktion die Funktion angewiesen ist, die den Fernaufruf initiiert (wie zum Beispiel $ .get oder $ ajax). Dann rufe ich die darauf eingestellten Rückrufe ab und teste sie diskret.

Hier ist ein Beispiel, das ich kürzlich gefunden habe:

https://Gist.github.com/946704

5
Justin Searls

Versuchen Sie es mit jqueryspy.comEs bietet eine elegante Jquery-ähnliche Syntax, um Ihre Tests zu beschreiben, und ermöglicht, dass Callbacks getestet werden, nachdem der Ajax abgeschlossen ist. Es eignet sich hervorragend für Integrationstests, und Sie können maximale Ajax-Wartezeiten in Sekunden oder Millisekunden konfigurieren.

0
Steve Toms

Ich habe das Gefühl, dass ich eine aktuellere Antwort geben muss, da Jasmine jetzt auf Version 2.4 ist und sich ein paar Funktionen gegenüber der Version 2.0 geändert haben.

Um zu überprüfen, ob eine Callback-Funktion innerhalb Ihrer Anforderung AJAX aufgerufen wurde, müssen Sie einen Spion erstellen, eine CallFake-Funktion hinzufügen und dann den Spy als Callback-Funktion verwenden. So geht es:

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

Ich habe den Trick für die Erfolgsfunktion sowie die Fehlerfunktion gemacht, um sicherzustellen, dass Jasmine die Spezifikationen so schnell wie möglich ausführt, selbst wenn Ihr AJAX einen Fehler zurückgibt.

Wenn Sie keine Fehlerfunktion angeben und Ihr AJAX einen Fehler zurückgibt, müssen Sie 5 Sekunden warten (Standard-Timeout-Intervall), bis Jasmine einen Fehler Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL. ausgibt. Sie können auch Ihr eigenes Timeout wie folgt angeben:

it("should get the content of an XML file", function(done)
{
    // your code
},
10000); // 10 seconds
0
pmrotule