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.
Ich denke, es gibt zwei Arten von Tests, die Sie durchführen können:
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
});
}
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.
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();
});
});
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:
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.
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