Testing angular services with Jasmine

Drop in your code, drop in your Jasmine specs, and away you go!

by munir

HTML

<script src="http://pivotal.github.io/jasmine/lib/jasmine-1.3.1/jasmine.js"></script>
<script src="http://pivotal.github.io/jasmine/lib/jasmine-1.3.1/jasmine-html.js"></script>
<link rel="stylesheet" href="http://pivotal.github.io/jasmine/lib/jasmine-1.3.1/jasmine.css">
<script src="http://code.angularjs.org/1.0.5/angular.js"></script>
<script src="http://code.angularjs.org/1.0.5/angular-mocks.js"></script>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    
    <head>
        <title>Jasmine Spec Runner</title>
        <script type="text/javascript">
            (function() {
                var jasmineEnv = jasmine.getEnv();
                jasmineEnv.updateInterval = 1000;

                var htmlReporter = new jasmine.HtmlReporter();

                jasmineEnv.addReporter(htmlReporter);

                jasmineEnv.specFilter = function(spec) {
                    return htmlReporter.specFilter(spec);
                };

                var currentWindowOnload = window.onload;

                window.onload = function() {
                    if (currentWindowOnload) {
                        currentWindowOnload();
                    }
                    execJasmine();
                };

                function execJasmine() {
                    jasmineEnv.execute();
                }

            })();
        </script>
    </head>
    
    <body></body>

</html>

JavaScript

//--- CODE --------------------------
angular.module('myApp', []).provider('MyService', function () {
    this.$get = ['$http', '$q', function ($http, $q) {
        function doGet(value) {
            var defer = $q.defer();

            $http({
                method: 'GET',
                url: '/someUrl',
                headers: {
                    'Accept-Language': 'en'
                },
                params: {
                    key1: value
                }
            }).
            success(function (data, status, headers, config) {
                // this callback will be called asynchronously
                // when the response is available
                defer.resolve();
            }).
            error(function (data, status, headers, config) {
                // called asynchronously if an error occurs
                // or server returns response with an error status.
                defer.reject();
            });

            return defer.promise;
        }
        var state;
        return {
            sendHttp: function (value) {
                doGet(value);
                state = value;
            },
            getState: function () {
                return state;
            }
        };
    }];
});

// ---SPECS-------------------------

describe('myApp', function () {
    var myService, $httpBackend;
    var expectedUrl = '/someUrl?key1=value1';
    beforeEach(function () {
        module('myApp');
        inject(function (MyService, _$httpBackend_) {
            myService = MyService;
            $httpBackend = _$httpBackend_;
        });
    });
    afterEach(function () {
        $httpBackend.verifyNoOutstandingExpectation();
        $httpBackend.verifyNoOutstandingRequest();
    });
    it('sends http requests', inject(function ($rootScope, $controller, $httpBackend) {
        $httpBackend.expectGET(expectedUrl).respond(200, '{"key":"value"}');
        myService.sendHttp('value1');
        $httpBackend.flush();
       ...