13

I am trying to figure out how to test my AngularJS service that has a dependency on $http.

When using $httpBackend to mock that AJAX post (whenPOST), does the object you post determine the response?

Here is my service and my test for example:

(function () {
    "use strict"

    var app = angular.module('cs');

    app.service('PlateCheckService', ['$http', function ($http) {
        return {
            checkPlate: function (plateNumber) {
                return $http.post('PlateCheck/Index', {
                    plateNumber: plateNumber
                }).then(function (response) {
                    return {
                        message: response.data.VehicleAtl === null ? 'Clean' : 'Hot',
                        alertClass: response.data.VehicleAtl === null ? 'alert-success' : 'alert-danger'
                    }
                });
            }
        }
    }]);

}());

Tests

/// <reference path="../libs/angular-1.0.8/angular.js" />
/// <reference path="../libs/angular-1.0.8/angular-mocks.js" />
/// <reference path="../libs/jasmine-1.3.0/jasmine.js" />
/// <reference path="../app.js" />
/// <reference path="../services/plate-check-service.js" />

describe('Plate Check Service', function () {
    var httpBackend,
        service;

    beforeEach(function () {
        module('cs');

        inject(function ($httpBackend, PlateCheckService) {
            httpBackend = $httpBackend;
            httpBackend.whenPOST('PlateCheck/Index', { plateNumber: '123456' }).respond({
                response: {
                    message: 'Clean',
                    alertClass: 'alert-success'
                }
            });
            httpBackend.whenPOST('PlateCheck/Index', { plateNumber: '123456789' }).respond({
                response: {
                    message: 'Hot',
                    alertClass: 'alert-danger'
                }
            });

            service = PlateCheckService;
        });
    });

    it('Should return a clean plate.', function () {
        var result;

        service.checkPlate('123456').then(function (response) {
            result = response;
        });

        httpBackend.flush();
        expect(result.message).toBe('Clean');
        expect(result.alertClass).toBe('alert-success');
    });
});

Test Results

Test 'Plate Check Service:Should return a clean plate.' failed
    Expected 'Hot' to be 'Clean'.
    Expected 'alert-danger' to be 'alert-success'.
in D:\Code\Scripts\angular\specs\plate-check-service-specs.js (line 35)

0 passed, 1 failed, 1 total (chutzpah).

========== Total Tests: 0 passed, 1 failed, 1 total ==========

It looks like it is not taking into account the plateNumber I am passing to the service which posts it to the server.

I would have expected this test to pass.

Does that make any sense?

1 Answer 1

10

You are using a when instead of a expect. $httpBackend can run in two different modes. From the docs:

There are two ways to specify what test data should be returned as http responses by the mock backend when the code under test makes http requests:

  • $httpBackend.expect - specifies a request expectation
  • $httpBackend.when - specifies a backend definition

Request Expectations vs Backend Definitions Request expectations provide a way to make assertions about requests made by the application and to define responses for those requests. The test will fail if the expected requests are not made or they are made in the wrong order.

Backend definitions allow you to define a fake backend for your application which doesn't assert if a particular request was made or not, it just returns a trained response if a request is made. The test will pass whether or not the request gets made during testing.

If you change your setup to use an expectPOST, then the mock will take the request into account.

Hope this helps.

Sign up to request clarification or add additional context in comments.

3 Comments

Should the expect go in the it or in the beforeEach like the when? Also, when would you use one over the other?
When you want to use the response use expect. You can put set in the beforeEach or in the it depending on how many tests are sharing your setup. However, it is preferable to localize setup near the test (as much as possible).
In the docs it says "Backend definitions ... just returns a trained response if a request is made" so I don't understand why backend definitions are not working in this case?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.