如何使用jasmine在XHR中模拟超时事件?

时间:2015-05-15 09:46:31

标签: javascript ajax unit-testing jasmine

我正在测试一个发出AJAX请求的函数,允许在网络不工作时重试,或者由于连接不稳定而导致超时(我正在考虑移动设备)。

我确信它有效,因为我已将它与其他代码集成使用,但我希望进行适当的测试。

但是,我无法创建单元测试以确保正式。我正在使用茉莉花2.3和业力,到目前为止这是我的代码:

var RETRIES=2;
var TIMEOUT=1000;

function doRequest(method, url, successFn, errorFn, body, retries) {
    var request = new XMLHttpRequest();
    retries = retries === undefined ? RETRIES : retries;
    request.open(method, url);
    request.setRequestHeader('Accept', 'application/json');
    request.setRequestHeader('Content-Type', 'application/json');

    request.onload = function () {
        if (request.status < 300 && request.status >= 200) {
            successFn(JSON.parse(request.responseText));
        } else {
            if (errorFn) {
                errorFn(this.status, this.responseText);
            }
        }
    };
    request.onerror = function () {
        if (this.readyState === 4 && this.status === 0) {
        //there is no connection
            errorFn('NO_NETWORK'); 
        } else {
            errorFn(this.status, this.responseText);
        }
    };

    if (retries > 0) {
        request.ontimeout = function () {
            doRequest(method, url, successFn, errorFn, body, retries - 1);
        };
    } else {
        request.ontimeout = function () {
            errorFn('timeout');
        };
    }
    request.timeout = TIMEOUT;
    if (body) {
        request.send(body);
    } else {
        request.send();
    }
}

这是我的考验:

describe('Ajax request', function () {
    'use strict';

    var RETRIES=2;
    var TIMEOUT=1000;

    beforeEach(function () {
        jasmine.Ajax.install();
        jasmine.clock().install();

    });

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


    it(' should call error callback function when a tiemout happens', function () {
        var doneFn = jasmine.createSpy('onLoad');
        var errorFn=jasmine.createSpy('onTimeout');
        doRequest('GET','http://www.mockedaddress.com', doneFn, errorFn,null,RETRIES);
        var request = jasmine.Ajax.requests.mostRecent();

        expect(request.method).toBe('GET');
        jasmine.clock().tick(TIMEOUT*(RETRIES+1)+50); //first attempt and then 2 retries
        expect(errorFn).toHaveBeenCalled(); // assertion failed
    });

});

这是测试的结果:

    Expected spy onTimeout to have been called.
        at Object.<anonymous> (js/test/doRequest_test.js:75:0)
Chrome 42.0.2311 (Windows 7): Executed 1 of 1 (1 FAILED) ERROR (0.007 secs / 0.008 secs)

1 个答案:

答案 0 :(得分:3)

在模拟的请求对象上使用.responseTimeout,此方法由 jasmine-ajax 提供,但未记录。

jasmine.Ajax.requests.mostRecent().responseTimeout();

但在此之后,在第一个请求上调用.responseTimeout时,仍然会出现错误,因为errorFn回调仅在多次重试后才会触发。您必须处理代码中定义的request.ontimeout自动发送的下一个请求。它可以这样解决:

var retries = 3;
var request;

do {
  request = jasmine.Ajax.requests.mostRecent();

  request.responseTimeout();

  retries -= 1;

} while(retries >= 0);

因此,它会为每个后续请求调用timeout

以下是一些使用代码http://plnkr.co/edit/vD2N66EwkpgiLFpg1Afc?p=preview

的沙箱