web-dev-qa-db-ja.com

ジャスミンを使用して完了オブジェクトをテストして遅延オブジェクトを失敗させる方法

これは、javascript送信要求(1)に関するコードです。
これは、jasmine(2)を使用してajaxリクエストをモックするテストです。

サーバーの動作を模擬したいと思います。何か案は?
詳細については、(1)および(2)のコメントを参照してください。

PS:
実際にはどちらの場合も、fakeFunctionの完了および失敗の遅延オブジェクトが呼び出されます。


(1)

submitForm: function () {
     // the server execute fail only if message.val() is empty
     // and I would like to mock this behaviour in (2)
     backendController.submitForm(message.val()).done(this.onSuccess).fail(this.onError);
},

backendController.submitForm = function (message) {
    return $.ajax({
        url: 'some url',
        type: 'POST',
        dataType: 'json',
        data: {
            message: message
        }
    }).done(function () {
        //some code;
    });
};

(2)

describe('When Submit button handler fired', function () {
    var submitFormSpy,
        fakeFunction = function () {
            this.done = function () {
                return this;
            };
            this.fail = function () {
                return this;
            };
            return this;
        };

    beforeEach(function () {
        submitFormSpy = spyOn(backendController, 'submitForm').andCallFake(fakeFunction);
    });

    describe('if the message is empty', function () {
        beforeEach(function () {
            this.view.$el.find('#message').text('');
            this.view.$el.find('form').submit();
        });
        it('backendController.submitForm and fail Deferred Object should be called', function () {
            expect(submitFormSpy).toHaveBeenCalled();
            // how should I test that fail Deferred Object is called?
        });
    });

    describe('if the message is not empty', function () {
        beforeEach(function () {
            this.view.$el.find('#message').text('some text');
            this.view.$el.find('form').submit();
        });
        it('backendController.submitForm should be called and the fail Deferred Object should be not called', function () {
            expect(submitFormSpy).toHaveBeenCalled();
            // how should I test that fail Deferred Object is not called?
        });
    });

});
28

実際に同じ問題に遭遇し、オンザフライテンプレート作成のためにAJAXされたテンプレートスクリプトを表すDeferredオブジェクトをテストしようとしました。私たちのテストソリューションでは、 Jasmine-Ajax ライブラリをJasmine自体と組み合わせて使用​​します。

したがって、おそらく次のようになります。

describe('When Submit button handler fired', function () {
  jasmine.Ajax.useMock();

  describe('if the message is empty', function () {

    beforeEach(function() {
      spyOn(backendController, 'submitForm').andCallThrough();
      // replace with wherever your callbacks are defined
      spyOn(this, 'onSuccess');
      spyOn(this, 'onFailure');
      this.view.$el.find('#message').text('');
      this.view.$el.find('form').submit();
    });

    it('backendController.submitForm and fail Deferred Object should be called', function () {
      expect(backendController.submitForm).toHaveBeenCalledWith('');
      mostRecentAjaxRequest().response({
        status: 500, // or whatever response code you want
        responseText: ''
      });

      expect( this.onSuccess ).not.toHaveBeenCalled();
      expect( this.onFailure ).toHaveBeenCalled();
    });
});

可能であれば、機能を分割して、DOMから応答へのコールバックパス全体を1つのテストでテストしないようにしてください。十分に細かい場合は、テスト内でDeferredオブジェクト自体を使用して、非同期のDeferred解決を実際にテストできます。

重要なのは、テスト自体の中で実際にDeferredオブジェクトを使用することです。これにより、expect呼び出しのスコープがit関数ブロック内に残ります。

describe('loadTemplate', function() {
  it('passes back the response text', function() {
    jasmine.Ajax.mock();
    loadTemplate('template-request').done(function(response) {
      expect(response).toBe('foobar');
    });
    mostRecentAjaxRequest().response({ status:200, responseText:'foobar' });
  });
});
25
Aintaer

これが私がどうやってそれを成し遂げたかです。

基本的に、$。ajaxオブジェクトはDeferredオブジェクトを返すため、$。ajaxをスパイしてDeferredを返し、それを手動でトリガーしてJavaScriptで.done()コードを実行できます。

コード

Index.prototype.sendPositions = function() {
  var me = this;
  $.ajax({
    ...
  }).done(function(data, textStatus, jqXHR) {
    me.reload();
  }).fail(function(jqXHR, textStatus, errorThrown) {
    console.log(errorThrown);
  });
};

テスト

it("should reload the page after a successful ajax call", function(){
  var deferred = new jQuery.Deferred();
  spyOn($, 'ajax').andReturn(deferred);
  spyOn(indexPage, 'reload');
  indexPage.sendPositions();
  deferred.resolve('test');
  expect(indexPage.reload).toHaveBeenCalled();
});
14
Tony

Ajaxリクエストのpromiseオブジェクトを持つvarがあると、テストがはるかに簡単になります。その場合、次のことができます。

 it('should do an async thing', function() {     
   var mutex = 1;
   var promF = jasmine.createSpy('prF');

   runs( function() {
     var promise1 = $.ajax();
     promise1.always(function(){
       mutex--;
     });
     promise1.fail(function(){
       promF();
     });
   });

   waitsFor(function(){
     return !mutex;
   }, 'Fetch should end', 10000);

   runs( function() {
      expect(promF).toHaveBeenCalled();
   });
 });

以下に、あなたに合うかもしれないテストされていないコードを投稿します。私はajax呼び出しが.submit()クラスから初期化されていると思いますか?たぶん、あなたはbeforeEach()からではなく、runs()ブロックからajaxリクエストを初期化するべきですが、どちらが機能するか試す必要があります。

describe('When Submit button handler fired and city is defined', function () {
    var ajaxRequestSpy,
        failSpy, successSpy, alwaysSpy,
        mutex;
    beforeEach(function () {
        ajaxRequestSpy = spyOn(backendController, 'ajaxRequest').andCallThrough();
        failSpy = spyOn(ajaxRequestSpy(), 'fail').andCallThrough()
        successSpy = spyOn(ajaxRequestSpy(), 'success').andCallThrough();
        mutex = 1; // num of expected ajax queries
        alwaysSpy =  spyOn(ajaxRequestSpy(), 'always').andCallFake(function() {
             mutex--;
        });
        this.view = new MyView({
            el: $('<div><form>' +
                '<input type="submit" value="Submit" />' +
                '<input type="text" name="city">' +
                '</form></div>')
        });
        this.view.$el.find('form').submit();
    });
    it('backendController.ajaxRequest should be called', function () {
        runs( function() {
            // maybe init ajax here ?   
        });

        waitsFor( function() {
            return !mutex;
        }, 'ajax request should happen', 5000);

        runs( function() {
            expect(ajaxRequestSpy).toHaveBeenCalled(); // true
            expect(failSpy).toHaveBeenCalled(); // Error: Expected spy fail 
                                            // to have been called.
        });

    });
});

しかし、私はラインが

failSpy = spyOn(ajaxRequestSpy(), 'fail').andCallThrough();

あなたがしたいことをします。別のスパイをスパイすることは可能ですか?もしそうなら、なぜあなたはスパイを呼んでいるのですか?たぶんあなたは試してみるべきです

failSpy = spyOn(ajaxRequestSpy, 'fail').andCallThrough();
3
basos