web-dev-qa-db-fra.com

Jasmine teste les directives AngularJS avec templateUrl

J'écris des tests de directives pour AngularJS avec Jasmine et j'utilise templateUrl avec eux: https://Gist.github.com/tanepiper/62bd10125e8408def5cc

Cependant, lorsque j'exécute le test, j'obtiens l'erreur incluse dans le Gist:

Error: Unexpected request: GET views/currency-select.html

D'après ce que j'ai lu dans les documents, je pensais que je faisais cela correctement, mais il ne semble pas que ce soit - qu'est-ce qui me manque ici?

Merci

70
Tane Piper

Si vous utilisez ngMockE2E ou ngMock:

toutes les requêtes HTTP sont traitées localement à l'aide des règles que vous spécifiez et aucune n'est transmise au serveur. Étant donné que les modèles sont demandés via HTTP, ils sont également traités localement. Étant donné que vous n'avez rien spécifié à faire lorsque votre application tente de se connecter à views/currency-select.html, il vous indique qu'il ne sait pas comment le gérer. Vous pouvez facilement dire à ngMockE2E de transmettre votre demande de modèle:

$httpBackend.whenGET('views/currency-select.html').passThrough();

N'oubliez pas que vous pouvez également utiliser des expressions régulières dans vos chemins de routage pour parcourir tous les modèles si vous le souhaitez.

Les docs en discutent plus en détail: http://docs.angularjs.org/api/ngMockE2E.$httpBackend

Sinon, utilisez ceci:

Vous devrez utiliser le $injector pour accéder au nouveau backend. À partir des documents liés:

var $httpBackend;
beforeEach(inject(function($injector) {
  $httpBackend = $injector.get('$httpBackend');
  $httpBackend.whenGET('views/currency-select.html').respond(200, '');
}));
70
Josh David Miller

la manière Karma est de charger dynamiquement le modèle html dans $ templateCache. vous pouvez simplement utiliser le pré-processeur html2js karma, comme expliqué ici

cela revient à ajouter des modèles '. html' à vos fichiers dans le fichier conf.js ainsi que des préprocesseurs = {'. html': 'html2js' };

et utilise

beforeEach(module('..'));

beforeEach(module('...html', '...html'));

dans votre fichier de test js

20
Lior

S'il s'agit d'un test unitaire, vous n'aurez pas accès à $httpBackend.passthrough(). Cela n'est disponible que dans ngMock2E2, pour des tests de bout en bout. Je suis d'accord avec les réponses impliquant ng-html2js (Anciennement nommé html2js) mais je voudrais les développer pour fournir une solution complète ici.

Pour rendre votre directive, Angular utilise $http.get() pour récupérer votre modèle à partir de templateUrl. Parce que c'est un test unitaire et que angular-mocks Est chargé , angular-mocks Intercepte l'appel à $http.get() et vous donne l'erreur Unexpected request: GET. Vous pouvez essayer de trouver des moyens de contourner cela, mais il est beaucoup plus simple d'utiliser simplement les angulaires $templateCache Pour précharger vos modèles. De cette façon, $http.get() ne sera même pas un problème.

C'est ce que le préprocesseur ng-html2js fait pour vous. Pour le faire fonctionner, installez-le d'abord:

$ npm install karma-ng-html2js-preprocessor --save-dev

Configurez-le ensuite en ajoutant/mettant à jour les champs suivants dans votre karma.conf.js

{
    files: [
      //
      // all your other files
      //

      //your htmp templates, assuming they're all under the templates dir
      'templates/**/*.html'
    ],

    preprocessors: {
        //
        // your other preprocessors
        //

        //
        // tell karma to use the ng-html2js preprocessor
        "templates/**/*.html": "ng-html2js"
    },

    ngHtml2JsPreprocessor: {
        //
        // Make up a module name to contain your templates.
        // We will use this name in the jasmine test code.
        // For advanced configs, see https://github.com/karma-runner/karma-ng-html2js-preprocessor
        moduleName: 'test-templates',
    }
}

Enfin, dans votre code de test, utilisez le module test-templates Que vous venez de créer. Ajoutez simplement test-templates À l'appel de module que vous effectuez généralement dans beforeEach, comme ceci:

beforeEach(module('myapp', 'test-templates'));

La navigation devrait être fluide à partir de maintenant. Pour un examen plus approfondi de ce scénario et d'autres scénarios de test de directive, consultez cet article

6
lastoneisbearfood

Vous pourriez peut-être obtenir le $templatecache de l'injecteur, puis faites quelque chose comme

$templateCache.put("views/currency-select.html","<div.....>");

où à la place de <div.....> vous mettriez votre modèle.

Après cela, vous configurez votre directive et cela devrait très bien fonctionner!

5
ganaraj

Comme demandé, convertir un commentaire en réponse.


Pour les personnes qui souhaitent utiliser la réponse de @ Lior dans les applications Yeoman :

Parfois, la façon dont les modèles sont référencés dans karma config et par conséquent - les noms des modules produits par ng-html2js ne correspond pas aux valeurs spécifiées comme templateUrls dans les définitions de directive.
Vous devrez ajuster les noms des modules générés pour qu'ils correspondent à templateUrls.
Ceux-ci pourraient être utiles:

4
vucalur

Si cela ne fonctionne toujours pas, utilisez fiddler pour voir le contenu du fichier js généré dynamiquement par le processeur htmltojs et vérifiez le chemin du fichier modèle.

Ça devrait être quelque chose comme ça

angular.module('app/templates/yourtemplate.html', []).run(function($templateCache) {
  $templateCache.put('app/templates/yourtemplate.html', 

Dans mon cas, ce n'était pas la même chose que j'avais dans ma directive actuelle qui était à l'origine du problème.

Avoir le templateURL exactement le même dans tous les endroits m'a aidé.

4
akshayswaroop

c'est par exemple comment tester une directive qui utilise partial comme templateUrl

describe('with directive', function(){
  var scope,
    compile,
    element;

  beforeEach(module('myApp'));//myApp module

  beforeEach(inject(function($rootScope, $compile, $templateCache){
   scope = $rootScope.$new();
   compile = $compile;

   $templateCache.put('view/url.html',
     '<ul><li>{{ foo }}</li>' +
     '<li>{{ bar }}</li>' +
     '<li>{{ baz }}</li>' +
     '</ul>');
   scope.template = {
     url: 'view/url.html'
    };

   scope.foo = 'foo';
   scope.bar = 'bar';
   scope.baz = 'baz';
   scope.$digest();

   element = compile(angular.element(
    '<section>' +
      '<div ng-include="template.url" with="{foo : foo, bar : bar, baz : baz}"></div>' +
      '<div ng-include="template.url" with=""></div>' +
    '</section>'
     ))(scope);
   scope.$digest();

 }));

  it('should copy scope parameters to ngInclude partial', function(){
    var isolateScope = element.find('div').eq(0).scope();
    expect(isolateScope.foo).toBeDefined();
    expect(isolateScope.bar).toBeDefined();
    expect(isolateScope.baz).toBeDefined();
  })
});
2
a8m

Si vous utilisez jasmine-maven-plugin avec RequireJS, vous pouvez utiliser plugin texte pour charger le contenu du modèle dans une variable, puis le placer dans le cache du modèle.


define(['angular', 'text!path/to/template.html', 'angular-route', 'angular-mocks'], function(ng, directiveTemplate) {
    "use strict";

    describe('Directive TestSuite', function () {

        beforeEach(inject(function( $templateCache) {
            $templateCache.put("path/to/template.html", directiveTemplate);
        }));

    });
});
0