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

标签 javascript ajax unit-testing jasmine

我正在测试一个发出 AJAX 请求的功能,允许在网络不工作或因连接不稳定而超时时重试(我正在考虑移动设备)。

我确信它可以工作,因为我已经将它与其他代码集成使用,但我想进行适当的测试。

但是我还没有能够创建一个单元测试来正式地确保它。我正在使用 jasmine 2.3 和 karma,这是我目前的代码:

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)

最佳答案

在模拟请求对象上使用 .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

关于javascript - 如何使用 jasmine 在 XHR 中模拟超时事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30256322/

相关文章:

Javascript 在浏览器之外触发下载

javascript - 如何使用 Javascript 在 chrome 中禁用保存密码气泡?

javascript - .change() 处理程序使表单需要两次点击才能提交

javascript - JQuery AJAX刷新多个div(重复刷新)

c++ - 将线程逻辑与业务逻辑解耦?

PHP AJAX文件上传解决方案

javascript - 数组计数中的唯一值

jquery - 让 ASP.NEt 函数与 Ajax 一起使用来填充下拉列表

c# - 在 Ninject 中查找抽象类绑定(bind)到哪个类

Android - Assertj Android - 运行错误