Angular Jasmine SpyOn $resource Handle Errors - javascript

I am trying to unit test an AngularJS service that uses $resource. To keep it isolated, I would like to use Jasmine's spyOn and spy on the $resource's query() method. In my controller, I would like to be able to use the short form of query() where you pass a success and an error function directly to the query method without calling $promise.then(success, error). Is this possible, or am I stuck with the long form of query().$promise.then(success, error)?
Here is a plunker I created with a failing test illustrating my problem: http://plnkr.co/edit/hVc2YNnwUDNv7IHODOMD?p=preview
I have found several questions on SO claiming to solve the problem, but all are using much older versions of the components I am using. From the plunker you can see I'm working with Angular 1.5.2, and Jasmine 2.4.1.
As a related question, a number of tutorials show that in your controller, you can just assign the return value of query() to an array, and as the data is loaded, the array will be updated. This is the cleanest solution, but what happens if an error occurs? I would expect if there is a problem loading the data, you just end up with either some default error notification, or nothing happening at all. Is the best practice to handle errors elsewhere via an interceptor and maybe fire an event and notify the user in some generic non-controller specific way? I think then the interceptor would need some way of determining what message to display to the user to give some context, eg 'Loading of Bagels seems to be taking longer than usual, click here to retry' as opposed to 'some request returned a 500 status code'

You should still be able to use the function shorthand where you pass in the functions as query(success, error). To fix the unit test you need to account for the error function as shown below:
spyOn(mockBagelApiService, 'query').and.callFake(function(callback1, callback2) {
queryDeferred.promise.then(callback1);
queryDeferred.promise.catch(callback2);
return {$promise: queryDeferred.promise}
});
callFake will take in the parameters you pass into query() which are two functions for success and error. Depending on whether the promise has been resolved or rejected you need to handle the then and catch blocks with the appropriate callback.
The way i've handled request errors in my angular apps is by creating an error handler service that gets called in the catch block and will take in a specific error message and pop up a modal. You can configure it however you want: you can define the modal buttons to reload or redirect etc. For handling the message, you can configure your services to return problem codes that give a description of the situation such as USER_IS_NOT_AUTH or OAUTH_ERROR that your error handler can use to provide a more specific reponse.

Related

Is it possible to get request information from a rxjs-timeout-error?

I'm trying to improve our current implementation of error handling and one part of it is the better description of errors in general and also in testing environments. I do this for an Ionic app but since my problem lies within the rxjs timeout-method, I think this is neglectable.
One part im currently stuck on is the correct visualization (error message) of timeout errors since they don't seem to contain anything of value at all. I'd like to show to the user which request was the origin of the timeout error when the error happens and the user sees. In the case of testing environments additional thinks like url, device-version, etc. should be shown as well.
But all the Timeout-Error contains seems to be a stacktrace of the javascript library beneath handling the post request.
So, my question is if there is a way to add or retrieve additional information from an rxjs timeout error?
Below you can see how the TimeoutError from rxjs looks for me.
Thanks!
TimeoutError has nothing to do with values emitted by the source Observable. Still, it's thrown when there are no emissions from the source so what how could it contain any information anyway.
What you can do however is use catchError to get the error that produced, turn it into another error and send it further with throwError:
...
catchError(e => throwError({...e, ...whatever}))
You can for example check whether the error is an instance of TimeoutError and if it is the do something with it.

Non existing property: EventEmitter memory error instead of proper error message

