Getting All jQuery Events for a DOM Node.

I have more than once found myself needing to know all of the events for a specific DOM node. In the past I have used which worked great for a time. The problem is that I am now working on projects so large that Visual Events takes forever to load and then fills the entire screen making it nigh impossible to find the events for the node I am interested in. Combine this with live events, delegated events, on/off, etc, Visual Events was no longer doing the job for me. So I made myself another bookmarklet.

jQuery Events

To use it:

Drag the link to your bookmark bar.

Open the page you wish to see the events on.

Open your javascript console.

Click the bookmarklet.

Click the little red “Click Me” it puts in the top left corner.

Click the element you wish to see the events for.

In your console you will see a list of all of the events for the node you clicked, what type they are, and their namespace. If the node you click has no events (perhaps you clicked an element inside of the one with the events) it will look up the DOM until it finds a node with events. It will also look all the way up the DOM for that node and show you all of the events that are delegated to that node. The code could use a lot of cleanup and stuff, but it works for me right now.

Here is the code for it:

javascript:(function() {
$('#eventFinder, #eventTitle').remove();




Click Me
'); $('#eventTitle').click(function() { $('#eventFinder').show(); }); function findNodeEvents(e) { $('#eventFinder').hide(); var ele; if(e.pageX) { ele = document.elementFromPoint(e.pageX, e.pageY); } else { ele = e[0]; } var tmpEvents; var $origEle = $(ele); var $ele = $origEle; var events = []; var eventsFound = false; console.log('Finding events for node:'); console.log($origEle); while(true) { tmpEvents = $'events'); if(tmpEvents) { for(type in tmpEvents) { for(var i = 0; i < tmpEvents[type].length; i++) { if(((!tmpEvents[type][i].selector && $ele[0] === ele) || $[type][i].selector))) { eventsFound = true; if($ele[0] !== ele) { console.log('Delegated From:'); console.log($ele); } console.log('Event: ' + type + (tmpEvents[type][i].namespace ? '.' + tmpEvents[type][i].namespace : '') + ': ' + tmpEvents[type][i].handler); } } } } $ele = $ele.parent(); if($ele.length <= 0) { break; } } if(!eventsFound) { var $parent = $origEle.parent(); if($parent.length > 0) { console.log('No events found - Trying parent'); findNodeEvents($parent); } else { console.log('No events found - Do you know what you are doing?'); } } }; $('#eventFinder').click(findNodeEvents); })();

Unit testing jQuery w/ QUnit

So, like most developers I love having unit test, but I hate writing them. Really figuring out the best way to write them and have them work well, is a pain in the ass, and that is what I hate. I have spent some time recently playing with QUnit and despite the number fact that I have found a number of posts online about it, none of them have provided (in my mind) a good way to test a site. The ideas used work well for testing a library, or specific functions, but I don’t write libraries or one off functions, I develop websites. So, I have come up with a method that I like that allows me to test my sites in a way that I like.

The Problems:

The unit testing information I have found mainly deals with testing libraries – this is no good for me.
Testing involves putting QUnit on your page, along with its specific markup – although you can have a “debug” mode for this, it just seems like a bad idea, for a number of reasons, including it not really being an accurate representation of your page, and it does not work across page requests.
Using headless testing – it is cool, but not cross browser or even really O/S ready.
Using something like Selenium – also cool, but involves building tests using a new tool that uses java.

My solution:

I have come up with my own solution, which, I admit is not perfect, but it does a darn good job of testing what I need tested. Basically it involves having a very simply html page next to your site, that loads your site in an iframe and runs the tests on it. It is cross-browser and cross-O/S safe, it works for pretty much any site, and uses the same javascript/jQuery I already write every day.

There are a couple of problems still with my solution, but they are pretty easy to overcome, and writing tests becomes very simple. The basic page we need to get started with the testing is this:



QUnit Tests

    test markup, will be hidden

    Note: We can (and probably should) actually move our tests into different .js files making it much easier to deal with as our number of tests grow.

    We are doing a couple of interesting things here, first we are testing multiple pages at one time. Every time a new page loads up, we grab the jQuery refrence from inside of it, then run the tests that are specified for that page.

    Another cool thing is how we get the jQuery reference for each page.

    We start by loading jQuery using noConflict(true)

    This is because we need to grab the jQuery instance from inside the actual website. When jQuery attaches events to DOM elements, it actually saves those events inside of itself, so although we can trigger events inside of the page itself using our external jQuery, triggering events inside of the iframe will not actually fire any events that were created inside the page. So, instead we grab the jQuery that is actually on the page and trigger the events using it. This has the added bonus that because it is the reference from inside the page we are loading, we can reference DOM nodes as though we were working that that page directly.

    Here we grab the jQuery reference from inside the iframe with:

    $ = window.frames[0].jQuery;

    Note: For ANY of this to work we must adhere to SOP, this is why we load this up on a server, side by side with our site. This is why I am loading up the iframe using location.protocol + ‘//’ + location.hostname rather than typing out the URL. This will allow it to work as we move between servers and such.

    One of the cool things we are doing here is tying the starting of the tests to a button, so we can get the page to any state necessary before starting the tests – such as logging in, waiting for ajax requests to finish, or navigating to somewhere specific (not that we couldn’t do these in the tests, it just gives us options.)
    Also, before we run our tests we are running the 2 following commands:

    $.ajax({async: false});
    $ = true;

    This will make our ajax requests and animations synchronous. Although you would never do this (especially the ajax one) on a site, for our tests it is necessary to ensure that the page is ready before we perform each test.

    Now that we have done this we can run our test just like we were on the page directly.

    We can select elements and trigger events on them, like so:

    $(elem).click(); or $(elem).trigger(‘click’);
    $(elem).mousedown(); or $(elem).trigger(‘mousedown);
    Test things, such as visibility:

    Basically anything you would normally do. Simple and easy.

    This is not a perfect way to test your events, it is however pretty good, and will let us know when we break things.

    Here are some examples of tests in action. I hope this helps you get started with unit testing.

    Tests in action!