Ensuring $httpBackend flush for series of requests - angularjs

I have a need to test an in-house angular service implemented under Angular 1.5.9 with jasmine/karma.
I need to write a test which checks that the response of a particular service function is as expected. To do this I am constructing a mock object, instantiating the service, calling the function to be tested and using expect().toBe() to check the returned value.
Unfortunately, the service makes numerous calls to it's own functions, many of which make further calls using the $http angular service. It does this in order to populate objects such as user data, locale and other bespoke product information. Suffice to say that I am not in a position to refactor the service into a better architecture; I must simply construct this test.
As there are so many calls to $http I intend to mock all the data it would request using a series of lines such as this:
var mockGetCartData = { "d": null, "message": null }; // at the top of the describe
$httpBackend.when('GET', /(.*)\/order\/api\/v1\/GetCart/).respond(200, mockGetCartData); // in the beforeEach
When I call the function to be tested I am immediately calling $httpBackend.flush() but, as the test is failing, I am concerned that what I need to do is cause each (faked) $http call to be flushed before the next is made.
Do I need to do this or is setting up all of the $httpBackend.when().respond() entries, acting on the test function and then calling a single flush() enough? If this is not enough, what should I do?

You do not need to call flush() for each request that is made as it flushes all pending requests.
See the Documentation: https://docs.angularjs.org/api/ngMock/service/$httpBackend
or source: https://github.com/angular/angular.js/blob/master/src/ngMock/angular-mocks.js#L1830
However, if the $http requests in the method under test are chained together (so subsequent requests are only made after the previous request is resolved) then you will need to flush() for every request in the chain. Without seeing the code under test that's all the help I am able to give.

You have to mock the only required http call in It block and flush it after the function call. Otherwise it will try to flush unexpected http calls which will result in error.

Related

Using Angular Mock Backend resource multiple times

I am trying to do backend less development in Angular while working disconnected from the backend resources.
Most functionality works fine, but if I try to use any resource a second time I get an error:
Error: Unexpected request: GET /localPTicket?ticket=123
No more request expected
The scenario I am mocking is one where, for every request to a backend service, I have to first make a Get call to get a valid Proxy Ticket, the response from this is then passed to the next API call.
I have set up a plunker that demonstrates the issue:
https://plnkr.co/edit/KKa6MXcnbK1gcMiBB7MI?p=preview
I think that the issue is related to flushing the mock requests, but my understanding of the documentation is that using ngMockE2E this should not be an issue.
Thanks for any pointers!
Les
It's because your are using global regexes.
Global regexes in JavaScript can be very confusing since they have a state. The first time you call it it returns the first match in the string, the second time you call it it returns the next match in the string. If there are no more matches it will return that there were no matches and reset its state.
Simply remove the g from the end of your regexes and it should behave as you expect.

Which approach is best to unit test composed code?

Say I have the following AngularJs service:
angular.module("foo")
.service("fooService", function(){
var svc = this;
svc.get = function(id){...};
svc.build = function(id){...};
svc.save = function(thing){...}; //posts, then returns the saved thing
svc.getOrCreate = function(id){
return svc.get(id).then(function(thing){
return thing || svc.build(id).then(function(builtThing){
return svc.save(builtThing);
});
});
}
});
I can unit test the get method by making sure the right API endpoint is being reached, with the right data.
I can test the build method by making sure it pulls data from the proper endpoints/services and builds what it's supposed to.
I can test the save method by making sure the right API endpoint is being reached.
What should I do to test the getOrCreate method? I get two differing opinions on this:
stub the get, build and save methods and verify they're called when appropriate, and with the proper parameters
stub the API endpoints that are being called in get and build, then verify that the endpoints within save are being called with the proper parameters
The first approach is basically saying, "I know these three methods work because they're independently tested. I don't care how they actually work, but I care that they're being called within this method."
The second approach is saying, "I don't care about how this method acts internally, just that the proper API endpoints are being reached"
Which of these approaches is more "correct"? I feel the first approach is less fragile since it's independent of how the get, build and save methods are implemented, but it's not quite right in that it's testing the implementation instead of the behavior. However, option 2 is requiring me to verify the behavior of these other methods in multiple test areas, which seems more fragile, and fragile tests make people hate programming.
This is a common tradeoff I find myself facing quite often with tests... anybody have suggestions on how to handle it?
This is going to come down to a matter of opinion.
If you are unit testing your tests should work on very specific functionality.
If you start chasing promises, and you have promise chaining, where does it stop?
Most importantly, as your unit test scope gets bigger and bigger, there are more things that it depends on (services, APIs etc...), and more ways in which it can brake that may have nothing to do with the "unit". The very thing that you want to make sure works.
Question: If you have a solid controller that works great with your template, and a unit test that ensures your controller is rock solid. Should a twice detached promise that resolves from the response of a web service http API call break your controller test?
On the other hand, the same way you test your API client end points by mocking the service, you can test the service with its own tests using something like Angular's $httpBackend service.
I have seen it done both ways and don't have a strong preference either way. Personally, however, I would consider option 1 where you don't mock the other functions that are tested elsewhere to be integration tests because they're calling multiple publicly visible functions and therefore would prefer option 2.

