Tuesday, February 16, 2016

Checking the State of a $q Promise in a Jasmine Test

I came across a situation where I wanted to verify that my Angular service was correctly resolving or rejecting a $q.defer() object and I had a bit of trouble getting it worked out.

The function on the service looks like this:
this.get = function (id) {
    var deferred = $q.defer();

    $http({
        url: "http://localhost/GetPersonById?Id=" + id,
        method: "GET"
    }).success(deferred.resolve).error(deferred.reject);

    return deferred.promise;
};

I want to have two tests.  One test will confirm that when a successful (200 level) response is returned from the server, deferred is resolved.  The other test will confirm that when a failure (400 level) response is returned from the server, deferred is rejected.

The problem is that you can't really test the state of the deferred object.  Fortunately, the workaround turned out to be pretty simple.

Test for success:
it('should return resolved promise when server returns success', function () {
    $httpBackend.whenGET(url).respond(200);
    var wasSuccess = false;
    var wasError = false;

    var result = addressRepository.getByPersonId(1, 2, 3);

    result.then(function () { wasSuccess = true; }, function() { wasError = true; });

    $httpBackend.flush();

    expect(wasSuccess).toBe(true);
});

Test for failure:
it('should return rejected promise when server returns failure', function () {
    $httpBackend.whenGET(url).respond(400);
    var wasSuccess = false;
    var wasError = false;

    var result = addressRepository.getByPersonId(1, 2, 3);

    result.then(function () { wasSuccess = true; }, function() { wasError = true; });

    $httpBackend.flush();

    expect(wasError).toBe(true);
});

result is the promise of the deferred so it is chainable using .then().  By invoking the .then() function and checking for the appropriate boolean to be true we can confirm the promise was resolved or rejected as we expected.

No comments:

Post a Comment