In a NodeJS 6.10.2/SailsJS 0.12.13 based JavaScript application I experience since several months a strange error behavior.
In a Sails controller, I try to retrieve a property of a literal object:
console.log(someObject.someProperty);
console.log("I am still here!");
However, in my case someObject is undefined. So, I'd expect to get an error like 'Cannot read property someProperty of undefined.' - and then either Node.js to stop completely or the code to go on (with the next console.log).
Instead, the code simply stops executing at that point and I get a strange warning: "(node:4822) Warning: Possible EventEmitter memory leak detected. 11 close listeners added. Use emitter.setMaxListeners() to increase limit." It is however, unpredictable how often this error occurs. Somethings only once, somethings about 20 times right after each other.
What I found out so for is that it is somehow connected to the question whether there was already a response or not. Consider the following:
mySailsControllerFunction: function(req, res) {
console.log(someObject.someProperty);
console.log("I am still here!");
res.json({"foo":"dahoo"});
}
This will result in Sending 500 ("Server Error") response: ReferenceError: someObject is not defined - exactly what I expect.
However, now I first send some response and then trying to access my non existing property, turning the code into:
mySailsControllerFunction: function(req, res) {
res.json({"foo":"dahoo"});
setTimeout(function () {
console.log("Yeah!");
console.log(someObject.someProperty);
console.log("I am still here!");
},1000);
}
then I often get simply nothing: 'Yeah!' displayed, but nothing comes afterwards. The event listener error is sometimes there, sometimes not. Very strange.
Additionally, and strange enough, the problem seems to be somehow connected to the time passed since the start of Sails. I put the code you see above inside a Sails controller function which is called immediately after the clients re-connect. I then played around with the timeout values, restarting the Sails server several times. Outcome: If I set the timeout to 1s, in 4 of 5 tests, I will get the correct error behavior. For 10 seconds it is about 50%, for 30s the error will always be ignored without any console output.
However, if I put my test code outside of the Sails controller, I always get the correct error behavior by Node. So, I'm quite sure this is a wrong behavior of Sails, not Node.
Disclaimer: I don't know Sails. So it may or may not be related, but my answer may offer a clue.
From the Sails documentation:
http://sailsjs.com/documentation/reference/response-res/res-json
This method is terminal, meaning it is generally the last line of code
your app should run for a given request (hence the advisory usage of
return throughout these docs).
Thus, when you use res.json({"foo":"dahoo"});, Sails probably sends the response back to the client, closing the call sequence, which, if it uses Promises or some other async mechanism, may kind of "swallow" further code, as also suggested in an above comment. This is probably internal coding in Sails, so it's not immediately obvious from the outside WHY your second code block specifically doesn't work.
So you should stick to the first pattern: access your property first, and put res.json() at the end of the controller function.
For reference: I finally solved that issue.
There were, somehow hidden in the code, process exit handlers defined:
process.on('exit', myErrorFunction.bind());
process.on('SIGINT', myErrorFunction.bind());
process.on('uncaughtException', myErrorFunction.bind());
The problem was: The function in which these lines were in was bound to a cronjob. So, each time the cronjob executed, new handlers were registered. So, my assumption above (before vs. after response) was wrong: In fact everything worked till the cronjob was executed for the first time. From then on, it didn't. And eventually, the warning was fired (correctly!).
I would have never found out without this answer: Make node show stack trace after EventEmitter warning
You have to add one line of code to get the stack trace:
process.on('warning', e => console.warn(e.stack));
Additionally, speaking of stack traces: In the Sails serverError response (api/api/responses/serverError.js), it is convenient to access it like this:
module.exports = function serverError (data, options) {
console.log(data.stack);
/* ... */
};

When does Phoenix's Socket.js fire the onConnError vs the onError callbacks?

I'm writing an application that uses the Phoenix channels and phoenix's socket.js. I want to handle errors when the websocket can't connect (spotty Internet connection, etc.) and show an appropriate message.
Looking at the socket.js source code, there are two possible ways to register for errors on the Socket object. The first is
socket.onConnError(callback)
and the second is
socket.onError(callback)
I can trigger onError to be called by stopping the Phoenix server and trying to call socket.connect() in a browser. I can't seem to get socket.onConnError to fire though - when is it used? What are the differences between these two events/callbacks?
onConnError is not a way to register a callback for an error. onConnError is used to trigger an error. Calling onConnError will, in addition to some other things, call all the onError callbacks with the specified error message. It's called by the Socket class itself on any errors thrown by the connection object.
Looking more closely at the source code, looks like onConnError is used internally for actually triggering the onError callbacks that the user has registered.
Short answer: Use socket.onError.

How to display a full-page error in Ember.js using error substates?

