Driving Javascript code with synthetic mouse events

475 views Asked by At

I am trying to inject events to trigger the jquery.cluetip.js library to display its popup for website testing purposes using behat & mink. We need to do this so that needed HTML/DOM elements are put in place by cluetip for the subsequent test rules.

I have created some code to trigger the events used by the cluetip code, but although cluetip does receive the events, something goes wrong and no tooltip is displayed. It would appear that the events are not reaching the correct event handler in the library.

The injected test code is:

 xpath = $auth->getXpath(); // $auth is a Mink node
 js = <<<'JS'
    return (function(xpath) {
      console.log('************* Calling mouseover/mousemove trigger ***************');
      var xPathRes = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null );
      var thisNode = xPathRes.singleNodeValue;
      if (thisNode) {
        var mevent,
            nodeWidth2 = thisNode.offsetWidth/2,
            nodeHeight2 = thisNode.offsetHeight/2,
            pageTop = thisNode.offsetTop,
            pageLeft = thisNode.offsetLeft,
            screenTop = pageTop + window.screenY,
            screenLeft = pageLeft + window.screenX,
            eventParams = {
            pageX: pageLeft+nodeWidth2,
            pageY: pageTop+nodeHeight2,
            screenX: screenLeft+nodeWidth2,
            screenY: screenTop+nodeHeight2
        };
        mevent = jQuery.Event('mouseenter', eventParams);
        jQuery(thisNode).trigger(mevent);
        console.log('sent enter');
        mevent = jQuery.Event('mouseover', eventParams);
        jQuery(thisNode).trigger(mevent);
        console.log('sent over');
        mevent = jQuery.Event('mouseover', eventParams);
        jQuery(thisNode).trigger(mevent);
        console.log('sent over');
        mevent = jQuery.Event('mouseover', eventParams);
        jQuery(thisNode).trigger(mevent);
        console.log('sent over');
        console.log('************* Done trigger ***************');
      }
    return thisNode;
    })("{{XPATH}}");
JS;
$js = str_replace('{{XPATH}}', $xpath, $js);

The intention of the nodeWidth2 calculation is to simulate a mouse event in the centre of the referenced element.

When called, this does call into the cluetip library (i've included some console logging to demonstrate):

"************* Calling mousever/mousemove trigger ***************" e03842 line 68 > Function:2
"mouseenter mouse - state" jquery.cluetip.js:260
Object { type: "mouseenter", pageX: 141.5, pageY: 188.5, screenX: 859.5, screenY: 188.5, timeStamp: 1417103270770, jQuery182037529489744405187: true, isTrigger: true,     exclusive: undefined, namespace: "", 7 more… } jquery.cluetip.js:261
"mouseover.cluetip" jquery.cluetip.js:814
Object { type: "mouseenter", pageX: 141.5, pageY: 188.5, screenX: 859.5, screenY: 188.5, timeStamp: 1417103270770, jQuery182037529489744405187: true, isTrigger: true,     exclusive: undefined, namespace: "", 7 more… } jquery.cluetip.js:815
"sent enter" e03842 line 68 > Function:21
"mouseenter mouse - state" jquery.cluetip.js:260
Object { type: "mouseover", pageX: 141.5, pageY: 188.5, screenX: 859.5, screenY: 188.5, timeStamp: 1417103270772, jQuery182037529489744405187: true, isTrigger: true, exclusive: undefined, namespace: "", 7 more… } jquery.cluetip.js:261
"mouseover.cluetip" jquery.cluetip.js:814
Object { type: "mouseover", pageX: 141.5, pageY: 188.5, screenX: 859.5, screenY: 188.5, timeStamp: 1417103270772, jQuery182037529489744405187: true, isTrigger: true, exclusive: undefined, namespace: "", 7 more… } jquery.cluetip.js:815
"sent over" e03842 line 68 > Function:24
"mouseenter mouse - state" jquery.cluetip.js:260
Object { type: "mouseover", pageX: 141.5, pageY: 188.5, screenX: 859.5, screenY: 188.5, timeStamp: 1417103270773, jQuery182037529489744405187: true, isTrigger: true, exclusive: undefined, namespace: "", 7 more… } jquery.cluetip.js:261
"mouseover.cluetip" jquery.cluetip.js:814
Object { type: "mouseover", pageX: 141.5, pageY: 188.5, screenX: 859.5, screenY: 188.5, timeStamp: 1417103270773, jQuery182037529489744405187: true, isTrigger: true, exclusive: undefined, namespace: "", 7 more… } jquery.cluetip.js:815
"sent over" e03842 line 68 > Function:27
"mouseenter mouse - state" jquery.cluetip.js:260

However the cluetip code doesn't get to the 'show' stage and nothing is displayed.

Any ideas what is going wrong, or avenues to investigate?

[using Firefox 33 on Ubuntu Precise/64, cluetip works fine with real mouse movement]

1

There are 1 answers

1
Martin Ernst On

This answer doesn't solve the problem but will help a little bit and is too much for a comment.

I tested the plugin jquery.cluetip with jquery-1.11.1 in Firefox 33 on Windows 7 / 64 with this simple setup:

CSS:
#tipElem.highlight {border: 10px solid blue;}
JS:
// on hover cluetip adds class 'highlight' to the element
$("#tipElem").cluetip({hoverClass: 'highlight'});
// additional event listener
$("#tipElem").on('mouseenter', function(ev) {console.log(ev);});
// trigger 'mouseenter' without defining any event params
window.setTimeout(function() {$("#tipElem").mouseenter();}, 3000);

cluetip injects some elements into the html, one of them has the id cluetip. By default they are display: none;. With Firebug opened following happens:

  • When mouse enters: 1) The border is applied, so the plugin works. 2) An error is thrown inside jQuery's event system. 3) The #cluetip stays display: none;
  • When mouse leaves: 1) the border is removed. 2) The error is thrown inside jQuery.
  • After 3 sec: 1) The border is applied. 2) The error is thrown. 3) The event isn't logged.

Without Firebug (or with Firefox' own developer tools) all steps works as expected. Result: 1) The plugin can be triggered by a synthetic mouseenter even without any event parameters defined. 2) The plugins broad event system conflicts somehow with Firebug.