I try to simulate a server with sinon.js and call it with jQuery.ajax. But i can't make it works.
Here's the code :
$(function() {
var server = sinon.fakeServer.create();
server.respondWith('POST', '/some/test', [200, { 'Content-Type' : 'application/json'}, JSON.stringify({
id : 'test',
value : 'test'
})]);
var success = sinon.spy(),
error = sinon.spy();
jQuery.ajax({
url : '/some/test',
async : false,
type : 'POST',
data : JSON.stringify({
test : 'test'
}),
contentType : 'application/json',
success : success,
error : error,
});
console.log(server.requests[0].status);
console.log(server.requests[0].method);
console.log(server.requests[0].url);
console.log(server.requests[0].requestBody);
console.log(success.called);
console.log(error.called);
server.restore();
});
If you try this code, you'll see this output :
200
POST
/some/test
{"test":"test"}
false
false
According to the first 4 logs, sinon respond to the request. But jQuery never called the success callback (and the error is not called too).
It's like the jQuery ajax request never finish.
The issue comes from sinon.js with jQuery 2.1 : https://github.com/cjohansen/Sinon.JS/issues/510
jQuery 2.1 makes synchronous ajax request like this :
var req = new XMLHttpRequest();
req.open('POST', '/some/test', false);
req.setRequestHeader('Content-Type', 'application/json');
req.onload = function() {
console.log('success');
};
req.onerror = function() {
console.log('error');
};
req.send(JSON.stringify({
test : 'test'
}));
The problem is Sinon doesn't trigger the onload or the onerror callback for a synchronous request. The issue is in the method setResponseBody of FakeXMLHttpRequest. You can find this code :
if (this.async) {
this.readyStateChange(FakeXMLHttpRequest.DONE);
} else {
this.readyState = FakeXMLHttpRequest.DONE;
}
In recent browsers, XmlHttpRequest trigger the callbacks even for a synchronous request. So this code should be modified in this :
if (!this.async) {
this.readyState = FakeXMLHttpRequest.DONE;
}
this.readyStateChange(FakeXMLHttpRequest.DONE);
If you patch sinon.js like that, everything works.
Related
After attaching videoroom plugin to Janus, in "success" callback i send synchronous message to it
janus.attach(
{
plugin: "janus.plugin.videoroom",
opaqueId: opaqueId,
success: function(pluginHandle) {
roomMaster = pluginHandle;
var isExist = {
"request" : "exists",
"room" : myroom
};
roomMaster.send({"message": isExist})
},
and get response in console from janus.js, but in documentation tells that plugin will send to me response message. And I can't understand - where i can catch it?
onmessage: function(msg, jsep){
// is fired only after sending async requests like "join", "start" - not "exists"
conslole.log(msg);
}
Anybody know?
Thank you
You can define a success callback in the request object:
roomHandle.send({
"message" : {
request : 'list'
},
success: function(result) {
console.log(result);
}
});
In Microsoft Edge, a GET request is not running. I have stepped through the code to the point of the AJAX request being run, and set a breakpoint in the callback(s). However, the code never reaches the callbacks.
I already have a .then() and .fail() setup with callbacks, and tried adding a .done() and .always() with callbacks, but none of the code in the callbacks is running.
I then checked the network tab in dev-tools, and I cannot find the request at all. It seems as though Edge is not firing the request off for some reason.
request = function(options, resolveScope) {
var deferred = $.Deferred();
corsHandler.makeRequest(options)
.done(this._wrap(function(response) {
deferred.resolveWith(resolveScope, [response]); //never gets here
}, this))
.fail(this._wrap(function(response) {
deferred.rejectWith(resolveScope, [response]); //never gets here
}, this));
return deferred;
}
This is what calls the request function above.
ajaxFunc = function(data, scope) {
return request({
url: '/path/to/server',
internalUrl: true,
method: 'GET',
datatype: 'json',
data: data
}, scope);
}
This is the implementation used to make that request.
(function() {
// set data var
return ajaxFunc(data, self)
.then(function(res) { console.log(res); }) //never gets here
.done(function(res) { console.log(res); }) //never gets here
.fail(function(res) { console.log(res); }) //never gets here
.finally(function(res) { console.log(res); }) //never gets here
})();
Here is the cors stuff. (I don't know a whole lot about this.)
corsHandler.makeRequest = function(options) {
// resolve default options
_.defaults(options, {
xhr: null,
corsUrl: null,
url: null,
method: 'GET',
data: {},
success: function() {},
error: function() {},
terminate: false,
binary: false,
headers: {},
internalUrl: false,
datatype: ''
});
// if url is internal, create absolute url from relative url
if (options.internalUrl) {
options.url = this.createAbsoluteInternalUrl(options.url);
}
// resolve cors url or proxy url
options.corsUrl = options.corsUrl || this.getCorsUrl(options.url);
if (!options.corsUrl) {
options.url = this.getProxyUrl(options.url);
options.corsUrl = this.getCorsUrl(options.url);
}
// create xhr
if (!options.xhr && options.corsUrl) {
options.xhr = this.createXhr(options.corsUrl);
}
// create cleanup procedure
var cleanUpAfterRequest = $.proxy(function() {
if (options.terminate) {
options.xhr.destroy();
this._removeCacheXhr(options.corsUrl);
}
}, this);
// prepare deffered object
var deferred = $.Deferred();
deferred
.done(function() {
if (options.success) {
options.success.apply(null, Array.prototype.slice.call(arguments));
}
})
.fail(function() {
if (options.error) {
options.error.apply(null, Array.prototype.slice.call(arguments));
}
});
// make actual request
if (!options.xhr) {
throw 'corsHandler: xhr object was not created or defined to make request';
// this does not happen
}
options.xhr.request(
{
url: options.url,
method: options.method,
data: options.data,
binary: options.binary,
headers: options.headers,
datatype: options.datatype
},
function() {
deferred.resolve.apply(null, Array.prototype.slice.call(arguments));
cleanUpAfterRequest();
},
function() {
deferred.reject.apply(null, Array.prototype.slice.call(arguments));
cleanUpAfterRequest();
}
);
return deferred;
}
UPDATE
It looks like the issue is in easyXDM. waitForReady() is not firing on(window, "message", waitForReady) in edge. I'm looking into the issue more now.
easyXDM snippet:
targetOrigin = getLocation(config.remote);
if (config.isHost) {
// add the event handler for listening
var waitForReady = function(event){
if (event.data == config.channel + "-ready") {
// replace the eventlistener
callerWindow = ("postMessage" in frame.contentWindow) ? frame.contentWindow : frame.contentWindow.document;
un(window, "message", waitForReady);
on(window, "message", _window_onMessage);
setTimeout(function(){
pub.up.callback(true);
}, 0);
}
};
on(window, "message", waitForReady);
// set up the iframe
apply(config.props, {
src: appendQueryParameters(config.remote, {
xdm_e: getLocation(location.href),
xdm_c: config.channel,
xdm_p: 1 // 1 = PostMessage
}),
name: IFRAME_PREFIX + config.channel + "_provider"
});
frame = createFrame(config);
}
The above snippet runs, but the waitForReady method is never called. The only browser it's not called in is Edge (Works in IE8+, Chrome, Safari, FF, and mobile chrome/safari).
It turns out there was a required "hack" that a previous developer wrote into our implementation of easyXDM.
In our implementation of easyXDM, we had to update the Window object on IE because our app launches in an iFrame. As Edge isn't technically a version of IE, our test was failing, so the code was not running to update window to be window.parent in the context of easyXDM.
We are using typeof document.documentMode === 'number' to detect IE, but document.documentMode is undefined in Edge, so we added a navigator.userAgent check for Edge.
This resolved the issue.
I'm trying to access any web resource via Ext.Ajax.request but it is always failing, for example I have GlassFish Server on my localhost at port 4848 and when I try to access it the request fails,I've tried other urls but with no success.
this is my code:
`items:[
{
id : 'button1',
xtype : 'button',
text : 'click',
listeners: {
click : function(btn){
Ext.Ajax.request({
method : 'GET',
url : 'http://localhost:4848',
success : function(){
alert('success');
},
failure : function(){
alert('fail');
}
});
}
}
]`
I think you should firstly specify a file after localhost.
I have the following jasmine spec:
describe "plugins", ->
beforeEach ->
#server = sinon.fakeServer.create()
afterEach ->
#server.restore()
describe "reviewStatus", ->
it "should attach dates to content", ->
#server.respondWith("GET", "/GeneralDocument.mvc.aspx/GetDocumentParent?typeName=ncontinuity2.core.domain.Plan&documentParentUid=45f0bccb-27c9-410a-bca8-9ff900ab4c28d",
[200, {"Content-Type": "application/json"},
'{"ReviewDate":"22/09/2012","AcknowledgedDate":"05/07/2012"}'])
$('#jasmine_content').addReviewStatus('ncontinuity2.domain.Plan', "45f0bccb-27c9-410a-bca8-9ff900ab4c28")
#server.respond()
expect($('#reviewDateTab').find("strong").eq(0).length).toEqual(1)
The addReviewStatus is a jQuery plugin I have written:
do($ = jQuery) ->
$.fn.extend
addReviewStatus: (type, uid) ->
ele = #
reviewData = null
getJSON '/GeneralDocument.mvc.aspx/GetDocumentParent', {typeName: type, documentParentUid: uid},
(document) ->
console.log('document = ' + document)
compileTemplate(ele, document)
(response) ->
showErrorMessage resonse.responseText
#etc., etc.
The getJSON method above calls $.ajax like this:
function getJSON(url, params, ajaxCallBack, ajaxErrorHandler, excludeProgress){
var e = (ajaxErrorHandler) ? ajaxErrorHandler : validationErrorCallBack;
var s = (ajaxCallBack) ? ajaxCallBack : jsonCallBack;
$.ajax({
type: "GET",
url: url,
cache: false,
data: params,
beforeSend: function(xhr) {
xhr.setRequestHeader("Ajax", "true");
xhr.setRequestHeader("UseAjaxError", "true");
},
complete: function() {
},
success: s,
timeout: _ajaxTimeOut,
dataType: "json",
error: e
});
}
The anonymous function callback of the getJSON method is not being fired. Also the call to $.ajax is returning a 404 not found. Can anyone see what I am doing wrong?
Sinon fakeserver returns a 404 if the URL for which you have called it does not have a response assigned.
It appears that your problem is that the url you are calling is not the exact one in the respondWith() parameter. Also, there may be a limit on URL length in Sinon, not sure though.
I am having a similar problem with. It seems to be related to the turning off of the cache in the AJAX call. I will post more if I get around it. You could try turning off the cache for the test and seeing if it passes. Not sure why it needs that though.
Ronan
At start of my app I need to send three ajax get (Dojo xhrGET ) requests, but problem is that I need to send second when I process data from first and send third when I process data from second ( order is important ! ). I put this requests one behind other but it sometimes doesn't work. How to synchronize and solve this, is there any way to lock or wait like in Java ?
If you're using 1.6, check out the new Promises API (returned by dojo.xhrGet), or use deferreds in 1.5. They provide a 'neater' way to achieve this.
Essentially you can write:
dojo.xhrGet({
url: './_data/states.json',
handleAs: 'json'
}).then(
function(response) {
// Response is the XHR response
console.log(response);
dojo.xhrGet({
url: './_data/'+response.identifier+'.json',
handleAs: 'json'
}).then(
function(response2) {
// The second XHR will fail
},
// Use the error function directly
errorFun
)
},
function(errResponse) {
// Create a function to handle the response
errorFun(err);
}
)
var errorFun = function(err) {
console.log(err);
}
See http://dojotoolkit.org/documentation/tutorials/1.6/deferreds/ and http://dojotoolkit.org/documentation/tutorials/1.6/promises/ for more information
You can use option sync = true, and put the request one behind other. With this, 3rd will be sent after 2nd after 1st.
Or you can begin send 2nd request after 1st is done by using load function.
Example:
dojo.xhrGet({ //1st request
load: function(){
dojo.xhrGet({ //2nd request
load: function(){
dojo.xhrGet({ //3nd request
});
}
});
}
});
For more information: http://dojotoolkit.org/reference-guide/dojo/xhrGet.html
Can we make the second ajax request in the success callback method of the first request:
$.ajax({
'type' : 'get', // change if needed
'dataType' : 'text', // data type you're expecting
'data' : { 'className' : divClass },
'url' : url,
'success' : function(newClass) {
//make the second ajax request...
}
});
And do the same thing for the third request.