Florents great answer could be improved a tiny bit would by outsourcing the JS snippet into a separate file and wrap it into the old-style JS module format with readable parameter names.
A file called e.g. simulate_wheel.js
with:
/* global arguments */
(function (element, deltaY, offsetX, offsetY) {
var box = element.getBoundingClientRect();
var clientX = box.left + (offsetX || box.width / 2);
var clientY = box.top + (offsetY || box.height / 2);
var target = element.ownerDocument.elementFromPoint(clientX, clientY);
for (var e = target; e; e = e.parentElement) {
if (e === element) {
target.dispatchEvent(new MouseEvent("mouseover", {
view: window,
bubbles: true,
cancelable: true,
clientX: clientX,
clientY: clientY
}));
target.dispatchEvent(new MouseEvent("mousemove", {
view: window,
bubbles: true,
cancelable: true,
clientX: clientX,
clientY: clientY
}));
target.dispatchEvent(new WheelEvent("wheel", {
view: window,
bubbles: true,
cancelable: true,
clientX: clientX,
clientY: clientY,
deltaY: deltaY
}));
return "";
}
}
return "Element is not interactable";
}).apply(null, arguments);
Which then can be read and used the following
# Load it using the module loader, the module in this example is called "helper_js"
# Alternatively, simple read functions could be used
import pkgutil
wheel_js = pkgutil.get_data("helper_js", "simulate_wheel.js").decode("utf8")
def simulate_wheel(element, deltaY=120, offsetX=0, offsetY=0):
error = element._parent.execute_script(wheel_js, element, deltaY, offsetX, offsetY)
if error:
raise WebDriverException(error)
This is similar to how it's down inside the Selenium bindings for Python.
"#scene > .canvas-container canvas"
, but that's no biggie) – Gettogether