J'essaie de commencer avec les tests Karma, en les ajoutant à une application existante Angular.
Ceci est mon fichier de définition d'application principal:
angular
.module('myApp', [
'ngRoute',
'moduleAdherence'
]);
Voici mon fichier contrôleur:
angular
.module('moduleAdherence', [])
.controller('AdherenceCtrl', ['$scope', function ($scope) {
$scope.awesomeThings = [1,2,3,4];
}]);
Ceci est mon premier coup de couteau dans un fichier:
describe('Controller: AdherenceCtrl', function () {
beforeEach(module('myApp'));
var MainCtrl,
scope;
beforeEach(inject(function ($controller, $rootScope) {
scope = $rootScope.$new();
MainCtrl = $controller('AdherenceCtrl', {
$scope: scope
});
}));
it('should attach a list of awesomeThings to the scope', function () {
expect(scope.awesomeThings.length).toBe(4);
});
});
Lorsque j'essaie d'exécuter cela avec grunt test
, il échoue avec l'erreur suivante:
Uncaught Error: [$injector:nomod] Module 'd3' is not available!
You either misspelled the module name or forgot to load it.
If registering a module ensure that you specify the dependencies
as the second argument.
http://errors.angularjs.org/1.2.0/$injector/nomod?p0=d3
at /Users/me/Dropbox/projects/myapp/app/bower_components/angular/angular.js:1498
Je ne comprends pas cela, car ce contrôleur n'utilise pas D3. J'utilise D3 ailleurs dans l'application, dans une directive, mais je ne l'enregistre pas avec le module (j'utilise le fichier D3 externe).
Pourquoi Karma remarque-t-il D3? Ne devrait-il pas pouvoir tester ce contrôleur sans D3?
Dans le fichier de configuration de karma (karma.conf.js), vous devez définir toutes les bibliothèques.
etc.
// list of files / patterns to load in the browser
files: [
'app/lib/angular/angular.js',
'app/lib/angular-route/angular-route.js',
'test/lib/angular-mocks.js',
'app/app.js',
'app/controllers/*.js',
'app/services/*.js',
'app/*',
'test/spec/**/*.js'
],
J'ai eu un problème similaire et ma solution (inspirée en quelque sorte par le commentaire @danba) était de charger les scripts dans le files
dans le exact dans le même ordre que celui qu'ils étaient chargés dans le index.html. Dans mon cas, les modèles de globbing comme app/scripts/**/*.js
causait des problèmes au karma qui provoquait constamment des erreurs.
Ce n'est peut-être pas la solution la plus élégante pour copier toutes les définitions de scripts mais a finalement fonctionné pour que mon test puisse enfin reprendre. J'espère que ça aide.
EDIT: Modifier cela parce qu'aujourd'hui j'ai probablement (et j'espère ) compris ce qui n'allait pas ici. Il semble donc que Karma n'aime pas les modèles globbing lorsque le même module est défini dans un fichier et utilisé dans de nombreux fichiers différents. Disons que la structure de votre dossier est la suivante:
Supposons que dans AuthService.js
vous avez votre définition de module pour tous vos services dans ce dossier, de sorte que ce fichier commence par:
angular.module('myApp.services', [
'myApp.urls',
'ngCookies'
])
Ensuite, dans tous les autres fichiers, vous attachez simplement d'autres services à ce même module. Dans la photo tokenService.js
commencerait par:
angular.module('myApp.services');
Si tout reste ainsi, tout fonctionnera probablement. Mais si par hasard je définis le module dans l'autre sens, la définition du module n'est donc plus dans le premier fichier de ce dossier mais dans un autre que Karma lit après AuthService
alors il va lancer une erreur et refuser de terminer les tests.
Une solution pourrait être de placer la définition du module dans son propre fichier, en commençant par un trait de soulignement. Enfin, laissez tous les fichiers frères et sœurs dépendre de celui-ci. La structure de dossiers ci-dessus devrait donc être:
Une autre solution, probablement meilleure, consiste à marquer les fichiers dans lesquels les modules sont définis avec un suffixe/extension commun, par exemple service.module.js
tandis que les fichiers qui en dépendent peuvent être nommés normalement comme authService.js
, tokenService.js
. La configuration de Karma à ce stade deviendra quelque chose comme:
// list of files / patterns to load in the browser
files: [
'app/lib/angular/angular.js',
'test/lib/angular-mocks.js',
'app/app.js',
'app/**/*.module.js', // <-- first the module definitions...
'app/**/*.js', // <-- ..then all the other files
'test/spec/**/*.js'
],
De cette façon, le karma chargera d'abord les définitions des modules, puis les fichiers qui en dépendent.
Voici une solution simple qui a fonctionné pour moi, basée sur la solution n ° 1 ci-dessus de @Nobita ET le commentaire de @ danba.
Dans karma.conf.js, chargez explicitement le fichier de prérequis au-dessus du modèle qui extrait le reste:
files: [
...
'app/module.js',
'app/*.js'
]
Karma ne semble pas s'inquiéter que le modèle corresponde également à "module.js".
Chargez toujours la version non réduite de angular dans le karma. Cela affichera des erreurs et vous aidera à mieux savoir quoi changer. Dans votre cas, c'est l'ordre des fichiers chargés par karma.
Vérifiez votre index.html que vous n'incluez pas quelque chose par une balise de script comme.
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5angular-resource.js"
Tout votre fichier Javascript doit être dans votre karma.config.js
J'ai également eu le même problème, dans mon cas, un problème s'est produit car il y avait plusieurs fichiers par module, ce qui est une mauvaise pratique car nous pouvons pointer vers le module non initialisé. Résolu cela en incluant un seul fichier par module.