55

我有一个相当简单的函数,它返回一个 jQuery .ajax() 承诺,如下所示:

CLAW.controls.validateLocation = function(val, $inputEl) {
    return $.ajax({
        url: locationServiceUrl + 'ValidateLocation/',
        data: {
            'locationName': val
        },
        beforeSend: function() {
            $inputEl.addClass('busy');
        }
    }).done(function(result) {
        // some success clauses
    }).fail(function(result) {
        // some failure clauses
    }).always(function() {
        // some always clauses
    });
}

在大多数情况下,这个新的 Promise 接口就像做梦一样工作,并且在使用 jQuery 的 .ajax() 时消除回调金字塔非常棒。但是,我终生无法弄清楚如何使用 Jasmine 和/或 Sinon 正确测试这些 Promise:

  1. 所有 Sinon 的文档都假设您使用的是老式回调;我没有看到一个如何将它与 promises/deferreds 一起使用的示例

  2. 当试图使用 Jasmine 或 Sinon spy 来监视 $.ajax 时,spy 有效地覆盖了 Promise,因此ajax 函数中不再存在其 、 和 子句,因此 Promise 永远不会解决并done抛出fail错误always

我真的很喜欢一两个如何使用上述测试库来测试这些新的 jQuery .ajax() 承诺的例子。我已经相当激烈地搜索了网络,并没有真正挖掘出任何东西。我确实找到的一个资源提到了使用 Jasmine.ajax,但如果可能的话,我想避免这种情况,因为 Sinon 提供了开箱即用的大部分相同功能。

4

4 回答 4

106

实际上并没有那么复杂。根据您的情况返回一个承诺并解决它就足够了。

例如:

spyOn($, 'ajax').andCallFake(function (req) {
    var d = $.Deferred();
    d.resolve(data_you_expect);
    return d.promise();
});

为了成功,或

spyOn($, 'ajax').andCallFake(function (req) {
    var d = $.Deferred();
    d.reject(fail_result);
    return d.promise();
});

失败。

Jasmine 2.0 的语法略有变化:

spyOn($, 'ajax').and.callFake(function (req) {});

Jasmine 2.0 中不存在 .andCallFake() 方法

于 2012-10-31T19:07:28.707 回答
17

沿着这些思路 / 使用 sinon 和 jQuery 延迟

ajaxStub = sinon.stub($, "ajax");

function okResponse() {
  var d = $.Deferred();
  d.resolve( { username: "testuser", userid: "userid", success: true } );
  return d.promise();
};

function errorResponse() {
 var d = $.Deferred();
 d.reject({},{},"could not complete");
 return d.promise();
};

ajaxStub.returns(okResponse());
ajaxStub.returns(errorResponse());
于 2013-04-18T17:45:44.117 回答
0

这是一种仅使用 javascript 的更简单的方法。

quoteSnapshots: function (symbol, streamId) {
                var FakeDeferred = function () {
                    this.error = function (fn) {
                        if (symbol.toLowerCase() === 'bad-symbol') {
                            fn({Error: 'test'});
                        }
                        return this;
                    };
                    this.data = function (fn) {
                        if (symbol.toLowerCase() !== 'bad-symbol') {
                            fn({});
                        }
                        return this;
                    };
                };

                return new FakeDeferred();
            }

每个回调中的 if 语句是我在测试中用来驱动成功或错误执行的。

于 2013-04-26T12:14:49.807 回答
0

如果您使用诸如.complete().

但是,万岁,茉莉花做了一个插件来做到这一点:http: //jasmine.github.io/2.0/ajax.html

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

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

//in your tests
expect(jasmine.Ajax.requests.mostRecent().url).toBe('/some/cool/url');
于 2016-01-21T01:57:17.020 回答