I am using Ember.js and ember-cli v2.7.0.
As stated in the Ember Guide on Loading and Error Substates one can react to an error that occurs when processing the beforeModel, model, and/or afterModel, hooks by creating an error action, e.g.:
export default Ember.Route.extend({
actions: {
error(err, transitionTo) {
if (err) {
return this.transitionTo('error');
}
}
}
...
}
If I place that error action in the routes/application.js route I will supposedly be able to react to errors that occur in any of those hooks.
My goal...
I would like the default behavior of the application to render a full page error, ideally allowing for child routes to redefine this behaviour as depending on the interaction model, for example allowing a child route to render the error into a flash message region or a modal.
When displaying a full page error, I would prefer to do so without transitioning to a new URL. For example if someone requests: http://myemberapp.com/some/path and that path errors (for any reason), I would like the default behavior to be to display either a 404, 500, in the main {{outlet}} of the application.
What I've tried so far...
I have played around wit the this.transitionTo and I can effectively move from an error substate to a full page, but it moves my user(s) to a new route. I also don't seem to retain the error context, and passing err as the second (model) argument to transitionTo causes its own errors!
Next steps...
Now, it clearly seems like this.transitionTo is not what I want if I truly want to display the errors "inline" to the page they occur on, because that will take me to the error page route I have defined (routes/error.js), and as far as I can tell it transitions without an implicit error model in the above form. Furthermore, as mentioned above, attempting to pass err as the second argument causes errors.
At this point in time, I would be OK with transitioning to a new page as an interim solution, but would need to be able to retain access to the error information when reaching the new route and I don't know how to properly pass the error context from the route an error occurs on through the error action to the new route.
Also, as far as I can tell, there is no guarantee what form the error, err, will take within the error action. If you follow the JSONAPI spec you might end up with one form of error (a JSON object) but if you invoke invalid javascript code, e.g. null.boom it would appear from my testing that the error is different. How does one account for this? I would like to be able to know--whether the error comes from the client or the server--if I should be trying to render a 404, a 500 page, or something else.
(As a bonus, is there any way to get Ember to throw a 404, or similar, error when a user attempts to navigate to a URL that doesn't exist in the router? Globbing maybe?)
I would also like to know if my assumption that I can have some child route, e.g. some.child.route pre-empt the default error handling in favor of say an alert or modal, is correct.
I have spent a fair amount of time over the last few months learning Ember.js but this subject seems to have very little knowledge shared on it.
Finally, are there any good articles or tutorials out there that really dissect the topic of error routing and error handling in Ember.js, particularly in the 2.x release series?
Help?
(Thanks in advance!)
UPDATE (2016/08/18):
I can assign a lastError property to the error route's controller before transitioning to it that allows me to access error information in the controller and the template. Is there a better way? E.g.
error(err, transitionTo) {
let errorController = this.controllerFor("error")
errorController.set("lastError", err);
this.transitionTo("error");
},
You could set a property on the application controller with error information and then display it using the application template.
{{#if error}}
<div class="error">{{error}}</div>
{{else}}
{{outlet}}
{{/if}}

How does one handle a Facebook Connect timeout

I don't see any way to respond to a timeout issue if Facebook is down or not responding when I use FB.init. There's no option here: http://wiki.developers.facebook.com/index.php/JS_API_M_FB.Bootstrap.Init_2
Would be nice if there were some way to respond to errors like you can with normal xmlhttprequests. Is there such a thing with Facebook Connect?
As far as I know, you cannot gracefully handle timeouts with FB.init.
That's why I never use FB.init directly. Instead, I always call FB_RequireFeatures. This wraps the FB.init call so that I can deal with errors and degrade gracefully. What I do is write my own function that checks whether Facebook Connect initialized correctly and then does something appropriate if it did not.
For example:
FB_RequireFeatures(["Connect"], function() {
FB.init("API_KEY", "xd_receiver.htm");
myPostConnectFunction();
});
function myPostConnectFunction() {
// Check for success of FBconnect, and deal with errors accordingly.
};
If that seems hacky, well... it is. :-)

Categories

Resources