Bug 1911423 - add a desktop-only JS intervention for Power BI maps to fix touchpad zooming; r=denschub,webcompat-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D249886
This commit is contained in:
Thomas Wisniewski
2025-05-21 16:53:42 +00:00
committed by twisniewski@mozilla.com
parent 90fec2e1ca
commit a9c1c3eef1
4 changed files with 145 additions and 0 deletions

View File

@@ -3099,12 +3099,23 @@
"1944518": {
"issue": "broken-scrolling",
"matches": ["*://app.powerbi.com/view*"]
},
"1919263": {
"issue": "broken-zooming",
"matches": ["*://app.powerbi.com/view*"]
}
},
"interventions": [
{
"platforms": ["mac"],
"ua_string": ["add_Chrome"]
},
{
"platforms": ["desktop"],
"content_scripts": {
"all_frames": true,
"js": ["bug1911423-app.powerbi.com-emulate-mousewheel-events.js"]
}
}
]
},

View File

@@ -0,0 +1,38 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/* globals exportFunction */
/**
* Bug 1911423 - app.powerbi.com - zooming is broken on maps
*
* They listen for non-standard mousewheel events, rather than wheel,
* which breaks zooming. This emulates mousewheel events for them.
*/
console.info(
"Emulating mousewheel events for compatibility reasons. See https://bugzilla.mozilla.org/show_bug.cgi?id=1911423 for details."
);
(function () {
const { prototype } = window.wrappedJSObject.WheelEvent;
Object.defineProperty(prototype, "type", {
configurable: true,
get: exportFunction(() => "mousewheel", window),
set: exportFunction(() => {}, window),
});
})();
(function () {
const { prototype } = window.wrappedJSObject.EventTarget;
const { addEventListener } = prototype;
prototype.addEventListener = exportFunction(function (type, fn, c, d) {
if (type === "mousewheel") {
type = "wheel";
}
return addEventListener.call(this, type, fn, c, d);
}, window);
})();

View File

@@ -74,6 +74,52 @@ class Client:
element,
)
async def send_apz_scroll_gesture(
self, units, element=None, offset=None, coords=None
):
if coords is None:
if element is None:
raise ValueError("require coords and/or element")
coords = self.get_element_screen_position(element)
if offset is not None:
coords[0] += offset[0]
coords[1] += offset[1]
with self.using_context("chrome"):
return self.execute_async_script(
"""
const [units, coords, done] = arguments;
const { devicePixelRatio, windowUtils } = window;
const resolution = windowUtils.getResolution();
const toScreenCoords = x => x * devicePixelRatio * resolution;
// based on nativeVerticalWheelEventMsg()
let msg = 4; // linux default
switch (Services.appinfo.OS) {
case "WINNT":
msg = 0x0115; // WM_VSCROLL
break;
case "Darwin":
msg = 1; // use a gesture; don't synthesize a wheel scroll
break;
}
windowUtils.sendNativeMouseScrollEvent(
toScreenCoords(coords[0]),
toScreenCoords(coords[1]),
msg,
0,
units,
0,
0,
0,
document.documentElement,
() => { done(); },
);
""",
units,
coords,
)
async def send_apz_mouse_event(
self, event_type, coords=None, element=None, button=0
):

View File

@@ -0,0 +1,50 @@
import asyncio
import pytest
URL = "https://lmiamap.ca/"
FRAME_CSS = "iframe[src*=powerbi]"
MAP_CSS = ".MicrosoftMap"
CANVAS_CSS = "[id='Microsoft.Maps.Imagery.RoadSceneWithoutLabels']"
HERO_CSS = "svg .mapBubbles:not(:empty)"
async def can_zoom_maps(client):
await client.navigate(URL, wait="none")
client.switch_frame(client.await_css(FRAME_CSS, is_displayed=True))
map = client.await_css(MAP_CSS, is_displayed=True)
canvas = client.await_css(CANVAS_CSS, is_displayed=True)
# wait for the map to load and settle down (it zooms in and adds SVG annotations)
client.await_css(HERO_CSS, is_displayed=True)
await asyncio.sleep(2)
# now we scroll and see if the canvas' transform changes (it snaps back to its original transform afterward)
pre = client.execute_script("return arguments[0].style.transform", canvas)
for i in range(30):
await client.send_apz_scroll_gesture(4, element=map, offset=[40, 40])
await asyncio.sleep(0.05)
if pre != client.execute_script(
"return arguments[0].style.transform",
canvas,
):
return True
return False
# Android is unaffected; Linux may be, but testing scroll gestures doesn't seem to work.
@pytest.mark.skip_platforms("android", "linux")
@pytest.mark.asyncio
@pytest.mark.with_interventions
async def test_enabled(client):
assert await can_zoom_maps(client)
@pytest.mark.skip_platforms("android", "linux")
@pytest.mark.asyncio
@pytest.mark.without_interventions
async def test_disabled(client):
assert not await can_zoom_maps(client)