Search code examples
angularjsunit-testingcontrollerkarma-runnerangular-routing

Unit-testing secondary routing controller


Currently i'm developing a simple pizza-webshop for a school assignment. I'm experienced in Java & C# but AngularJS is new to me.

I created a single page application with 1 main order controller (index contains an overview of the total order) and another menu controller to load the .JSON menu into a partial view.

The order controller is set in the index as follows;

index.html

    <html ng-app="pizzaApp" ng-controller="orderCtrl">
<head>
    <link rel="stylesheet" href="CSS/style.css"/>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular-route.min.js"></script>
    <script src="Apps/pizzaApp.js"></script>
    <script src="Controllers/menuCtrl.js"></script>
    <script src="Controllers/orderCtrl.js"></script>
</head>

and the menu controller is set in the app's routing as follows;

pizzaApp.js

var app = angular.module("pizzaApp", ["ngRoute"]);

    // View routing
    app.config(function ($routeProvider) {
        $routeProvider
            .when('/', {
                templateUrl : 'Views/main.html'
            })
            .when('/pizzas', {
                templateUrl: 'Views/pizzas.html',
                controller: 'menuCtrl'
            })
            .when('/pizzas/:param', {
                templateUrl: 'Views/pizzaInfo.html',
                controller: 'menuCtrl'
            })
            .when('/orders', {
                templateUrl: 'Views/orders.html',
            })
    });

I managed to write a working (and passing) unit-test for the order controller as follows;

orderCtrl.spec.js

describe('Controllers', function() {
    beforeEach(module('pizzaApp'));

    var $controller;

    beforeEach(inject(function(_$controller_){
      $controller = _$controller_;
    }));

    describe('orderCtrl Test', function() {
      var $scope, controller;

      beforeEach(function() {
        $scope = {};
        controller = $controller('orderCtrl', { $scope: $scope });
      });

      it('orderCtrl.addPizza methode', function() {
         //code...
      });

      it('orderCtrl.clearList methode', function() {
         //code...
      });

    });
  });

However, if i try to write a simple unit test for the menu controller in the exact same way, it says the scope/controller is undefined and/or gives me back nulls resulting in the following error message;

Expected null to equal [  ].
        at UserContext.<anonymous> (C:/Users/Ken/Git repositories/angular-phonecat/app/practicum/Unit_tests/menuCtrl.spec.js:88:34)
    Error: Unexpected request: GET Models/menu.json
    Expected GET ../Models/menu.json

menuCtrl.spec.js

describe('menuCtrl Tests', function() {
    beforeEach(module('pizzaApp'));

    var $controller, $httpBackend;

    beforeEach(inject(function(_$controller_, _$httpBackend_){
        $controller = _$controller_;
        $httpBackend = _$httpBackend_;
        $httpBackend.expectGET("../Models/menu.json").respond([{name: 'Margaritha'}, {name: 'Shoarma'}, {name: 'Supreme'}]);

    }));

    describe('menuCtrl Tests', function() {
      var $scope, controller;

        beforeEach(function() {
            $scope = {};
            controller = $controller('menuCtrl', { $scope: $scope});
        });

        it('should create a `menu` property with 3 pizzas with `$httpBackend`', function() {
            jasmine.addCustomEqualityTester(angular.equals);

             expect($scope.Menu).toEqual([]);

             $httpBackend.flush();
             expect($scope.Menu).toEqual([{name: 'Margaritha'}, {name: 'Shoarma'}, {name: 'Supreme'}]);
           });



    });
  });

menuCtrl.js

app.controller('menuCtrl', function ($scope, $http, $routeParams) {

    $scope.param = $routeParams.param;  //URL Parameter (.../index.html#!/pizzas/#)
    $scope.test="123";

    //Menu array inladen vanuit .JSON
    $http.get('Models/menu.json')
        .then(function (menu) {
            $scope.Menu = menu.data;

        });

});

I have read the f*cking manual, searched google for many-many hours, read all similar questions on stack and i have been trying to solve this for about 2 weeks total, all to no avail...

I have tried changing the unit tests, controllers, front-end, routing, dependency injections, using controller instead of scope, etc. etc. ... and i am COMPLETELY stuck!


Solution

  • In menuCtrl.js, add:

    $scope.Menu = [];
    

    before the GET request, i.e. after

    $scope.test="123";
    

    The test is expecting a scope variable Menu to exist and since it is not initialized until after the GET request, the test is not passing.

    Also a side note, In the test, you are expecting a GET request to the URI "../Models/menu.json" (in $httpBackend.expectGET()) and making the GET request to the URI "Models/menu.json". If this is unintentional, you may need to change either of those values