4

I am trying to test an AngularJS component using karma, mocha, power-assert. I have a textarea and a button in my component, where the button is disabled based on the length of text in textarea.

When I run the component in browser it works perfectly. But I can't figure out how to test this functionality.

Here's a bit of code.

inquiryForm.js

function inquiryForm($scope) {
  // i plan to add some logic here
}
angular.module('myApp').component('inquiryForm', {
  controller: inquiryForm,
  controllerAs: 'inquiryForm',
  templateUrl: 'inquiryForm.html'
});

inquiryForm.html

<div class="contact">
    <div>Thanks for contacting us.</div>
    <form>
        <textarea ng-model="inquiryForm.inquiryText" name=""></textarea>
        <input type="submit" value="SEND" ng-disabled="!inquiryForm.inquiryText.length">
    </form>
</div>

inquiryFormTest.js

describe('inquiry form ', () => {
  let $rootScope;
  let $scope;
  let $compile;
  let element;

  beforeEach(() => {
    angular.mock.module('myApp');

    inject(($injector) => {
      $rootScope = $injector.get('$rootScope');
      $scope = $rootScope.$new();
      $compile = $injector.get('$compile');
    });
  });

  const compileDirective = () => {
    element = $compile('<inquiry-form></inquiry-form>')($scope);
    $scope.$digest();
  };

  describe('inquiry form', () => {
    beforeEach(() => {
      compileDirective();
    });

    // this test passes
    it('disables the submit button if textbox is empty', () => {
      assert(element.find('input').prop('disabled'), true);
    });

    // this test fails
    it('enables the submit button if textbox is not empty', () => {
      // making some changes to DOM here
      element.find('textarea').text('hello, world!');
      console.log(element.find('textarea').text()); // expected: "hello, world!", actual: "hello, world!"

      // since the state of scope has changed, I call digest to reflect those 
      $scope.$digest();

      // this assert passes
      assert(element.find('textarea').text(), 'hello, world!');

      // this one fails.
      assert(element.find('input').prop('disabled'), false);
    });
  });
});

As you can see in the comments above, the second test fails. I am guessing the test has failed since the state of html has not been reflected to the component controller inquiryForm. Sure the DOM of textarea is being updated, but the ng-disabled directive does not trigger since component controller inquiryForm is not connected to the scope.

How can I make this ng-disabled fire with mock user input in textarea...

2
  • you have described the inquiry form. Did you try to name the from using name="inquiry form" Commented Jul 11, 2016 at 10:46
  • @mattymanme i don't think the value of describe in unittest can link to the angular js object. I did try that though and it did not work. Commented Jul 12, 2016 at 6:58

2 Answers 2

2

After lots of searching and trial and error, I have finally found the solution. As I was guessing, the changing of text in textarea was not being communicated to the component controlller hence the ng-disabled="!inquiryForm.inquiryText.length" which contains the reference to it was not triggering.

Here is how I changed my test code...

// this test fails
it('enables the submit button if textbox is not empty', () => {
  // making some changes to DOM here
  // ↓---↓ REMOVED THIS
  // element.find('textarea').text('hello, world!');
  // ↑---↑ this was just making changes to DOM but was not informing the component controller of those changes.

  // ↓+++↓ ADDED THIS
  angular.element(element.find('textarea')).val('hello, world!').triggerHandler('change');
  // ↑+++↑ I used the .val() and .triggerHandler() of angularjs to inform component of changes in state of scope

  // since the state of scope has changed, I call digest to init the watchers 
  $scope.$digest();

  // now this assert passes
  assert(element.find('input').prop('disabled') === false);
});

reference: https://stackoverflow.com/a/26376249/6573907

Sign up to request clarification or add additional context in comments.

Comments

0

use naming the form as below:

<form name="inquiry form" ng-submit="inquiryForm.handleSubmit()" method="post">

1 Comment

thanks for your answer. This does not work. The ng-disabled directive does not work even after changing the value of textarea.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.