-->

Setting view value an input field in a unit test o

2019-01-22 02:22发布

问题:

I have a directive that builds a form:

app.directive('config', function() {
  return {
    restrict: 'E',
    scope: {
      data: '='
    },
    template: '<form name="configForm">' +
      '<input type="number" max="10" ng-model="config.item" name="configItem"/>' +
      '<div class="form-error" ng-show="configForm.$error.max">Error</div>' + 
      '</form>',
    controller: 'ConfigDirectiveController',
  };
});

What I want to do is validate via a unit test that the error message will show up given some input. With angular 1.2 I could modify $scope.config.item and it would update the view value and show the error.

As near as I can tell, with angular 1.3, if the model does not pass validation the view value does not get updated...so I need to modify the view value to make sure the error message shows up.

How can I get access to the "configItem" input so that I can set the view value to ensure that the error message will show up?

Edited to show unit test

I see that the value is set properly, but the error still has an ng-hide applied to the tag. When I am viewing the page and manually changing the input value, the ng-hide will be removed and the error will display if I enter in something greater than 10.

  beforeEach(inject(function($compile, $rootScope) {
      element = angular.element('<config data="myData"></config>');
      $scope = $rootScope.$new();
      $scope.myData = {};
      element = $compile(element)($scope);
    }));

    it('should warn that we have a large number', function() {
      var input = element.find('[name="configItem"]')[0];
      $scope.$apply(function() {
        angular.element(input).val('9000000001');
      });
      errors = element.find('[class="form-error ng-binding"]');
      expect(errors.length).toBe(1);
    })

回答1:

Here's how I've been unit testing my input-based directives (Lots of code omitted for clarity!) The important line you are after is:

angular.element(dirElementInput).val('Some text').trigger('input');

Here's the full unit test:

  it('Should show a red cross when invalid', function () {

    dirElement = angular.element('<ng-form name="dummyForm"><my-text-entry ng-model="name"></my-text-entry></ng-form>');

    compile(dirElement)(scope);
    scope.$digest();

    // Find the input control: 
    var dirElementInput = dirElement.find('input');

    // Set some text!
    angular.element(dirElementInput).val('Some text').trigger('input');
    scope.$apply();

    // Check the outcome is what you expect! (in my case, that a specific class has been applied)
    expect(dirElementInput.hasClass('ng-valid')).toEqual(true);
  });


回答2:

The previous answer is correct if you are using Angular with jQuery but for Angular without jQuery (using jqlite) you can use triggerHandler instead (see here for full API)

it('foos to the bar', function() {
  el.val('Foo').triggerHandler('input');

  // Assuming el is bound to scope.something using ng-model ...
  expect(scope.something).toBe('Foo');
});