How to Make a Synchronous Call an Asynchronous Call in Angular?

I have an app that shows statuses for internal processes. It also has a separate view that allows you to set up new records. To set up a new record, you fill out a form, and upon submit a call is made to my nodejs server that:
inserts the record into a table
kicks off a stored procedure
routes you back to the status page
The issue here, is that the page hangs while this happens, as sometimes the stored procedure takes a minute or two to run. So you wait for a couple minutes, and then are routed back to the status page.
Now, I don't actually care to see any exit code for this stored proc on the front end, as you will see the status of it on the status page. I'm wondering if there's a way for me to kick this process off, but not have the front end care about the return.
I've tried adding in the $location.path() before the $http call to the server, but then the $http call never happens.
Any ideas?
Thanks!
You can wrap the stored procedure call in a promise. The browser will make the call and continue on without waiting for it to complete and you can react appropriately in the resolve or reject functions. You can use angular's $q service:
insertRecord();
$q(function() {
storedProcCall();
});
redirect();

what is a Backbone model.save( ) call expecting on a POST operation?

I'm calling save() on a backbone model to do a POST operation on the back-end. The operation completes successfully server-side (I can see the record added and the response status comes back as 200). Currently the RESTful api call is returning the ID of the inserted record in the response body. I have success and error callbacks defined that I pass to the save call, but success is never called. Instead, the Backbone code is choking on that ID that gets returned from the REST call. Is there a better way for me to handle this from the client end or should the REST api implementation be returning something else?
By default I believe it expects the changed properties of the object as JSON. See: http://documentcloud.github.com/backbone/#Sync

How do I cancel an asynchronous operation in Silverlight/WCF?

I am calling an asynchronous service from my Silverlight app and I want to be able to cancel that call after it is made. There is an option for e.Cancelled once the service has finished (i.e. If e.Cancelled Then), but how to you set that cancelled to true after you have called it? How do you cancel that asynchronous call?
Let me clarify a bit... what I am trying to do is call the SAME method twice, one right after the other, and get the results of the last call into my collection. If I call an asynchronous method twice there is no guarantee that the second call will return first, so I may end up with the results of the first call coming in last and having the wrong results in my collection. So what I would like to do is cancel the first call when I make the second so I don't get results back from the first call. Seeing as how there is a Cancelled flag in the completed event args I figure you should be able to do this. But how?
It's async... the transfer is passed off to a remote server and it does not return until the server is done with it.
Basically the server will keep going, but you don't have to wait for the response. Disconnect your service completed event handler and pretend it was never called. That will give the effect of cancelling the operation.
If you really need to cancel something in progress on the server you would need to make another call to the server to cancel the first call. Assuming the first call is a very slow one, this might be possible.
Update (as question changed)
In the case you specify, it will be up to the server to cancel a operation in progress if a second one comes through, not up to the client. e.Cancelled is set server-side.
However... :)
You have exposed a client usability issue. Shouldn't you also delay sending any service request until an idle delay has passed. That way rapid selections will not result in multiple service calls.
Also... :>
You may also want to send a sequence number to your service calls and return that as part of the result. Then you will know if it is the latest request or not.
It sounds like what you really want to do is ignore the responses of all but the most recent call.
Set a unique ID (could be request #, a Guid, timestamp, or whatever) with the request, and make sure the service sends that same value back. Keep around the ID of the most recent request and ignore response that don't match that ID.
This will be safer than cancelling the first request, since if the service has already started sending the response before the cancel request happens, you still get your error condition.

Resources