2

I'm trying to write a unit test for a controller which fetches article details using $http service.

Controller:

 .controller('ArticleDetailCtrl',function($scope, Article, $routeParams, API_URL, ARTICLE_URL, $http, $sce){

    $scope.url = API_URL + ARTICLE_URL + '/' + $routeParams.articleId;

    $http.get($scope.url).then(function(response) {
        //console.log(response.data);
        $scope.heading = response.data.Headline;
        $scope.rawBody = response.data.Body;
        $scope.body = $sce.trustAsHtml($scope.rawBody);
        $scope.image = response.data.Assets[0].URL;
    });   
    });

Unit test:

'use strict';

describe('Controller: Article', function () {

    var scope,
        $httpBackend,
        articleEndpoint;



    // load the controller's module
    beforeEach(module('myApp'));


    describe('ArticleDetailCtrl', function () {

        var ArticleDetailCtrl,
            jsonObject,
            ArticleId = '123';

        // Initialize the controller and a mock scope
        beforeEach(inject(function ($controller, $rootScope, _$httpBackend_, Article, API_URL, ARTICLE_URL) {

            scope = $rootScope.$new();
            ArticleDetailCtrl = $controller('ArticleDetailCtrl', { $scope: scope });
            $httpBackend =  _$httpBackend_;
            articleEndpoint = API_URL + ARTICLE_URL + '/' + ArticleId;

            jsonObject = {
                'Headline': 'Headline',
                'Body': '<p>Body</p>',
                'Assets': [
                    {
                        'URL': 'path/to/image/article1.jpg'
                    }
                ]
            };

            $httpBackend.when('GET', articleEndpoint).respond(jsonObject);
        }));

        afterEach(function() {
            $httpBackend.verifyNoOutstandingExpectation();
            $httpBackend.verifyNoOutstandingRequest();
        });

        it('should fetch article details from the API', function () {
            //expect(scope.articles.length).toEqual(3);

            $httpBackend.expectGET(articleEndpoint);
            $httpBackend.flush();
        });

    });    

});

But I keep on getting the following error:

Error: Unexpected request: GET http://localhost:3000/api/articles/undefined
Expected GET http://localhost:3000/api/articles/123
    at $httpBackend (/Users/gill/Documents/projects/angularjs-test/app/bower_components/angular-mocks/angular-mocks.js:1179)
    at sendReq (/Users/gill/Documents/projects/angularjs-test/app/bower_components/angular/angular.js:8181)
    at /Users/gill/Documents/projects/angularjs-test/app/bower_components/angular/angular.js:7921
    at /Users/gill/Documents/projects/angularjs-test/app/bower_components/angular/angular.js:11319
    at /Users/gill/Documents/projects/angularjs-test/app/bower_components/angular/angular.js:11405
    at /Users/gill/Documents/projects/angularjs-test/app/bower_components/angular/angular.js:12412
    at /Users/gill/Documents/projects/angularjs-test/app/bower_components/angular/angular.js:12224
    at /Users/gill/Documents/projects/angularjs-test/app/bower_components/angular-mocks/angular-mocks.js:1438
    at /Users/gill/Documents/projects/angularjs-test/test/spec/controllers/article.js:77
Error: Unsatisfied requests: GET http://localhost:3000/api/articles/123
    at /Users/gill/Documents/projects/angularjs-test/app/bower_components/angular-mocks/angular-mocks.js:1472
    at /Users/gill/Documents/projects/angularjs-test/test/spec/controllers/article.js:65

This is the first time am writing unit tests which I followed along by reading some tutorials. I don't know what am I doing wrong?

4
  • Do you set route in your angular code ? An .config Commented Jul 7, 2014 at 12:14
  • You haven't set the variable articleId on $routeParams Commented Jul 7, 2014 at 12:18
  • @Lucas_Santos Yes I have set route in the main file app.js Commented Jul 7, 2014 at 12:25
  • @JonSamwell I did set it to 123 Commented Jul 7, 2014 at 12:26

1 Answer 1

5

Your problem is a simple, but a common one.

When you write your Jasmine / Karma unit tests, creating your controllers are almost automatic using the $controller service. That means, for the most part, you can say from your unit test

$controller('ArticleDetailCtrl')

And AngularJS will figure out its dependent services, inject them and create an instance of the controller for you to unit test.

There is one exception to this:

AngularJS does not know how to inject context specific services like $scope and $routeParams, which change based on the HTML structure and the URL for each instance of the controller.

I notice in your unit test you create the controller as

ArticleDetailCtrl = $controller('ArticleDetailCtrl', { $scope: scope });

So at this point, you tell AngularJS what object to use when the controller asks for $scope as a dependent service. But in your controller, you also inject $routeParams. And based on its articleId you create the URL for the request.

So if you change your controller instantiation code to:

ArticleDetailCtrl = $controller('ArticleDetailCtrl', { 
    $scope: scope, 
    $routeParams: articleId: ArticleId
});

That should now create the correct URL (instead of using undefined for articleId, which was the error)

Let me know if that helps.

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

Comments

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.