Javascript 如何使用 Jasmine 验证 jQuery AJAX 事件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4662641/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I verify jQuery AJAX events with Jasmine?
提问by mnacos
I am trying to use Jasmine to write some BDD specs for basic jQuery AJAX requests. I am currently using Jasmine in standalone mode (i.e. through SpecRunner.html
). I have configured SpecRunner to load jquery and other .js files. Any ideas why the following doesn't work? has_returned does not become true, even thought the "yuppi!" alert shows up fine.
我正在尝试使用 Jasmine 为基本的 jQuery AJAX 请求编写一些 BDD 规范。我目前在独立模式下使用 Jasmine(即通过SpecRunner.html
)。我已将 SpecRunner 配置为加载 jquery 和其他 .js 文件。任何想法为什么以下不起作用?has_returned 不会变成真的,甚至想到了“yuppi!” 警报显示正常。
describe("A jQuery ajax request should be able to fetch...", function() {
it("an XML file from the filesystem", function() {
$.ajax_get_xml_request = { has_returned : false };
// initiating the AJAX request
$.ajax({ type: "GET", url: "addressbook_files/addressbookxml.xml", dataType: "xml",
success: function(xml) { alert("yuppi!"); $.ajax_get_xml_request.has_returned = true; } });
// waiting for has_returned to become true (timeout: 3s)
waitsFor(function() { $.ajax_get_xml_request.has_returned; }, "the JQuery AJAX GET to return", 3000);
// TODO: other tests might check size of XML file, whether it is valid XML
expect($.ajax_get_xml_request.has_returned).toEqual(true);
});
});
How do I test that the callback has been called? Any pointers to blogs/material related to testing async jQuery with Jasmine will be greatly appreciated.
如何测试回调是否已被调用?任何与使用 Jasmine 测试异步 jQuery 相关的博客/材料的指针将不胜感激。
回答by Alex York
I guess there are two types of tests you can do:
我想你可以做两种类型的测试:
- Unit tests that fake the AJAX request (using Jasmine's spies), enabling you to test all of your code that runs just beforethe AJAX request, and just afterwards. You can even use Jasmine to fake a response from the server. These tests would be faster - and they would not need to handle asynchronous behaviour - since there isn't any real AJAX going on.
- Integration tests that perform real AJAX requests. These would need to be asynchronous.
- 伪造 AJAX 请求的单元测试(使用 Jasmine 的间谍),使您能够测试在 AJAX 请求之前和之后运行的所有代码。您甚至可以使用 Jasmine 来伪造来自服务器的响应。这些测试会更快——而且它们不需要处理异步行为——因为没有任何真正的 AJAX 正在进行。
- 执行真实 AJAX 请求的集成测试。这些将需要是异步的。
Jasmine can help you do both kinds of tests.
Jasmine 可以帮助您进行这两种测试。
Here is a sample of how you can fake the AJAX request, and then write a unit test to verify that the faked AJAX request was going to the correct URL:
下面是一个示例,说明如何伪造 AJAX 请求,然后编写单元测试来验证伪造的 AJAX 请求是否发送到正确的 URL:
it("should make an AJAX request to the correct URL", function() {
spyOn($, "ajax");
getProduct(123);
expect($.ajax.mostRecentCall.args[0]["url"]).toEqual("/products/123");
});
function getProduct(id) {
$.ajax({
type: "GET",
url: "/products/" + id,
contentType: "application/json; charset=utf-8",
dataType: "json"
});
}
For Jasmine 2.0use instead:
对于Jasmine 2.0,请改用:
expect($.ajax.calls.mostRecent().args[0]["url"]).toEqual("/products/123");
as noted in this answer
Here is a similar unit test that verifies your callback was executed, upon an AJAX request completing successfully:
这是一个类似的单元测试,用于验证您的回调是否在 AJAX 请求成功完成后执行:
it("should execute the callback function on success", function () {
spyOn($, "ajax").andCallFake(function(options) {
options.success();
});
var callback = jasmine.createSpy();
getProduct(123, callback);
expect(callback).toHaveBeenCalled();
});
function getProduct(id, callback) {
$.ajax({
type: "GET",
url: "/products/" + id,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: callback
});
}
For Jasmine 2.0use instead:
对于Jasmine 2.0,请改用:
spyOn($, "ajax").and.callFake(function(options) {
as noted in this answer
Finally, you have hinted elsewhere that you might want to write integration tests that make real AJAX requests - for integration purposes. This can be done using Jasmine's asyncronous features: waits(), waitsFor() and runs():
最后,您在别处暗示您可能想要编写发出真正 AJAX 请求的集成测试 - 用于集成目的。这可以使用 Jasmine 的异步功能来完成:waits()、waitsFor() 和 running():
it("should make a real AJAX request", function () {
var callback = jasmine.createSpy();
getProduct(123, callback);
waitsFor(function() {
return callback.callCount > 0;
});
runs(function() {
expect(callback).toHaveBeenCalled();
});
});
function getProduct(id, callback) {
$.ajax({
type: "GET",
url: "data.json",
contentType: "application/json; charset=utf-8"
dataType: "json",
success: callback
});
}
回答by user533109
Look at the jasmine-ajax project: http://github.com/pivotal/jasmine-ajax.
查看 jasmine-ajax 项目:http: //github.com/pivotal/jasmine-ajax。
It's a drop-in helper that (for either jQuery or Prototype.js) stubs at the XHR layer so that requests never go out. You can then expect all you want about the request.
它是一个插入式帮助程序(对于 jQuery 或 Prototype.js)在 XHR 层存根,以便请求永远不会发出。然后,您可以期待有关请求的所有信息。
Then it lets you provide fixture responses for all your cases and then write tests for each response that you want: success, failure, unauthorized, etc.
然后它允许您为所有案例提供夹具响应,然后为您想要的每个响应编写测试:成功、失败、未授权等。
It takes Ajax calls out of the realm of asynchronous tests and provides you a lot of flexibility for testing how your actual response handlers should work.
它将 Ajax 调用排除在异步测试领域之外,并为您测试实际响应处理程序的工作方式提供了很大的灵活性。
回答by skipy
here is a simple example test suite for an app js like this
这是一个像这样的应用程序js的简单示例测试套件
var app = {
fire: function(url, sfn, efn) {
$.ajax({
url:url,
success:sfn,
error:efn
});
}
};
a sample test suite, which will call callback based on url regexp
一个示例测试套件,它将根据 url regexp 调用回调
describe("ajax calls returns", function() {
var successFn, errorFn;
beforeEach(function () {
successFn = jasmine.createSpy("successFn");
errorFn = jasmine.createSpy("errorFn");
jQuery.ajax = spyOn(jQuery, "ajax").andCallFake(
function (options) {
if(/.*success.*/.test(options.url)) {
options.success();
} else {
options.error();
}
}
);
});
it("success", function () {
app.fire("success/url", successFn, errorFn);
expect(successFn).toHaveBeenCalled();
});
it("error response", function () {
app.fire("error/url", successFn, errorFn);
expect(errorFn).toHaveBeenCalled();
});
});
回答by Justin Searls
When I specify ajax code with Jasmine, I solve the problem by spying on whatever depended-on function initiates the remote call (like, say, $.get or $ajax). Then I retrieve the callbacks set on it and test them discretely.
当我使用 Jasmine 指定 ajax 代码时,我通过监视启动远程调用的任何依赖函数(例如 $.get 或 $ajax)来解决问题。然后我检索设置在它上面的回调并离散地测试它们。
Here's an example I gisted recently:
这是我最近举的一个例子:
回答by Steve Toms
Try jqueryspy.com It provides an elegant jquery like syntax to describe your tests and allows callbacks to test after the ajax has complete. Its great for integration testing and you can configure maximum ajax wait times in seconds or milleseconds.
试试 jqueryspy.com 它提供了一个优雅的类似 jquery 的语法来描述你的测试,并允许回调在 ajax 完成后进行测试。它非常适合集成测试,您可以以秒或毫秒为单位配置最大的 ajax 等待时间。
回答by pmrotule
I feel like I need to provide a more up-to-date answer since Jasmine is now at version 2.4 and a few functions have changed from the version 2.0.
我觉得我需要提供一个更新的答案,因为 Jasmine 现在是 2.4 版,并且一些功能已经从 2.0 版改变了。
So, to verify that a callback function has been called within your AJAX request, you need to create a spy, add a callFake function to it then use the spy as your callback function. Here's how it goes:
因此,要验证在您的 AJAX 请求中是否调用了回调函数,您需要创建一个 spy,向其中添加一个 callFake 函数,然后使用该 spy 作为您的回调函数。这是它的过程:
describe("when you make a jQuery AJAX request", function()
{
it("should get the content of an XML file", function(done)
{
var success = jasmine.createSpy('success');
var error = jasmine.createSpy('error');
success.and.callFake(function(xml_content)
{
expect(success).toHaveBeenCalled();
// you can even do more tests with xml_content which is
// the data returned by the success function of your AJAX call
done(); // we're done, Jasmine can run the specs now
});
error.and.callFake(function()
{
// this will fail since success has not been called
expect(success).toHaveBeenCalled();
// If you are happy about the fact that error has been called,
// don't make it fail by using expect(error).toHaveBeenCalled();
done(); // we're done
});
jQuery.ajax({
type : "GET",
url : "addressbook_files/addressbookxml.xml",
dataType : "xml",
success : success,
error : error
});
});
});
I've done the trick for the success function as well as the error function to make sure that Jasmine will run the specs as soon as possible even if your AJAX returns an error.
我已经完成了成功函数和错误函数的技巧,以确保即使您的 AJAX 返回错误,Jasmine 也会尽快运行规范。
If you don't specify an error function and your AJAX returns an error, you will have to wait 5 seconds (default timeout interval) until Jasmine throws an error Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
. You can also specify your own timeout like this:
如果您没有指定错误函数并且您的 AJAX 返回错误,您将必须等待 5 秒(默认超时间隔),直到 Jasmine 抛出错误Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
。您还可以像这样指定自己的超时时间:
it("should get the content of an XML file", function(done)
{
// your code
},
10000); // 10 seconds