web-dev-qa-db-fra.com

Comment injecter des dépendances dans le test de jasmin pour un élément angular

Voici le fichier de spécifications de test:

describe('Test main controller', function(){
        it('Should initialize value to Loading', function(){
            $scope = {}
            ctrl =  new mainNavController($scope)
            expect($scope.wksp_name).toBe('Loading')
        })
    })

Voici le fichier contrôleur

function mainNavController($scope) {
    $scope.wksp_name = 'Loading...'
    $scope.$on('broadCastWkspNameEvent', function (e, args) {
        $scope.wksp_name = args
    })
}

mainNavController.$inject=['$scope']

Mais mon test échoue en disant Object #<Object> has no method '$on'

J'utilise la configuration de base de jasmine.

<!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>

  <link rel="shortcut icon" type="image/png" href="testlib/jasmine-1.2.0/jasmine_favicon.png">
  <link rel="stylesheet" type="text/css" href="testlib/jasmine-1.2.0/jasmine.css">
  <script type="text/javascript" src="testlib/jasmine-1.2.0/jasmine.js"></script>
  <script type="text/javascript" src="testlib/jasmine-1.2.0/jasmine-html.js"></script>

  <!-- include source files here... -->
  <script type="text/javascript" src="/static_files/js/test-specs/main-nav-spec.js"></script>

  <!-- include spec files here... -->
  <script type="text/javascript" src="/static_files/js/common/jquery/latest.js"></script>
  <script type="text/javascript" src="/static_files/js/common/angular/angular-1.0.1.min.js"></script>
  <script type="text/javascript" src="/static_files/js/common/angular/angular-resource-1.0.1.min.js"></script>
  <script type="text/javascript" src="/static_files/js/section/main-nav-controller.js"></script>

  <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>

Qu'est-ce que je fais mal? Je ne peux pas comprendre comment cette chose est censée fonctionner :)

29

Le principal problème avec votre code de test est qu'il essaie de créer une instance de contrôleur "à la main" en utilisant le nouvel opérateur. Ce faisant, AngularJS n'a aucune chance d'injecter des dépendances. Ce que vous devriez faire, c'est autoriser les dépendances à injecter AngularJS:

var $scope, ctrl;

//you need to inject dependencies first
beforeEach(inject(function($rootScope) {
    $scope = $rootScope.$new();        
}));

it('Should initialize value to Loading', inject(function($controller) {
    ctrl = $controller('MainNavController', {
        $scope: $scope
    });
    expect($scope.wksp_name).toBe('Loading...');
}));

Voici le lien vers un jsFiddle complet: http://jsfiddle.net/pkozlowski_opensource/7a7KR/3/

Il y a 2 choses à noter dans l'exemple ci-dessus:

  1. Vous pouvez utiliser la méthode inject () du module ngMock pour injecter des dépendances: https://docs.angularjs.org/api/ngMock/function/angular.mock.inject
  2. Pour créer une instance de contrôleur (qui prend en charge l'injection de dépendances), vous utiliseriez le service $ controller: http://docs.angularjs.org/api/ng.$controller

Comme dernière remarque: je conseillerais de nommer les contrôleurs en commençant par une lettre majuscule - de cette façon, nous ne les confondrons pas avec les noms de variables.

59

Grande réponse de @ pkozlowski.opensource. Pour en savoir un peu plus ... Parfois, il pourrait également être utile d'affirmer que $scope.$on a vraiment été appelé par votre contrôleur. Dans ce cas, vous pouvez espionner $scope.$on comme indiqué ci-dessous:

beforeEach(inject(function($rootScope) {
    $scope = $rootScope.$new();        
    spyOn($scope, '$on').andCallThrough();
}));

Et puis vous pouvez affirmer que $on a été appelé avec votre nom d'événement et certaines fonctions comme arguments:

it('Should bind to "broadCastWkspNameEvent"', inject(function($controller) {
    ctrl = $controller('MainNavController', {
        $scope: $scope
    });
    expect($scope.$on).toHaveBeenCalledWith('broadCastWkspNameEvent', jasmine.any(Function));
}));
17
zbynour

Je suis d'accord avec la réponse de pkozowski, mais pour répondre plus directement à votre question, vous devez supprimer "$ on"

Votre exemple réussirait si votre $ scope ressemblait à:

$scope = {
  $on: function() {}
}
4
Lee