简体   繁体   English

用 Jasmine 模拟 jQuery ajax 调用

[英]Mocking jQuery ajax calls with Jasmine

I am using Jasmine 2.5.2 to write unit tests for code that performs Ajax requests using jQuery 3.1.1 .我正在使用 Jasmine 2.5.2 为使用 jQuery 3.1.1 执行 Ajax 请求的代码编写单元测试。 I would like to mock out the Ajax call, providing my own response status and text.我想模拟 Ajax 调用,提供我自己的响应状态和文本。

I am using the Jasmine ajax plug-in ( https://github.com/pivotal/jasmine-ajax ).我正在使用 Jasmine ajax 插件 ( https://github.com/pivotal/jasmine-ajax )。

Following the example on https://jasmine.github.io/2.0/ajax.html , which uses the XMLHttpRequest object, works fine.按照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: this differs slightly from the documented example, had to change jasmine.Ajax.requests.mostRecent().response() to jasmine.Ajax.requests.mostRecent().respondWith() .注意:这与记录的示例略有不同,必须将jasmine.Ajax.requests.mostRecent().response()更改为jasmine.Ajax.requests.mostRecent().respondWith()

When I use jQuery Ajax, the doneFn is never called.当我使用 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');                      
        });
    });
});

Jasmine states that茉莉花说

Jasmine-Ajax mocks out your request at the XMLHttpRequest object, so should be compatible with other libraries that do ajax requests. Jasmine-Ajax 在 XMLHttpRequest 对象模拟您的请求,因此应该与其他执行 ajax 请求的库兼容。

$.ajax returns a jqXHR from 1.4.x and not XMLHttpRequest - does this break support with Jasmine Ajax? $.ajax 从 1.4.x 返回 jqXHR 而不是 XMLHttpRequest - 这是否会破坏对 Jasmine Ajax 的支持?

Here are a couple of ways you could mock ajax in your jasmine tests以下是您可以在茉莉花测试中模拟 ajax 的几种方法

Approach A:方法一:

  • Using mock ajax.js, you can mock the global xhr object as described in the doc使用模拟 ajax.js,您可以模拟文档中描述的全局 xhr 对象
  • However you'll need to specify a spy on the success function and let it callThrough (as seen in the code below)但是,您需要在成功函数上指定一个间谍并让它调用(如下面的代码所示)
  • See it in action 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'); }); });

Approach B:方法B:

  • Directly mocking the $.ajax object.直接模拟 $.ajax 对象。 Be it get/post/load or any ajax flavor from jquery, you can simply mock the $.ajax as shown below.无论是 get/post/load 还是来自 jquery 的任何 ajax 风格,您可以简单地模拟 $.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 aa fake response'}).promise(); }); spyOn(testObj, 'successFunction').and.callThrough(); testObj.ajaxFunction('https://jsonplaceholder.typicode.com/posts/1'); expect(testObj.successFunction).toHaveBeenCalledWith({'text':'this aa fake response'}); }); });

When mocking the $.ajax object, the parameter passed in can be used directly to trigger a success or failure, without going through the promise interface.在mock $.ajax 对象时,可以直接使用传入的参数来触发成功或失败,无需经过promise 接口。

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

In addition to danronmoon answer(Approach B):除了danronmoon答案(方法 B):

I added options.success(testData) inside spyOn($, 'ajax') to trigger this.processResponseData我在spyOn($, 'ajax')添加了options.success(testData) spyOn($, 'ajax')来触发this.processResponseData

Fn to test: Fn 测试:

 var objUnderTest = {};
 objUnderTest.makeRequest(requestUrl) {
    $.ajax(requestUrl)
      .then(response => {
        this.processResponseData(response.data[0]) // get data from first array item
      })
  }

Test:测试:

  describe('objUnderTest.makeRequest', () => {
    const testData = {data: [{'text': 'this a a fake response'}]};

    let processResponseData;
    beforeAll(() => {
      spyOn($, 'ajax').and.callFake(function (options) {
        options.success(testData)
        return $.Deferred().resolve(testData).promise();
      });
      processResponseData = spyOn(objUnderTest, 'processResponseData')
    })

    it('should make ajax call', () => {
      objUnderTest.makeRequest({success: stockTicker.processResponseData});

      expect(processResponseData).toHaveBeenCalled();
    });
  });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM