Mocking Angular’s $http Promise return type using only Mocks
Last week, we had a look at Mocking Angular’s $http Promise return type using the $q library. This gives you a great deal of control over when your mock promises are resolved. But, it comes at the cost of requiring both the $q library and manually calling $rootscope.$apply().
If you want to avoid those (and you don’t mind losing that bit of control), then you can do something very similar just with mocks.
Promise Service
We’ll use the same service that returns a promise as before:
And the same controller using the service:
Building a Promise
Our mock-only promise helper will have slightly different public methods from our previous version. When using mocks, we’ll set up our methods to immediately respond to requests, so we need to set up return handlers at the start of the test.
constructor: create a new helper
getHttpPromiseMock: get a mock promise return type
Our constructor uses Jasmine to create a new mock object with the public methods we need to match the HTTP promise return type.
Since the return object is chainable, we set default return value on each of the methods to return the same promise. This means that the mock will fulfil the minimal implementation on creation.
getHttpPromiseMock
For our mock object, we want to create something that looks and acts like a promise. We already have the mock object created in the class, so we just need to return a reference to that.
willResolveWith
For promise resolution, the promise will accept a callback to the success method. This callback will be called with the return data from the request. We need to mock this.
We can pass in the fulfilment data to the willResolveWith method of our mock and use Jasmine’s callFake function to set up a dummy method that can be called. This dummy method will invoke the callback with the test data and then return an instance of the mock promise for chaining.
willReject
Our willReject method is very similar. We can use the same callFake function to set up a dummy handler to handle error calls on the mock and pass through the promise for chaining.
Our full helper class looks like this:
So, now that we have that, how do we use it?
Testing Methods that Return a Promise
Just as a reminder, our controller looks like this:
We’ll need some test data along with our helper, so we’ll set these up in our beforeEach function of our Jasmine test. We’ll also create a new instance of the PromiseHelper.
Then, in our tests, we can use Jasmine mocking to create a version of our service.
Just for clarity, this is firstly creating a new Jasmine Spy object with the function getContacts.
Then we’re setting the return type of this Spy to return a mock HTTP promise from our helper class.
Putting this together with a full test then looks something like this:
On lines 7-9, we’re setting up the return data for our promise when success is called. Since the methods within the mock service are Jasmine Spies, we can explicitly check that the method has been called on line 20.
Testing for Rejection
If we wanted to test for a rejected promise, our test would look like this:
On lines 7-9, we’re setting up our promise to reject.
Our controller throws an error when the service rejects the promise, so we can check for this using Jasmine’s toThrow method on the promise call (lines 15-17).