Showing posts with label SInon. Show all posts
Showing posts with label SInon. Show all posts

Tuesday, 24 January 2017

Manual event triggering and event listening in angular


Manual event triggering and event listening in angular


We may come at situation where we need to manually trigger event  on some element or to listen existing events on DOM. This is very easy when we use JQuery . We all have been doing this since long.

Angular comes with Jquery light instead of JQuery .  We still can use JQuery but  not  advisable.  All we stick to JQuery light which comes as default.

In Angular things are simple as you can bind event listener in html template itself  for example ng-click. This  post is regarding situation where we need to manually trigger events or listen some existing events and how to cover that in test cases.

I will cover both manually triggering the event and normal event listener in controller.

Lets say you want to bind key down  to capture some events like CTRL + P or CTRL +V etc..

Use case 1 - Listening to some event listener in angular.

You can do in controller simply by below example. you can see in yellow line. So I covered one use
case that is listening to some event listener in angular.


class Controller {
  constructor( $document) {
    this.$document = $document;
  }

 $onInit() {
    this.$document.on('keydown', (e) => this.handleCtrlP(e));
  }

 handleCtrlP(event) {
    if (event.keyCode === 80 && (event.metaKey || event.ctrlKey)) {
      event.preventDefault();
      this.printPage();
    }
  }

Use case 2 - Manually triggering the event in angular

I will cover by writing the test case for above case. So i can show how to write the test case for the same and can cover second use case.

describe('handleCtrlP', () => {

    beforeEach(() => {
        sinon.spy(controller, 'handleCtrlPOfflinePrint');
        sinon.spy(controller, 'printPage');
        controller.$onInit();
      });

    it('should call printPage method when ctrl p triggered', () => {
        angular.element(controller.$document).triggerHandler({ type: 'keydown', keyCode: 80, ctrlKey:         true });
        expect(controller.handleCtrlP).to.have.been.called;
        expect(controller.printPage).to.have.been.called;
      });

     it('should not call printPage method when other than ctrl p kewdown gets trigeered', () => {
        angular.element(controller.$document).triggerHandler({ type: 'keydown', keyCode: 89,                       metaKey: true });
        expect(controller.handleCtrlP).to.have.been.called;
        expect(controller.printPage).not.to.have.been.called;
      });
});

You can notice how i am triggering the keyDown event with keyCode to achieve ctrl +P event. 
Same way you can trigger wherever you want either in your functional code or test case.

triggerHandler comes with JQuery light in angular.element.  You can trigger event on any html element. Just pass that element in argument. In our case its controller.$document  as we listened ctrl + p event on document element.


Hope this article is useful for Angular and specially for test cases.


Note :  I used ECMA 2015 and Angular 1.5 for coding in above example and Mocha + Sinon + Chai syntax for test cases:

Friday, 2 December 2016

Spying on Jasmine vs Mocha + Sinon + Chai


                           Spying on Jasmine vs Mocha + Sinon  + Chai


As a UI front end developer, many of us have come across the Jasmine framework for Js test cases and Mocha Sinon with Chai assertion Library.  We know that it almost impossible to write test case without SPY functionality of any Testing Framework. Let me tell you basic difference between above two framework when you make a SPY for test case.


1. Anonymous spy : 

creates an anonymous function that records arguments, this value, exceptions and return values for all calls. It does not call actual function.

Using Jasmine:


           object.method =  jasmine.createSpy(); OR

            spyOn( object, 'method' ); (from jasmine 2.0) 

*Important : SpyOn needs method to be present on object so not actually anonymous spy while jasmnie.createSpy does not require as it assigns empty anonymous function. 

In short if your try spyOn(object, 'method') without having method available on object then you will get error stating the method to be spied upon does not exist on object.

Using Mocha chai:  


     object.method =  sinon.spy();
            
             sinon.stub( object , 'method');

*Important :  sinon.stun needs  method to be present on object so not actually anonymous spy while sinon.spy() does not require as it assigns empty anonymous function.



2. Spy with Actual function call : 

calls actual implementation and allow to record arguments, this value, exceptions and return values for all calls. 

Using Jasmine:


              spyOn( object, 'method' ).add.callThrough()

Using Mocha chai:


             sinon.spy(object , 'method');   

             (Notice the difference between sinon.spy and sinon.stub)



3. Spy with stub function call : 

assign the stub function which can receive the arguments and can return the stub data. 


Using Jasmine:


      spyOn( object, 'method' ).add.callFake( function (args) { 
                  return  value;
             });            

             for just return the value :

              spyOn( object, 'method' ).add.returnValue(true);



Using Mocha chai: 


      sinon.stub( object, 'method', function (args) {
                   retrun value;
              }); 



conclusion:


I write the test cases in both framework and above noticed 
differences helped me a lot to quick writing of the test case. Hope you can get benefit of that. Enjoy :)