How can I cause mouseenter and mouseleave from dispatched mousemove events

30 Views Asked by At

I am writing some integration tests, and I want to simulate user interactions in the most literal possible way. My approach was to create an animated mouse pointer, which tweens mouse movements. The mouse movements are simulated using the following:

eventTarget.dispatchEvent(new MouseEvent("mousemove", {
  clientX: x,
  clientY: y,
  bubbles: true,
}));

As far as my trying out goes, these artificial mouse events do not cause consequent mouseenter and mouseleave event triggers. For the purpose of my tests, I'd like these events to take place as if it were a real mouse moving around.

  • How could I cause the consequential events of an organic interaction take place in the context of an automated test in a browser?
  • Am I wrong about my conclusion that consequential mouseenter and mouseleave events don't take place as consequence of dispatching mousemove on the coordinates where an HTMLElement is located?

here my concept testing code:

const innerEl = document.querySelector("#inner")
const mouseEl = document.querySelector("#mouse")
const mouse = {
    x:0, y:0
}
// this one will obviously be triggered by dispatching mousemove
document.addEventListener("mousemove",(ev)=>{
    mouse.x = ev.clientX
  mouse.y = ev.clientY
  mouseEl.style.left = mouse.x + "px";
  mouseEl.style.top = mouse.y + "px";
})

// will these get triggered as consequence?
innerEl.addEventListener("mouseenter",(ev)=>{
    innerEl.style.backgroundColor="red"
})
innerEl.addEventListener("mouseleave",(ev)=>{
    innerEl.style.backgroundColor = ""
})

const innerLocation = innerEl.getBoundingClientRect()

const frame = (t) => {
    const x = Math.cos(t / 1000 ) * 10 + innerLocation.right;
    const y = Math.sin(t / 1000 ) * 10 + innerLocation.bottom;
    document.dispatchEvent(new MouseEvent("mousemove", {
    clientX: x,
    clientY: y,
    bubbles: true,
  }));
  requestAnimationFrame(frame)
}
requestAnimationFrame(frame)

(jsfiddle: https://jsfiddle.net/wxz139bo/2/)

1

There are 1 best solutions below

6
matt On

it would appear the browser does not auto generate events for you and this is probably a good thing allowing the programmer to have fine grained control and generate exactly what they want

if you want to handle generating mouse events you'll have to go the whole 9 yards with it

there is a very definate order to which mouse events and in what order, as with absolutely everything webpage/html related, according to the spec Mouse Event Order

['mousemove','mouseenter','mouseleave'].forEach(evt=>{
      inner['on'+evt]   = e=>output.append(evt,'\n');
})

var t   = 0;
var old;

(function frame(){

      t  += 5;
      if(t===100)return;
      
      var x   = t;
      var y   = t;
      
      mouse.style.left    = x+"px";
      mouse.style.top     = y+"px";
      
      var target    = document.elementFromPoint(x,y);
   
      if(target!==old){

            evt(target,'mousemove',x,y)
            evt(target,'mouseover',x,y)
            evt(target,'mouseenter',x,y)

            if(old){
                evt(old,'mouseout',x,y)
                evt(old,'mouseleave',x,y)
            }

      }else{
            evt(target,'mousemove',x,y)
      }

      old   = target;          

      setTimeout(frame,200)  
      
})();


function evt(target,name,x,y){

      var evt    =  new MouseEvent(name,{
        pageX     : x,
        pageY     : y,
        bubbles   : true,
      });
      target.dispatchEvent(evt);
      
}//evt
#outer {
  padding:20px;
}

#inner {
  width:40px;
  height:40px;
  border:solid 1px;
}

#mouse {
  position:absolute;
  width:20px;
  height:20px;
  pointer-events:none;
}
<div id=outer>
  <div id=inner>
  </div>
</div>

<img id=mouse src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAsVJREFUOE+VlFFrG1cQhc/cuatItRUlFdgpSRrHEgIb6pdCU/Kkf563pBQELcauoEqc2LESm6S27Ka2NvfOCQN2kVKvTS8sLLvLt2dmzhnBzFlfX18sy3IZwC1VPUspfRKRyWg0ms5+d929zL5cWVm5E2N8HGNspZQI4ATA21ardTwYDDIAuwk8B1xbW/supfSjiKwAuE3yI8lfU0o77Xb702Aw+Py/gJ1O56GqPhWRHsm7ZnYM4HcAoxjj+4WFhZOblM4p7Ha7DwD8HEJ4BKBmZl72uaqOc85bKaX9m5TOAXu93n2ST0jeAzANIQjJhoicmdkeyX1Vfd9sNidVSquAd0TkIIRwJiJFznkRQBvAqZlt5pzfVim9Eigii2a2G0I4MrMUQrjrfTWzSPKNT76qp1XApojs5ZwPcs4fQgg1VX1EcllEHH5S1dNKoPeL5LjRaLybTqdqZt+r6irJHgAf1h8i8qpWq+1tbm5OLp7xWqCXBeCjmdXNrKOqHZJ+NUgeicifRVG8ILm7vb2d3PhVwLaZHXlSYox/k6yTvC8i98ys7YMi6bF8qarPReTNtUAADwEUbhv3YghB3ZcXZU093yQPAOyLyM5wOPSfexuuLhlAJ4TQ8iVBUkTESGYR+cdLDSGMzexlzvnd18vjP0kRkScXwNtuExFxRd4fV/DZzM7cNgB+88GNRiPP979LYw7Y6XSWVPUHAJ6YupdK0mFerisuAJQkX6vqi+FwuHtZ6uXSmANubGwsTKfTpZzzN7VaDSklN3IdwAMR2bhIiysekXwWY3x1OYwrgf1+Px4eHtbLsgytVitNJpOoqh67xyR/ArDkfQSwE2P8ZdYuVwIBSL/f19PTU1ldXbWtrS0ty7JeFMVySqknIk23UgjBJ/x6drpVwK/3Z+h2u0VRFN8C8OjVc87HOee/zs/PP4zHY1c7d74AWKnTJOq+JIkAAAAASUVORK5CYII='>

<pre id=output></pre>