web-dev-qa-db-ja.com

JasmineやSinonを使用してjQueryの.ajax()promiseを適切に単体テストする方法は?

JQuery .ajax()promiseを返すようなかなり単純な関数があります。

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

ほとんどの場合、この新しいpromiseインターフェイスは夢のように機能し、jQueryの.ajax()を使用するときにコールバックピラミッドを排除することは素晴らしいことです。ただし、JasmineやSinonを使用してこれらの約束を適切にテストする方法を理解することはできません。

  1. Sinonのドキュメントはすべて、古い学校のコールバックを使用していることを前提としています。 promise/deferredでそれを使用する方法の例は見当たりません

  2. JasmineまたはSinonスパイを使用して$ .ajaxをスパイしようとすると、スパイは効果的にpromiseを上書きするため、そのdonefail、およびalways句はもはやなくなります。 ajax関数に存在するため、promiseは決して解決せず、代わりにエラーを投げます

これらの新しいjQuery .ajax()の約束を前述のテストライブラリでテストする方法の1つまたは2つの例が大好きです。私は「ネットをかなり徹底的に精査しましたが、そうすることについて何もreallyしていませんでした。私が見つけた1つのリソースはJasmine.ajaxを使用して言及しましたが、Sinonがすぐに使用できるほとんどの機能を提供するので、可能であればそれを避けたいと思います。

55
J. Ky Marsh

実際にはそれほど複雑ではありません。約束を返して、あなたのケースに従ってそれを解決することで十分です。

例えば:

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には存在しません

106
ggozad

これらの線に沿ったもの/ sinonと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());
16
yxa

@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');
0
damio

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ステートメントは、成功またはエラーの実行を促進するためにテストで使用するものです。

0
sam