How can I test and angular 1.5 component ng-click event with $comonentController?

526 views
Skip to first unread message

Aleck Landgraf

unread,
Jun 29, 2016, 6:28:48 PM6/29/16
to AngularJS
I have a simple component below that I want to test that the ng-click event handler function is triggered. 
Currently to test the click event, I have to:
  1. compile the angular component element with a new scope 
  2. then get that element's isolate scope
  3. replace the isolate scope $ctrl with a new one that has a jasmine spy in place of the click handler function 
  4. make my way through the compiled element and execute .click() on the DOM element within my component that triggers the handler
  5. check that the spy was called
Is there a better way to test this?

Since I'm using the 1.5 component, is it possible to add a spy via the $componentController's scope?



component:

module.component('note', {
  bindings: {
    notepad: '='
  },
  template: [
    '<div ng-if="!$ctrl.notepad.note">',
      '<p ng-click="$ctrl.handleOnClick()"><i class="fa fa-plus"></i> Add a note</p>',
    '</div>',
    '<div ng-if="$ctrl.notepad.note">',
      '<p ng-click="$ctrl.handleOnClick()">',
        '<span ng-bind="$ctrl.notepad.note"></span>',
      '</p>',
    '</div>',
  ].join(''),
  controller: ['$modal', function($modal) {
    function handleOnClick() {
      // ... open a modal to handle entering the note ...
    }

    this.handleOnClick = handleOnClick;  // <-- how can I test this function with $componentController
  }]
});


If I create a controller in the tests via $componentController, I do not have access to handleOnClick, only the bindings, unless I use 

testing:

describe("note component", function(){
    // globals set up and used in each test scenario
    var component, scope, notepad, $componentController, element;

    beforeEach(module('app'));

    beforeEach(inject(function($rootScope, _$componentController_, $compile) {
        scope = $rootScope.$new();
        // this part creates a controller we can test
        $componentController = _$componentController_;
        notepad = {
            note: 'We have a note',
        };
        // this part for testing the component compiles correctly and create the DOM
        element = angular.element('<note note="notepad"></note>');
        element = $compile(element)(scope);
        scope.notepad = notepad;
        scope.$apply();
    }));

    it("should bind notepad to the controller scope", function() {
        component = $componentController('note', null, {notepad: notepad});
        expect(component.notepad).toBeDefined();
        expect(component.notepad.note).toBe('We have a note');
        expect(component.handleOnClick).toBeDefined();
    });

   
    // Is it possible to use the $componentController to spy on the function in this test?
    it('should open a modal to edit the note when clicked', function () {
        // arrange
        var isolate_scope = element.isolateScope();
        isolate_scope.$ctrl = {
            handleOnClick: jasmine.createSpy('callback'),
            notepad: notepad
        };
        isolate_scope.$apply();
        var divs = element.find('div');
        var p_tags = divs.find('p');
        // act
        p_tags.eq(0).click();
        // assert
        expect(isolate_scope.$ctrl.handleOnClick).toHaveBeenCalled();
    });
});

Thanks,
Aleck
Reply all
Reply to author
Forward
0 new messages