Я построил угловую директиву onInputChange
, которая должна срабатывать при обратном вызове, когда пользователи меняют значение ввода, либо щелкнув вне входа (размытие), либо нажав ENTER
. Директива может использоваться как:Почему мои тесты на жасмин не срабатывают по этой директиве?
<input type="number" ng-model="model" on-input-change="callback()"/>
Он использует следующий код:
app.directive('onInputChange', [
"$parse",
function ($parse) {
return {
restrict : "A",
require : "ngModel",
link : function ($scope, $element, $attrs) {
//
var dirName = "onInputChange",
callback = $parse($attrs[dirName]),
evtNS = "." + dirName,
initial = undefined;
//
if (angular.isFunction(callback)) {
$element
.on("focus" + evtNS, function() {
initial = $(this).val();
})
.on("blur" + evtNS, function() {
if ($(this).val() !== initial) {
$scope.$apply(function() {
callback($scope);
});
}
})
.on("keyup" + evtNS, function ($evt) {
if ($evt.which === 13) {
$(this).blur();
}
});
}
//
$scope.$on("$destroy", function() {
$element.off(evtNS);
});
}
};
}
]);
директива работает как я ожидал бы в моем приложении. Теперь я решил написать несколько тестов, чтобы действительно обеспечить это так:
describe("directive", function() {
var $compile, $rootScope, $scope, $element;
beforeEach(function() {
angular.mock.module("app");
});
beforeEach(inject(function ($injector) {
$compile = $injector.get("$compile");
$scope = $injector.get("$rootScope").$new();
$scope.model = 0;
$scope.onchange = function() {
console.log("called");
};
$element = $compile("<input type='number' ng-model='model' on-input-change='onchange()'>")($scope);
$scope.$digest();
spyOn($scope, "onchange");
}));
afterEach(function() {
$scope.$destroy();
});
it("has default values", function() {
expect($scope.model).toBe(0);
expect($scope.onchange).not.toHaveBeenCalled();
});
it("should not fire callback on internal model change", function() {
$scope.model = 123;
$scope.$digest();
expect($scope.model).toBe(123);
expect($scope.onchange).not.toHaveBeenCalled();
});
//this fails
it("should not fire callback when value has not changed", function() {
$element.focus();
$element.blur();
$scope.$digest();
expect($scope.model).toBe(0);
expect($scope.onchange).not.toHaveBeenCalled();
});
it("should fire callback when user changes input by clicking away (blur)", function() {
$element.focus();
$element.val(456).change();
$element.blur();
$scope.$digest();
expect($scope.model).toBe(456);
expect($scope.onchange).toHaveBeenCalled();
});
//this fails
it("should fire callback when user changes input by clicking enter", function() {
$element.focus();
$element.val(789).change();
$element.trigger($.Event("keyup", {keyCode:13}));
$scope.$digest();
expect($scope.model).toBe(789);
expect($scope.onchange).toHaveBeenCalled();
});
});
Теперь моя проблема заключается в том, что два из моих тестов неудовлетворительная после запуска с кармой:
A:
Failed директива не срабатывает обратный вызов, когда значение не изменилось Прогнозный шпион Onchan не быть вызванным.
B:
Failed директивы должен стрелять обратный вызов, когда пользователь изменяет ввод, нажав кнопку ввода Прогнозных шпионского OnChange, что было названо.
Я создал Plunker, где вы можете попробовать сами.
1. Почему мой callback вызывается, даже если значение не изменилось?
2. Как я могу имитировать пользователя, поражающего ENTER
на моем входе? Я уже пробовал разные способы, но никто не работает.
Извините за длинный вопрос. Надеюсь, я смог предоставить достаточно информации, чтобы кто-то мог помочь мне в этом. Спасибо :)
Другие вопросы здесь на так что я прочитал по поводу моего вопроса:
- How do I trigger a keyup/keydown event in an angularjs unit test?
- AngularJS unit test for keypress event
Благодарим вас за подробное объяснение. Первая половина вашего ответа помогла мне исправить тесты, чтобы все прошло. В любом случае, я сейчас нахожусь, чтобы исправить мой метод тестирования, как вы описали во второй половине. Я новичок в тестировании угловых модулей, и ваш ответ - отличная помощь! +1 – Fidel90
Не могли бы вы взглянуть на этот обновленный плункер: https://plnkr.co/edit/bxCuhvp5NazZxsA1tD1t?p=preview Я не уверен, как правильно применять и запускать шпионов. – Fidel90
Я обновил ваш плункер с помощью нескольких спецификаций, чтобы показать, как это делается: https://plnkr.co/edit/dMl0UdxBypjGvsBkb281?p=info. Я изменил несколько вещей для удобства тестирования. Частные переменные '_' должны быть доступны для тестов. И прослушиватели 'on *' предоставляются непосредственно слушателям 'on', поэтому мы можем быть уверены, что слушатель - это функция, которую мы ожидаем (в противном случае мы должны поймать анонимную функцию с помощью' var listener $ element.on.calls.argsFor (...) [1] 'и проверьте, выполняет ли он то, что он должен делать, это PITA). – estus