JasmineでjQuery AJAXイベントを確認するにはどうすればよいですか?


114

Jasmineを使用して、基本的なjQuery AJAXリクエストのBDD仕様をいくつか作成しようとしています。現在、Jasmineをスタンドアロンモードで(つまりから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);
  }); 

});

コールバックが呼び出されたことをどのようにテストしますか?Jasmineで非同期jQueryをテストすることに関連するブログ/資料へのポインターは大いに評価されます。

回答:


234

あなたができるテストには2つのタイプがあると思います:

  1. ユニットテスト、あなたがその実行コードのすべてをテストすることを可能に偽(ジャスミンのスパイを使用して)AJAX要求を、直前 AJAX要求、およびだけで、その後。Jasmineを使用してサーバーからの応答を偽装することもできます。実際のAJAXが実行されていないため、これらのテストはより高速になり、非同期動作を処理する必要がなくなります。
  2. 実際のAJAXリクエストを実行する統合テスト。これらは非同期である必要があります。

Jasmineは、両方の種類のテストを実行するのに役立ちます。

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リクエストを作成する統合テストを作成する可能性があることを他の場所に示唆しました。これは、Jasmineの非同期機能を使用して実行できます:waits()、waitsFor()、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
    });
}

+1アレックスのすばらしい答え。実際、私はDeferredオブジェクトを使用してTest Ajaxリクエストの質問を開いた同様の問題に直面しました。見ていただけますか?ありがとう。
ロレーヌバーナード

12
私は本当にあなたの答えがジャスミンの公式ドキュメントの一部であることを望みます。数日間私を殺してきた問題への非常に明確な答え。
Darren Newton

4
この回答は、実際にはこの質問に対する公式の回答としてマークする必要があります。
Thomas Amar

1
最新の通話情報を取得する現在の方法は$ .ajax.calls.mostRecent()です
camiblanch

1
プレーンなJS ajaxにそれをどのように実装しますか?
2016年

13

jasmine-ajaxプロジェクトを見てくださいhttp : //github.com/pivotal/jasmine-ajax

これはドロップインヘルパーであり、(jQueryまたはPrototype.jsのいずれかに対して)XHRレイヤーでスタブを作成して、要求が出されないようにします。その後、リクエストについて必要なすべてを期待できます。

次に、すべてのケースにフィクスチャ応答を提供し、必要な各応答(成功、失敗、無許可など)のテストを作成できます。

非同期テストの領域からAjax呼び出しを取得し、実際の応答ハンドラーがどのように機能するかをテストするための多くの柔軟性を提供します。


@jasminebddに感謝します。jasmine-ajaxプロジェクトは、私のjsコードをテストする方法のように見えます。しかし、たとえば接続/統合テストなど、サーバーへの実際のリクエストでテストしたい場合はどうなりますか?
mnacos

2
@mnacos jasmine-ajaxは、サーバーへの呼び出しを特に避けたいユニットテストに最も役立ちます。統合テストを実行している場合、これはおそらく望んでいないことであり、別個のテスト戦略として設計する必要があります。
Sebastien Martin

7

これは、このようなアプリ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();
 });
});

ありがとう、相棒。この例は私に大いに役立ちました!Jasmine> 2.0を使用している場合、andCallFakeの構文はspyOn(jQuery、 "ajax")。and.callFake(/ * your function * /);であることに注意してください。
ジョアン・パウロモッタ

これがバージョンの問題かどうかはわかりませんが、でエラーが発生しました。代わり.andCallFakeに使用し.and.callFakeました。ありがとう。
OO

5

Jasmineでajaxコードを指定する場合、依存する関数がリモート呼び出しを開始するもの(たとえば、$。getまたは$ ajax)をスパイすることで問題を解決します。次に、それに設定されたコールバックを取得し、個別にテストします。

ここに私が最近挙げた例があります:

https://gist.github.com/946704


0

jqueryspy.comを試してください。これは、テストを記述するための構文のようなエレガントなjqueryを提供し、ajaxの完了後にコールバックがテストできるようにします。統合テストに最適であり、最大ajax待機時間を秒またはミリ秒単位で構成できます。


0

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

AJAXがエラーを返した場合でも、Jasmineが仕様をできるだけ早く実行できるように、success関数とerror関数のトリックを行いました。

エラー関数を指定せず、AJAXがエラーを返す場合、Jasmineがエラーをスローするまで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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.