J'ai essayé de suivre le format de ng-directive-testing repo pour une directive que j'ai écrite. La directive rend essentiellement une superposition lorsque l'utilisateur clique sur un élément. Voici la directive (simplifiée):
mod.directive('uiCopyLinkDialog', function(){
return {
restrict: 'A',
link: function(scope, element, attrs) {
var $Elm = angular.element(element);
element.bind('click', function(event) {
$Elm.addClass('test');
});
}
};
});
Le test que j'écris ressemble à ceci:
describe('pre-compiled link', function () {
beforeEach(mocks.inject(function($compile, $rootScope) {
scope = $rootScope;
element = angular.element('<span class="foo" ui-copy-link-dialog="url"></span>');
$compile(element)(scope);
scope.$digest();
}));
it("should change the class when clicked", function () {
element.click(); // this returns "'undefined' is not a function"
element[0].click(); // so does this
$(Elm).click(); // this uses jquery and doesn't *seem* to fail
waits(500); // hack to see if it was a race condition
expect(Elm.className).toContain('test'); // always fails
});
});
Vous pouvez voir dans le test que j'essaie de plusieurs manières de déclencher l'événement click()
sur le lien, la plupart d'entre elles donnant une erreur undefined
.
Quelqu'un peut-il me dire ce que je fais mal ici? En lisant les exemples, cela semble être la syntaxe correcte, mais mon coureur de test (Karma via Grunt) ne veut pas jouer au ballon.
Donc, cela se est avéré être un problème avec PhantomJS: certains événements qui agissent sur les éléments ne semblent pas tirer lorsque les éléments ne sont pas réellement sur un document nulle part, mais juste en mémoire (qui est ma théorie, de toute façon). Pour contourner cela, je devais utiliser cette fonction pour déclencher des événements sur click
éléments:
define(function () {
return {
click: function (el) {
var ev = document.createEvent("MouseEvent");
ev.initMouseEvent(
"click",
true /* bubble */, true /* cancelable */,
window, null,
0, 0, 0, 0, /* coordinates */
false, false, false, false, /* modifier keys */
0 /*left*/, null
);
el.dispatchEvent(ev);
}
};
});
Cela a fonctionné, bien que d'autres choses étaient plus difficiles: Je voulais aussi écrire un test qui assure une input
forme donnée a le focus, mais obtenir cette valeur était presque impossible avec PhantomJS puisque je suppose que le navigateur ne peut pas faire quelque chose de concentré si elle n'a pas à l'écran représentation. Toute personne ayant besoin cela pourrait jeter un oeil à CasperJS qui offre une API simple pour certaines de ces exigences.
Vous pouvez utiliser triggerHandler, une partie de JQLite.
J'ai utilisé cela pour déclencher un événement de clic sur une directive ...
element = angular.element("<div myDirective-on='click'></div>");
compiled = $compile(element)($rootScope);
compiled.triggerHandler('click');
. Exemple complet disponible sur ce blog: .__ http://sravi-kiran.blogspot.co.nz/2013/12/TriggeringEventsInAngularJsDirectiveTests.html
Donc, ma solution à c'était à ajouter en fait l'élément au corps. Étant donné que la racine du problème est que PhantomJS ne se déclenche pas d'événements pour les éléments en mémoire, il semblait plus simple d'ajouter chaque élément afin que les événements travaillent pour de vrai.
afterEach(function(){
$('body').empty();
});
it('should do something when clicked', function(){
element = $compile('<div my-directive></div>')($scope);
$('body').append(element);
// fire all the watches, so the scope expressions will be evaluated
$rootScope.$digest();
$(element).find('.my-input').click();
});
J'ai eu du mal avec cela aussi. Il semble que click()
ne semble pas fonctionner du tout pour moi avec PhantomJS pour tout élément que je compile. Il revient toujours pas défini.
Bien que pas vraiment aussi bon que d'un clic réel, vous pouvez accéder à la fonction de la directive cliquez sur ng pour simuler un clic à travers elle est d'isoler la portée:
var element = $compile('<a ng-click="myfunc()">Click me</a>')(scope);
var isolateScope = element.isolateScope();
isolateScope.myfunc();
scope.$digest();
/* check that things changed ... */
Vous pouvez utiliser test-runner angulaire bibliothèque et un test ressemblera:
const testRunner = require('angular-test-runner');
describe('directive', () => {
let app;
const {expectElement, click} = testRunner.actions;
beforeEach(() => {
app = testRunner.app(['mod']);
});
it("should add class when clicked", function () {
const html = app.runHtml('<span class="foo" ui-copy-link-dialog="url"></span>');
html.perform(
click.in('.foo')
);
html.verify(
expectElement('.foo').toHaveClass('test')
);
});
});