How to trigger ng-change in directive test in AngularJS
angularjs, angularjs-directive
Solution
From your explanatory comment:
All I want to do in directive's test is to check that `doIt` is called when user changes the input.
Whether or not the expression indicated by `ng-change` is correctly evaluated or not is really the responsibility of the `ngModel` directive, so I'm not sure I'd test it in this way; instead, I'd trust that the `ngModel` and `ngChange` directives have been correctly implemented and tested to call the function specified, and just test that calling the function itself affects the directive in the correct manner. An end-to-end or integration test could be used to handle the full-use scenario.
That said, you can get hold of the `ngModelController` instance that drives the `ngModel` change callback and set the view value yourself:
it('trigger doIt', function() {
var ngModelController = el.find('input').controller('ngModel');
ngModelController.$setViewValue('test');
expect($scope.youDidIt).toBe(true);
});
As I said, though, I feel like this is reaching too far into `ngModel`'s responsibilities, breaking the black-boxing you get with naturally composable directives.
Example: http://plnkr.co/edit/BaWpxLuMh3HvivPUbrsd?p=preview
[Update]
After looking around at the AngularJS source, I found that the following also works:
it('trigger doIt', function() {
el.find('input').trigger('input');
expect($scope.youDidIt).toBe(true);
});
It looks like the event is different in some browsers; `input` seems to work for Chrome.
Example: http://plnkr.co/edit/rbZ5OnBtKMzdpmPkmn2B?p=preview
Here is the relevant AngularJS code, which uses the `$sniffer` service to figure out which event to trigger:
changeInputValueTo = function(value) {
inputElm.val(value);
browserTrigger(inputElm, $sniffer.hasEvent('input') ? 'input' : 'change');
};
Even having this, I'm not sure I'd test a directive in this way.
Problem
I have the following AngularJS directive that creates an `input` element. Input has `ng-change` attribute that runs `doIt()` function. In my directive's unit test I want to check if `doIt` function is called when users changes the input. But the test does not pass. Though it works in the browser when testing manually. Directive: ``` ... template: "<input ng-model='myModel' ng-change='doIt()' type='text'>" ``` Test: ``` el.find('input').trigger('change') // Dos not trigger ng-change ``` Live demo (ng-change): http://plnkr.co/edit/0yaUP6IQk7EIneRmphbW?p=preview Now, the test passes if I manually bind `change` event instead of using `ng-change` attribute. ``` template: "<input ng-model='myModel' type='text'>", link: function(scope, element, attrs) { element.bind('change', function(event) { scope.doIt(); }); } ``` Live demo (manual binding): http://plnkr.co/edit/dizuRaTFn4Ay1t41jL1K?p=preview Is there a way to use `ng-change` and make it testable? Thank you.