J'ai la directive AngularJS suivante qui crée un élément input
. L'entrée a l'attribut ng-change
qui exécute la fonction doIt()
. Dans le test unitaire de ma directive, je souhaite vérifier si la fonction doIt
est appelée lorsque les utilisateurs modifient l'entrée. Mais le test ne passe pas. Bien que cela fonctionne dans le navigateur lorsque vous testez manuellement.
Directif:
...
template: "<input ng-model='myModel' ng-change='doIt()' type='text'>"
Tester:
el.find('input').trigger('change') // Dos not trigger ng-change
Démo en direct (ng-change): http://plnkr.co/edit/0yaUP6IQk7EIneRmphbW?p=preview
Maintenant, le test réussit si je lie manuellement l'événement change
au lieu d'utiliser l'attribut ng-change
.
template: "<input ng-model='myModel' type='text'>",
link: function(scope, element, attrs) {
element.bind('change', function(event) {
scope.doIt();
});
}
Démo en direct (liaison manuelle): http://plnkr.co/edit/dizuRaTFn4Ay1t41jL1K?p=preview
Existe-t-il un moyen d'utiliser ng-change
et de le rendre testable? Je vous remercie.
De votre commentaire explicatif:
Tout ce que je veux faire dans le test de la directive est de vérifier que
doIt
est appelé lorsque l'utilisateur modifie l'entrée.
Que l'expression indiquée par ng-change
soit correctement évaluée ou non relève vraiment de la directive ngModel
, je ne suis donc pas sûr de le tester de cette manière; au lieu de cela, je pense que les directives ngModel
et ngChange
ont été correctement implémentées et testées pour appeler la fonction spécifiée, et que l’appel de la fonction elle-même affecte la directive de manière correcte. Un test d'intégration ou de bout en bout peut être utilisé pour gérer le scénario d'utilisation complète.
Cela dit, vous pouvez obtenir l'instance ngModelController
qui pilote le rappel ngModel
change et définir vous-même la valeur d'affichage:
it('trigger doIt', function() {
var ngModelController = el.find('input').controller('ngModel');
ngModelController.$setViewValue('test');
expect($scope.youDidIt).toBe(true);
});
Comme je l’ai dit, cependant, j’ai l’impression que cela va trop loin dans les responsabilités de ngModel
, rompant avec les directives naturellement composables.
Exemple: http://plnkr.co/edit/BaWpxLuMh3HvivPUbrsd?p=preview
[Mettre à jour]
Après avoir jeté un coup d’œil à la source AngularJS, j’ai trouvé que ce qui suit fonctionnait également:
it('trigger doIt', function() {
el.find('input').trigger('input');
expect($scope.youDidIt).toBe(true);
});
Il semble que l'événement est différent dans certains navigateurs. input
semble fonctionner pour Chrome.
Exemple: http://plnkr.co/edit/rbZ5OnBtKMzdpmPkmn2B?p=preview
Voici le code AngularJS pertinent }, qui utilise le service $sniffer
pour déterminer quel événement déclencher:
changeInputValueTo = function(value) {
inputElm.val(value);
browserTrigger(inputElm, $sniffer.hasEvent('input') ? 'input' : 'change');
};
Même avec cela, je ne suis pas sûr que je testerais une directive de cette façon.
simple et ça marcheen votre test unitaire env:
spyOn(self, 'updateTransactionPrice');
var el = compile('<form name="form" latest novalidate json-schema="main.schema_discount" json-schema-model="main._data"><input type="text" ng-model="main._data.reverse_discount" ng-class="{ \'form-invalid\': form.reverse_discount.$invalid }" ng-change="main.transactionPrice(form);" name="reverse_discount" class="form-control-basic" placeholder="" ng-disabled="!main.selectedProduct.total_price"></form>')(scope);
el.find('input').triggerHandler('change');
expect(self.updateTransactionPrice).toHaveBeenCalled();
J'ai googlé "directive angulaire déclenchant-changement" et cette question de StackOverflow était le plus proche de tout ce qui m'était utile, je vais donc répondre "Comment déclencher un changement dans une directive", puisque d'autres vont atterrir sur cette page, et je ne sais pas comment fournir cette information.
Dans la fonction link de la directive, cela déclenchera la fonction ng-change sur votre élément:
element.controller('ngModel').$viewChangeListeners[0]();
element.trigger("change")
et element.trigger("input")
n'ont pas fonctionné pour moi, ni rien d'autre que j'ai pu trouver en ligne.
Par exemple, déclencher le changement de couleur sur le flou:
wpModule.directive('triggerChangeOnBlur', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.on('blur', function () {
element.controller('ngModel').$viewChangeListeners[0]();
});
}
};
}]);
Je suis désolé que cela ne réponde pas directement à la question de OP. Je serai plus qu'heureux de prendre des conseils judicieux sur où et comment partager ces informations.
J'ai essayé de faire en sorte que cela fonctionne, mais a échoué à chaque tentative. Finalement, j'ai conclu que le problème était mes options de modèle ng avec un paramètre anti-rebond sur onUpdate.
Si vous avez un anti-rebond, assurez-vous de choisir le service $ timeout. Dans angular mock, ce service de délai d'attente a été étendu avec une opération de vidage, qui gère toutes les requêtes/actions non satisfaites.
var tobetriggered = angular.element(element[0].querySelector('.js-triggervalue'));
tobetriggered.val('value');
tobetriggered.trigger('change');
$timeout.flush();
Je cherchais cette simple ligne pendant de longues heures ... juste pour la sauvegarder ici.
Comment sélectionner une valeur parmi html-select, en utilisant Karma, et obtenir ainsi que la fonction ng-change fonctionne?
HTML:
Contrôleur ou directive JS:
$scope.itemTypes = [{name: 'Some name 1', value: 'value_1'}, {name: 'Some name 2', value: 'value_2'}]
$scope.itemTypeSelected = function () {
console.log("Yesssa !!!!");
};
Fragment de test de karma:
angular.element(element.find("#selectedItemType")[0]).val('value_1').change();
console.log("selected model.selectedItemType", element.isolateScope().model.selectedItemType);
Console:
'Yesssa !!!!'
'selected model.selectedItemType', 'value_1'