RequireJS local error callback for timeout ignored - javascript

Any file that is required that does not respond for longer than the wait time breaks the application and does not enter ANY error callback I define.
require.config({
waitSeconds: 1,
catchError: {
define: true
}
});
require.onError = function() {
// Does not reach here
};
require(['http://localhost/remote-file-that-does-not-respond-for-more-than-config-wait-time.js'], function() {}, function() {
// Err callback never triggers
});
The app will crash and the console will log:
Uncaught Error: Load timeout for modules: remote-scripts!,http://localhost/remote-file-that-does-not-respond-for-more-than-config-wait-time.js http://requirejs.org/docs/errors.html#timeout
Whereas if there is a 404 response, the error callback works just fine:
require(['http://localhost/external-file-that-does-not-exist.js'], function() {}, function() {
// Err callback does trigger
});
Why is it that when the server does not respond it won't trigger the local error callback, or even reach the global error callback?

You should set enforceDefine: true. Otherwise, RequireJS may fail to detect some timeouts. Documentation here.

Related

In a Jasmine unit test, how do I force a failure callback to trigger that would result from a failed request?

Let's say I have this method (bellow is the function extrapolated):
function doSomething(onSuccess, onFailure){
var that = this;
that.$save(function(result){
if (onSuccess) {
onSuccess(result);
}
}, onFailure);
}
I'm already successfully testing that the onSuccess callback fires when that.$save executes as expected, but I'm having trouble finding any documentation on how to make that.$save fail to trigger the onFailure callback.
My attempt at creating a onFailure test looks like:
it ('should trigger the failure callback if necessary', function(){
var successCallback= jasmine.createSpy('successCallback');
var failureCallback= jasmine.createSpy('failureCallback');
// Force $save to fail to trigger failure callback
thing.$save = function(){};
spyOn(thing, '$save').and.throwError('thing.$save error');
thing.addNew(successCallback, failureCallback);
expect(failureCallback).toHaveBeenCalled();
expect(callback.successCallback).not.toHaveBeenCalled();
});
It still tries to call the success callback as I can tell per this error:
Expected spy failureCallback to have been called.
at /Users/pathy-path
Error: Unexpected request: POST http://website.com/things/5654d74a9b8d05030083239f
No more request expected
And if I setup the httpBackend to expect the POST (which it shouldn't since it should fail? At least that seems logical), the test fails because the wrong callback executes: Expected spy failureCallback to have been called.
For reference, my onSuccess test looks like this (somewhat simplified):
it ('should trigger the success callback', function(){
var successCallback = jasmine.createSpy('successCallback');
path = ENV.apiEndpoint + '/things/' + id;
// if this is triggered we know it would be saved
$httpBackend.expect('POST', path).respond(201);
thing.addNew(successCallback);
$httpBackend.flush();
expect(successCallback).toHaveBeenCalled();
});
You need to have it execute the second (onFailure) callback
spyOn(that, '$save').and.callFake(function(success, fail) {
fail();
});
I tried Phil's answer (which makes the test pass) but felt that it may not actually be a true test of how the doSomething function executes. To mimic an API failure I ended up using $httpBackend and forcing a 404 response so that Angular's .$save method still executes:
it ('should trigger the failure callback if necessary', function(){
var successCallback= jasmine.createSpy('successCallback');
var failureCallback= jasmine.createSpy('failureCallback');
// Force $save to fail to trigger failure callback
path = ENV.apiEndpoint + '/things/' + thing.id;
$httpBackend.expect('POST', path).respond(404);
thing.addNew(successCallback, failureCallback);
$httpBackend.flush();
expect(failureCallback).toHaveBeenCalled();
expect(successCallback).not.toHaveBeenCalled();
});

requiredjs fall to load fallback

When using requirejs, we do this:
require(['jquery','bootstrap','history','nanoscroller','noty','noty-theme','bootbox'],function(){
//run code
}
But how can I know when requirejs fail to load any of the plugin and show an alert box with message?
Pass a callback function as the third parameter and that will be called if one of the dependencies fails to load.
require(['jquery','bootstrap','history','nanoscroller','noty','noty-theme','bootbox'],
function(){
//run code
},
function (err) { // callback for dependency load failure
alert(err);
}
);
See the documentation for more details.
Note you can also use a global error handler. The following is an excerpt from the documentation:
To detect errors that are not caught by local errbacks, you can override requirejs.onError():
requirejs.onError = function (err) {
console.log(err.requireType);
if (err.requireType === 'timeout') {
console.log('modules: ' + err.requireModules);
}
throw err;
};

Handling prerequsites load failure in RequireJS require function

I'm using RequireJS for AMD. Using this code I execute my function after ensuring the module1 is loaded:
require(['module1'], function (module1) {
if (module1) {
// My function code...
}
);
In some cases the module1 is not available (mostly because of access security). I want to handle what happens if module1 failed to load. Using some code like:
require(['module1'], function (module1) {
if (module1) {
// My function code...
}
)
.fail(function(message)
{
console.log('error while loading module: ' + message);
}
or maybe the require function accepts another parameter for module load failures?
So the question is, how can I handle if the required module failed to load?
See RequireJS API document: http://requirejs.org/docs/api.html#errors.
require(['jquery'], function ($) {
//Do something with $ here
}, function (err) {
//The errback, error callback
//The error has a list of modules that failed
var failedId = err.requireModules && err.requireModules[0];
if (failedId === 'jquery') {
//undef is function only on the global requirejs object.
//Use it to clear internal knowledge of jQuery. Any modules
//that were dependent on jQuery and in the middle of loading
//will not be loaded yet, they will wait until a valid jQuery
//does load.
requirejs.undef(failedId);
//Set the path to jQuery to local path
requirejs.config({
paths: {
jquery: 'local/jquery'
}
});
//Try again. Note that the above require callback
//with the "Do something with $ here" comment will
//be called if this new attempt to load jQuery succeeds.
require(['jquery'], function () {});
} else {
//Some other error. Maybe show message to the user.
}
});

Jasmine failing with Uncaught Reference Error

I am trying to get a project to work properly with Jasmine. I am using the project that I downloaded from here. I added another spec file, PatientSpec.js:
describe('Patient :: Create', function() {
it("Must note be null", function() {
require(['models/Patient'], function(Patient) {
var patient1 = new Patient();
expect(patient).toBeDefined();
});
});
});
You see that my var is named patient1 and I am running the expectation on the variable name patient. When I look at my index.html, all of my tests are passing, and this is obviously not defined. I pull up my console and I here is my error:
What would cause this error? Why does it fail silently?
It fails silently cause the error happens in the callback of your require call not in your test. So when the error is thrown after your test has finished. You have to run your test inside of the callback:
require(['models/Patient'], function(Patient) {
describe('Patient :: Create', function() {
it("Must note be null", function() {
var patient1 = new Patient();
expect(patient).toBeDefined();
});
});
});
Take a look at this SO do understand how to test requireJs modules

Load async resource with requirejs timeout

I tried to load the Google APIs Client Library for JavaScript with requirejs and the async plugin:
require.config({
paths : {
async : '../lib/requirejs/async'
},
waitSeconds: 60
});
define('gapi', ['async!https://apis.google.com/js/client.js!callback'],
function(){
console.log('gapi loaded');
return gapi.client;
}
);
require(['gapi'], function(){
console.log("Callback");
console.log(gapi);
});
The usual way to load this library is
<script src="https://apis.google.com/js/client.js?onload=handleClientLoad"></script>
Everything is loaded in less than 2s but I always get this error:
Uncaught Error: Load timeout for modules: async!https://apis.google.com/js/client.js!callback_unnormalized2,async!https://apis.google.com/js/client.js!callback
http://requirejs.org/docs/errors.html#timeout
TL;DR; change the !callback to !onload that should fix the timeout.
define('gapi', ['async!https://apis.google.com/js/client.js!onload'],
function(){
console.log('gapi loaded');
return gapi.client;
}
);
The value after the ! is used as the argument name for the async callback, in this case the URI loaded will be something like https://apis.google.com/js/client.js?onload=__async_req_3__ where __async_req_3__ is a global variable (callback function) triggered as soon as the Google API is loaded (notifies the plugin that all dependencies are met).

Categories