PDA

View Full Version : Testing viewcontroller event handler is fired using Deft, EXTJS4 and Jasmine



GFI_SI
30 Jan 2014, 3:43 AM
Hi there,
I've been searching most of the morning for a definitive answer on this.

I want to test that a click event is fired on a menu item in my view and the event listener in the viewcontroller is triggered.

Currently I'm doing it this way, but I think there must be a nicer way to do it.

Here is my spec


it("click event is triggered", function() {
var components = Ext4.ComponentQuery.query('#settings_Users');
var usersMenuItem = components[0];
expect(usersMenuItem.hasListener('click')).toBeTruthy();
var listener = usersMenuItem.events.click.listeners[0].fn.$name;
expect(listener).toBe('onEditUsers');
var isitdone = usersMenuItem.fireEvent('click');
expect(isitdone).toBe(true);
});

As you can see I'm getting the menu option and checking that it has a click listener attached.

Then I'm checking the the name of the event listener is 'onEditUsers'

Then I'm firing the event manually and checking the result is true.

Now I know the event handler is being called because isitdone is set to true. If I edit my handler to return false immediately isitdone gets set to false.

My problem is I'd like to do something simple like


spyOn(viewController,'onEditUsers');
var components = Ext4.ComponentQuery.query('#settings_Users');
var usersMenuItem = components[0];
usersMenuItem.fireEvent('click');
expect(viewController.onEditUsers).toHaveBeenCalled();

However I get an error saying that it wasn't called. Is this some sort of scope issue?

GFI_SI
3 Feb 2014, 6:24 AM
If there isn't another way to do it is there at least a better way that I could do this?

var listener = usersMenuItem.events.click.listeners[0].fn.$name;

Seems a bit nasty to be at the mercy of the listeners object and it's ordering.

GFI_SI
5 Feb 2014, 6:06 AM
I came up with the following custom matcher for Jasmine which allows the checking of event handlers by type on an observable object.


toHandleListener: function(item, eventType, eventHandler) {
var failMessages = [];
var viewController = this.actual;
var listeners = [];
for (var event in item.hasListeners) {
if ( event === eventType ) {
if (item.events[event]) {
var listenersList = item.events[event].listeners;
for (var i in listenersList) {
listeners.push(listenersList[i].fn.$name);
}
}
}
}
if (!Ext.Array.contains(listeners, eventHandler)) {
failMessages.push(eventHandler+" is not set as an event handler on this component");
}
if (viewController.control[item.itemId][eventType] !== eventHandler ) {
failMessages.push(eventHandler+" is not set as the " + eventType + " event handler on this component");
}
if (!Ext.isFunction(viewController[eventHandler])) {
failMessages.push(eventHandler+" is not defined in the view controller");
}

this.message = function() {
return failMessages.join("; \n");
};

return !failMessages.length;
}

It seems to do the trick.