Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting view value an input field in a unit test of an angular form directive

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);
    })
like image 565
nathasm Avatar asked Oct 15 '14 00:10

nathasm


People also ask

What is fixture detectChanges ()?

fixture is a wrapper for our component's environment so we can control things like change detection. To trigger change detection we call the function fixture.detectChanges() , now we can update our test spec to: Copy it('login button hidden when the user is authenticated', () => { expect(el. nativeElement.

What is beforeEach in Angular?

beforeEach is a global function in Jasmine that runs some setup code before each spec in the test suite. In this test suite, beforeEach is used to create a testing module using the TestBed object and declares any components that would be used in this testing module.

What is SpyOn in Angular unit testing?

Test the Component logic using SpyOn. SpyOn is a Jasmine feature that allows dynamically intercepting the calls to a function and change its result. This example shows how spyOn works, even if we are still mocking up our service.


2 Answers

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);   }); 
like image 119
Ben Heymink Avatar answered Oct 26 '22 01:10

Ben Heymink


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'); }); 
like image 20
OrganicPanda Avatar answered Oct 26 '22 01:10

OrganicPanda