2017-01-25 5 views
0

Я использую Jasmine 2.5.2 для написания модульных тестов для кода, который выполняет запросы Ajax с использованием jQuery 3.1.1. Я хотел бы высмеять вызов Ajax, предоставляя свой собственный статус ответа и текст.Mocking jQuery ajax calls with Jasmine

Я использую плагин ajax Jasmine (https://github.com/pivotal/jasmine-ajax).

Следуя примеру на https://jasmine.github.io/2.0/ajax.html, который использует объект XMLHttpRequest, отлично работает.

describe("mocking ajax", function() { 
    describe("suite wide usage", function() { 
     beforeEach(function() { 
      jasmine.Ajax.install(); 
     }); 

     afterEach(function() { 
      jasmine.Ajax.uninstall(); 
     }); 

     it("specifying response when you need it", function() { 
      var doneFn = jasmine.createSpy("success"); 

      var xhr = new XMLHttpRequest(); 
      xhr.onreadystatechange = function(args) { 
       if (this.readyState == this.DONE) { 
        doneFn(this.responseText); 
       } 
      }; 

      xhr.open("GET", "/some/cool/url"); 
      xhr.send(); 
      expect(jasmine.Ajax.requests.mostRecent().url).toBe('/some/cool/url'); 
      expect(doneFn).not.toHaveBeenCalled(); 

      jasmine.Ajax.requests.mostRecent().respondWith({ 
       "status": 200, 
       "contentType": 'text/plain', 
       "responseText": 'awesome response' 
      }); 
      expect(doneFn).toHaveBeenCalledWith('awesome response');      
     }); 
    }); 
}); 

NB: это немного отличается от документированной, например, пришлось изменить jasmine.Ajax.requests.mostRecent().response() к jasmine.Ajax.requests.mostRecent().respondWith().

Когда я использую jQuery Ajax, doneFn никогда не вызывается.

describe("mocking ajax", function() { 
    describe("suite wide usage", function() { 
     beforeEach(function() { 
      jasmine.Ajax.install(); 
     }); 

     afterEach(function() { 
      jasmine.Ajax.uninstall(); 
     }); 

     it("specifying response when you need it", function() { 
      var doneFn = jasmine.createSpy("success"); 

      $.ajax({ 
       method: "GET",    
       url: "/some/cool/url"}) 
      .done(function(result) { 
       doneFn(result); 
      }); 
      expect(doneFn).toHaveBeenCalledWith('awesome response');      
     }); 
    }); 
}); 

Жасмин утверждает, что

Жасмин-издевается Ajax ваш запрос на объекта XMLHttpRequest, поэтому должны быть совместимы с другими библиотек, которые делают AJAX запросы.

$ .ajax возвращает jqXHR от 1.4.x, а не XMLHttpRequest - поддерживает ли этот разрыв поддержку Jasmine Ajax?

ответ

1

Вот несколько способов, которыми вы могли бы насмехаются Аякса в тестах жасмин

подход A:

  • Использование фиктивных ajax.js, вы можете издеваться глобальный объект XHR, как описано в doc
  • Однако вам необходимо указать шпионить функция успеха, и пусть это callThrough (как показано в коде ниже)
  • в действии here

    describe('ajax test suite', function() { 
    
        beforeEach(function() { 
        jasmine.Ajax.install(); 
        }); 
    
        afterEach(function() { 
        jasmine.Ajax.uninstall(); 
        }); 
    
        it('sample test', function() { 
        var xhr = new XMLHttpRequest(); 
        xhr.onreadystatechange = function(args) { 
         if (this.readyState == this.DONE) { 
         testObj.successFunction(this.responseText); 
         } 
        }; 
        spyOn(testObj, 'successFunction').and.callThrough(); 
        xhr.open("GET", "https://jsonplaceholder.typicode.com/posts/1"); 
        xhr.send(); 
        expect(jasmine.Ajax.requests.mostRecent().url).toBe('https://jsonplaceholder.typicode.com/posts/1'); 
        expect(testObj.successFunction).not.toHaveBeenCalled(); 
        jasmine.Ajax.requests.mostRecent().respondWith({ 
         "status": 200, 
         "contentType": 'text/plain', 
         "responseText": 'awesome response' 
        }); 
        expect(testObj.successFunction).toHaveBeenCalledWith('awesome response'); 
        }); 
    }); 
    

Подход B:

  • Непосредственно насмешливый объект S.ajax. Будь то получение/публикация/загрузка или любой аякс-аромат из jquery, вы можете просто издеваться над $ .ajax, как показано ниже.

    var testObj = { 
        ajaxFunction : function(url){  
        $.ajax({url : url}).done(this.successFunction.bind(this)); 
        }, 
        successFunction : function(data){ 
        console.log(data); 
    } 
    } 
    
    describe('ajax test suite', function(){ 
        it('sample test', function(){ 
        testObj.ajaxFunction('https://jsonplaceholder.typicode.com/posts/1'); 
        spyOn($, 'ajax').and.callFake(function(e) { 
          return $.Deferred().resolve({'text':'this a a fake response'}).promise(); 
        }); 
        spyOn(testObj, 'successFunction').and.callThrough(); 
        testObj.ajaxFunction('https://jsonplaceholder.typicode.com/posts/1'); 
        expect(testObj.successFunction).toHaveBeenCalledWith({'text':'this a a fake response'}); 
        }); 
    }); 
    
+0

Ваш второй подход работал для меня здесь. Подделка также может возвращать '$ .Deferred(). Reject (obj)' для проверки ошибки Ajax, где obj имеет свойство responseText с текстом ошибки. – Lozzer

+0

@Lozzer это правильно. С отложенным вы можете либо разрешить/отклонить, исходя из вашего требования. –

0

Когда насмешливый объект S.ajax, параметр передается в может быть использован непосредственно, чтобы вызвать успех или неудачу, не проходя через интерфейс посыла.

spyOn($, 'ajax').and.callFake(function (options) { 
    var result = undefined, status, xhr; 
    options.success(result, status, xhr); 
}); 

spyOn($, 'ajax').and.callFake(function (options) { 
    var xhr = undefined, status, error; 
    options.error(xhr, status, error); 
});