siesta-lite
Version:
Stress-free JavaScript unit testing and functional testing tool, works in NodeJS and browsers
227 lines (154 loc) • 7.64 kB
JavaScript
/*
Siesta 5.6.1
Copyright(c) 2009-2022 Bryntum AB
https://bryntum.com/contact
https://bryntum.com/products/siesta/license
*/
Role('Siesta.Recorder.Role.CanRecordMouseMove', {
does : [
Siesta.Util.Role.CanCalculatePageScroll,
Siesta.Recorder.Role.CanSwallowException
],
has : {
recordMouseMove : true,
// used by RootCause, position in page coordinates
cursorPosition : Joose.I.Array,
// used by RootCause (probably not needed anymore)
lastMoveTimestamp : null,
// used by RootCause
lastMouseMoveEvent : null
},
override : {
initialize : function () {
this.SUPERARG(arguments)
this.onBodyMouseMove = this.safeBind(this.onBodyMouseMove);
this.onBodyMouseOver = this.safeBind(this.onBodyMouseOver);
this.onBodyMouseOut = this.safeBind(this.onBodyMouseOut);
},
onStart : function () {
this.SUPERARG(arguments);
var win = this.window;
var doc = win.document;
var body = doc.body
if (this.recordMouseMove) {
// Need to also observe `mouseover` since it's fired before `mousemove` in case there is a crash
// in `mousemove` handler we need to know the exact cursor position
body.addEventListener('mouseover', this.onBodyMouseOver, true);
body.addEventListener('mouseout', this.onBodyMouseOut, true);
body.addEventListener('mousemove', this.onBodyMouseMove, true);
}
},
onStop : function () {
this.SUPERARG(arguments);
var win = this.window;
var doc = win.document;
var body = doc.body
if (this.recordMouseMove) {
body.removeEventListener('mouseover', this.onBodyMouseOver, true);
body.removeEventListener('mouseout', this.onBodyMouseOut, true);
body.removeEventListener('mousemove', this.onBodyMouseMove, true);
this.lastMouseMoveEvent = null
}
}
},
methods : {
saveMouseMoveData : function (event) {
var me = this
me.lastMoveTimestamp = new Date() - 0
me.cursorPosition[ 0 ] = me.viewportXtoPageX(event.clientX, me.window)
me.cursorPosition[ 1 ] = me.viewportYtoPageY(event.clientY, me.window)
me.lastMouseMoveEvent = event
},
onBodyMouseMove : function (e) {
// Skip test playback events and mouse moves in frames
if ((this.ignoreSynthetic && e.synthetic) || e.target.ownerDocument !== this.window.document) return;
this.saveMouseMoveData(e)
this.processBodyMouseMove(e)
},
processBodyMouseMove : function (e) {
},
onBodyMouseOver : function (e) {
// Skip test playback events and mouse moves in frames
if ((this.ignoreSynthetic && e.synthetic) || e.target.ownerDocument !== this.window.document) return;
this.saveMouseMoveData(e)
this.processBodyMouseOver(e)
},
processBodyMouseOver : function (e) {
},
onBodyMouseOut : function (e) {
// Skip test playback events and mouse moves in frames
if ((this.ignoreSynthetic && e.synthetic) || e.target.ownerDocument !== this.window.document) return;
this.saveMouseMoveData(e)
this.processBodyMouseOut(e)
},
processBodyMouseOut : function (e) {
},
targetToPathPoint : function (target) {
var pathPoint = [ target.getTargetAsQueryString() ]
if (target.getTarget().offset) pathPoint.push.apply(pathPoint, target.getTarget().offset)
pathPoint.xy = target.getTargetByType('xy').target
return pathPoint
},
addPathPoint : function (pathPoints, newPathPoint) {
// early exit, in case new path point is query-based
if (newPathPoint.length === 3) {
pathPoints.push(newPathPoint)
return
}
var lastPathPoint = pathPoints[ pathPoints.length - 1 ]
// if new path point is a absolute point (which will be the case for the `useXY` arg
// of `addMoveCursorAction` enabled then covert it to relative
if (newPathPoint.length === 1 && this.typeOf(newPathPoint[ 0 ]) == 'Array') {
var relativePoint = [
newPathPoint[ 0 ][ 0 ] - lastPathPoint.xy[ 0 ],
newPathPoint[ 0 ][ 1 ] - lastPathPoint.xy[ 1 ]
]
// do nothing
if (relativePoint[ 0 ] === 0 && relativePoint[ 1 ] === 0) return
relativePoint.xy = newPathPoint[ 0 ]
pathPoints.push(relativePoint)
} else
pathPoints.push(newPathPoint)
},
// this method merges several consequent calls to it to `moveCursorAlongPath` action
addMoveCursorAction : function (event, targetOverride, useXY) {
if (!(event instanceof Siesta.Recorder.Event)) event = Siesta.Recorder.Event.fromDomEvent(event)
var lastAction = this.getLastAction()
var isMouseMove = lastAction && (lastAction.action === 'moveCursorTo' || lastAction.action === 'moveCursorAlongPath')
if (!lastAction || !isMouseMove || !this.recordMouseMovePath) {
// defensive coding because of unknown: `lastAction.target` is undefined exception
if (lastAction && lastAction.hasTarget() && lastAction.target) {
var xy = lastAction.target.getTargetByType('xy')
if (xy) {
xy = xy.target
// do nothing if we already have an action with the same target point
// this might happen during our own tests, where we use `drag` command, which
// issues "mouseover" for initial and last points
if (event.x == xy[ 0 ] && event.y == xy[ 1 ]) return
}
}
var targetOptions = this.getPossibleTargets(event, true, targetOverride, useXY)
if (this.lastActionPosition.length === 0 || this.lastActionPosition[0] !== event.rawEvent.clientX || this.lastActionPosition[1] !== event.rawEvent.clientY) {
this.addAction({
action : 'moveCursorTo',
target : targetOptions,
sourceEvent : event,
options : event.options
})
}
} else {
var target = new Siesta.Recorder.Target({
targets : this.getPossibleTargets(event, true, targetOverride, useXY)
})
if (lastAction.action === 'moveCursorTo') {
lastAction.action = 'moveCursorAlongPath'
lastAction.value = [ this.targetToPathPoint(lastAction.target) ]
lastAction.target = null
}
this.addPathPoint(lastAction.value, this.targetToPathPoint(target))
this.fireEvent('actionupdate', lastAction)
}
}
}
// eof `override`
});