Bug 1490258 - [marionette] Remove moz:useNonSpecCompliantPointerOrigin capability. r=webdriver-reviewers,jgraham

Differential Revision: https://phabricator.services.mozilla.com/D181280
This commit is contained in:
Henrik Skupin 2023-06-21 16:24:08 +00:00
parent 446672d058
commit 1f4f920af8
12 changed files with 59 additions and 156 deletions

View File

@ -510,12 +510,9 @@ export class MarionetteCommandsChild extends JSWindowActorChild {
* Object with a list of WebDriver session capabilities.
*/
async performActions(options = {}) {
const { actions, capabilities } = options;
const { actions } = options;
if (this.actionState === null) {
this.actionState = new lazy.action.State({
specCompatPointerOrigin:
!capabilities["moz:useNonSpecCompliantPointerOrigin"],
});
this.actionState = new lazy.action.State();
}
let actionChain = lazy.action.Chain.fromJSON(this.actionState, actions);

View File

@ -239,10 +239,9 @@ export class MarionetteCommandsParent extends JSWindowActorParent {
});
}
async performActions(actions, capabilities) {
async performActions(actions) {
return this.sendQuery("MarionetteCommandsParent:performActions", {
actions,
capabilities: capabilities.toJSON(),
});
}

View File

@ -1448,11 +1448,7 @@ GeckoDriver.prototype.performActions = async function (cmd) {
await this._handleUserPrompts();
const actions = cmd.parameters.actions;
await this.getActor().performActions(
actions,
this.currentSession.capabilities
);
await this.getActor().performActions(actions);
};
/**

View File

@ -54,12 +54,7 @@ const MODIFIER_NAME_LOOKUP = {
* Typically each top-level browsing context in a session should have a single State object
*/
action.State = class {
constructor(options = {}) {
const { specCompatPointerOrigin = true } = options;
/** Flag for WebDriver spec conforming pointer origin calculation. */
this.specCompatPointerOrigin = specCompatPointerOrigin;
constructor() {
/**
* A map between input ID and the device state for that input
* source, with one entry for each active input source.
@ -420,11 +415,10 @@ class Origin {
*
* This is overridden in subclasses to provide a class-specific origin.
*
* @param {State} state - Actions state.
* @param {InputSource} inputSource - State of current input device.
* @param {WindowProxy} win - Current window global
*/
getOriginCoordinates(state, inputSource, win) {
getOriginCoordinates(inputSource, win) {
throw new Error(
`originCoordinates not defined for ${this.constructor.name}`
);
@ -433,14 +427,13 @@ class Origin {
/**
* Convert [x, y] coordinates to viewport coordinates
*
* @param {State} state - Actions state
* @param {InputSource} inputSource - State of the current input device
* @param {Array<number>} coords - [x, y] coordinate of target relative to origin
* @param {WindowProxy} win - Current window global
*/
getTargetCoordinates(state, inputSource, coords, win) {
getTargetCoordinates(inputSource, coords, win) {
const [x, y] = coords;
const origin = this.getOriginCoordinates(state, inputSource, win);
const origin = this.getOriginCoordinates(inputSource, win);
return [origin.x + x, origin.y + y];
}
@ -471,13 +464,13 @@ class Origin {
}
class ViewportOrigin extends Origin {
getOriginCoordinates(state, inputSource, win) {
getOriginCoordinates(inputSource, win) {
return { x: 0, y: 0 };
}
}
class PointerOrigin extends Origin {
getOriginCoordinates(state, inputSource, win) {
getOriginCoordinates(inputSource, win) {
return { x: inputSource.x, y: inputSource.y };
}
}
@ -491,18 +484,16 @@ class ElementOrigin extends Origin {
this.element = element;
}
getOriginCoordinates(state, inputSource, win) {
if (state.specCompatPointerOrigin) {
const clientRects = this.element.getClientRects();
// The spec doesn't handle this case; https://github.com/w3c/webdriver/issues/1642
if (!clientRects.length) {
throw new lazy.error.MoveTargetOutOfBoundsError(
`Origin element is not displayed`
);
}
return lazy.dom.getInViewCentrePoint(clientRects[0], win);
getOriginCoordinates(inputSource, win) {
const clientRects = this.element.getClientRects();
// The spec doesn't handle this case; https://github.com/w3c/webdriver/issues/1642
if (!clientRects.length) {
throw new lazy.error.MoveTargetOutOfBoundsError(
`Origin element is not displayed`
);
}
return lazy.dom.coordinates(this.element);
return lazy.dom.getInViewCentrePoint(clientRects[0], win);
}
}
@ -1017,7 +1008,6 @@ class PointerMoveAction extends PointerAction {
`Dispatch ${this.constructor.name} ${inputSource.pointer.type} with id: ${this.id} x: ${this.x} y: ${this.y}`
);
const target = this.origin.getTargetCoordinates(
state,
inputSource,
[this.x, this.y],
win
@ -1156,7 +1146,6 @@ class WheelScrollAction extends WheelAction {
`Dispatch ${this.constructor.name} with id: ${this.id} deltaX: ${this.deltaX} deltaY: ${this.deltaY}`
);
const scrollCoordinates = this.origin.getTargetCoordinates(
state,
inputSource,
[this.x, this.y],
win
@ -1392,7 +1381,6 @@ class PointerMoveTouchActionGroup extends TouchActionGroup {
let targetCoords = [];
for (const [actionInputSource, action] of this.actions.values()) {
const target = action.origin.getTargetCoordinates(
state,
actionInputSource,
[action.x, action.y],
win

View File

@ -466,7 +466,6 @@ export class Capabilities extends Map {
"moz:shutdownTimeout",
Services.prefs.getIntPref("toolkit.asyncshutdown.crash_timeout"),
],
["moz:useNonSpecCompliantPointerOrigin", false],
["moz:webdriverClick", true],
["moz:windowless", false],
]);
@ -618,10 +617,11 @@ export class Capabilities extends Map {
continue;
case "moz:useNonSpecCompliantPointerOrigin":
lazy.assert.boolean(
v,
lazy.pprint`Expected ${k} to be boolean, got ${v}`
);
if (v !== undefined) {
throw new lazy.error.InvalidArgumentError(
`Since Firefox 116 the capability ${k} is no longer supported`
);
}
break;
case "moz:webdriverClick":
@ -744,12 +744,6 @@ export class Capabilities extends Map {
lazy.pprint`Expected ${name} to be a boolean, got ${value}`
);
case "moz:useNonSpecCompliantPointerOrigin":
return lazy.assert.boolean(
value,
lazy.pprint`Expected ${name} to be a boolean, got ${value}`
);
case "moz:webdriverClick":
return lazy.assert.boolean(
value,

View File

@ -81,10 +81,6 @@ export class WebDriverSession {
* <dt><code>moz:debuggerAddress</code> (boolean)
* <dd>Indicate that the Chrome DevTools Protocol (CDP) has to be enabled.
*
* <dt><code>moz:useNonSpecCompliantPointerOrigin</code> (boolean)
* <dd>Use the not WebDriver conforming calculation of the pointer origin
* when the origin is an element, and the element center point is used.
*
* <dt><code>moz:webdriverClick</code> (boolean)
* <dd>Use a WebDriver conforming <i>WebDriver::ElementClick</i>.
* </dl>

View File

@ -176,7 +176,7 @@ add_task(function test_processPointerMoveActionDefaultOrigin() {
];
const chain = action.Chain.fromJSON(state, chainForTick(inputTickActions));
// The default is viewport coordinates which have an origin at [0,0] and don't depend on inputSource
deepEqual(chain[0][0].origin.getOriginCoordinates(state, null, null), {
deepEqual(chain[0][0].origin.getOriginCoordinates(null, null), {
x: 0,
y: 0,
});
@ -251,7 +251,6 @@ add_task(function test_computePointerDestinationViewport() {
inputSource.x = "99";
inputSource.y = "10";
const target = actionItem.origin.getTargetCoordinates(
state,
inputSource,
[actionItem.x, actionItem.y],
null
@ -277,7 +276,6 @@ add_task(function test_computePointerDestinationPointer() {
inputSource.x = 10;
inputSource.y = 99;
const target = actionItem.origin.getTargetCoordinates(
state,
inputSource,
[actionItem.x, actionItem.y],
null

View File

@ -399,8 +399,10 @@ add_task(function test_Capabilities_ctor() {
ok(caps.has("moz:platformVersion"));
ok(caps.has("moz:processID"));
ok(caps.has("moz:profile"));
equal(false, caps.get("moz:useNonSpecCompliantPointerOrigin"));
equal(true, caps.get("moz:webdriverClick"));
// No longer supported capabilities
ok(!caps.has("moz:useNonSpecCompliantPointerOrigin"));
});
add_task(function test_Capabilities_toString() {
@ -428,10 +430,6 @@ add_task(function test_Capabilities_toJSON() {
equal(caps.get("moz:platformVersion"), json["moz:platformVersion"]);
equal(caps.get("moz:processID"), json["moz:processID"]);
equal(caps.get("moz:profile"), json["moz:profile"]);
equal(
caps.get("moz:useNonSpecCompliantPointerOrigin"),
json["moz:useNonSpecCompliantPointerOrigin"]
);
equal(caps.get("moz:webdriverClick"), json["moz:webdriverClick"]);
});
@ -485,14 +483,20 @@ add_task(function test_Capabilities_fromJSON() {
caps = fromJSON({ "moz:debuggerAddress": true });
equal(null, caps.get("moz:debuggerAddress"));
caps = fromJSON({ "moz:useNonSpecCompliantPointerOrigin": false });
equal(false, caps.get("moz:useNonSpecCompliantPointerOrigin"));
caps = fromJSON({ "moz:useNonSpecCompliantPointerOrigin": true });
equal(true, caps.get("moz:useNonSpecCompliantPointerOrigin"));
caps = fromJSON({ "moz:webdriverClick": true });
equal(true, caps.get("moz:webdriverClick"));
caps = fromJSON({ "moz:webdriverClick": false });
equal(false, caps.get("moz:webdriverClick"));
// No longer supported capabilities
Assert.throws(
() => fromJSON({ "moz:useNonSpecCompliantPointerOrigin": false }),
/InvalidArgumentError/
);
Assert.throws(
() => fromJSON({ "moz:useNonSpecCompliantPointerOrigin": true }),
/InvalidArgumentError/
);
});
add_task(function test_mergeCapabilities() {
@ -535,10 +539,9 @@ add_task(function test_validateCapabilities_invalid() {
{ webSocketUrl: "foo" },
{ "moz:firefoxOptions": "foo" },
{ "moz:accessibilityChecks": "foo" },
{ "moz:useNonSpecCompliantPointerOrigin": "foo" },
{ "moz:useNonSpecCompliantPointerOrigin": 1 },
{ "moz:webdriverClick": "foo" },
{ "moz:webdriverClick": 1 },
{ "moz:useNonSpecCompliantPointerOrigin": false },
{ "moz:debuggerAddress": "foo" },
{ "moz:someRandomString": {} },
];
@ -567,7 +570,6 @@ add_task(function test_validateCapabilities_valid() {
{ webSocketUrl: true },
{ "moz:firefoxOptions": {} },
{ "moz:accessibilityChecks": true },
{ "moz:useNonSpecCompliantPointerOrigin": true },
{ "moz:webdriverClick": true },
{ "moz:debuggerAddress": true },
{ "test:extension": "foo" },

View File

@ -26,9 +26,7 @@ class InputModule extends WindowGlobalBiDiModule {
async performActions(options) {
const { actions } = options;
if (this.#actionState === null) {
this.#actionState = new lazy.action.State({
specCompatPointerOrigin: true,
});
this.#actionState = new lazy.action.State();
}
await this.#deserializeActionOrigins(actions);

View File

@ -56,6 +56,8 @@ websocket and interact with the browser by using the CDP protocol.
## `moz:useNonSpecCompliantPointerOrigin`
Note: This capability is no longer supported in Firefox 116 and later.
A boolean value to indicate how the pointer origin for an action
command will be calculated.
@ -67,10 +69,6 @@ referenced element, but on the in-view center point.
To temporarily disable the WebDriver conformant behavior use `false`
as value for this capability.
Please note that this capability exists only temporarily, and that
it will be removed once all Selenium bindings can handle the new
behavior.
## `moz:webdriverClick`
A boolean value to indicate which kind of interactability checks

View File

@ -6,7 +6,7 @@ import os
import sys
import unittest
from marionette_driver.errors import SessionNotCreatedException
import marionette_driver.errors as errors
from marionette_harness import MarionetteTestCase
@ -98,26 +98,29 @@ class TestCapabilities(MarionetteTestCase):
self.assertIn("moz:platformVersion", self.caps)
self.assertEqual(self.caps["moz:platformVersion"], self.os_version)
self.assertIn("moz:useNonSpecCompliantPointerOrigin", self.caps)
self.assertFalse(self.caps["moz:useNonSpecCompliantPointerOrigin"])
self.assertIn("moz:webdriverClick", self.caps)
self.assertTrue(self.caps["moz:webdriverClick"])
self.assertIn("moz:windowless", self.caps)
self.assertFalse(self.caps["moz:windowless"])
# No longer supported capabilities
self.assertNotIn("moz:useNonSpecCompliantPointerOrigin", self.caps)
def test_disable_webdriver_click(self):
self.marionette.delete_session()
self.marionette.start_session({"moz:webdriverClick": False})
caps = self.marionette.session_capabilities
self.assertFalse(caps["moz:webdriverClick"])
def test_use_non_spec_compliant_pointer_origin(self):
def test_no_longer_supported_capabilities(self):
self.marionette.delete_session()
self.marionette.start_session({"moz:useNonSpecCompliantPointerOrigin": True})
caps = self.marionette.session_capabilities
self.assertTrue(caps["moz:useNonSpecCompliantPointerOrigin"])
with self.assertRaisesRegexp(
errors.SessionNotCreatedException, "InvalidArgumentError"
):
self.marionette.start_session(
{"moz:useNonSpecCompliantPointerOrigin": True}
)
def test_valid_uuid4_when_creating_a_session(self):
self.assertNotIn(
@ -153,7 +156,7 @@ class TestCapabilityMatching(MarionetteTestCase):
def test_accept_insecure_certs(self):
for value in ["", 42, {}, []]:
print(" type {}".format(type(value)))
with self.assertRaises(SessionNotCreatedException):
with self.assertRaises(errors.SessionNotCreatedException):
self.marionette.start_session({"acceptInsecureCerts": value})
self.delete_session()
@ -174,20 +177,20 @@ class TestCapabilityMatching(MarionetteTestCase):
for value in ["", "EAGER", True, 42, {}, []]:
print("invalid strategy {}".format(value))
with self.assertRaisesRegexp(
SessionNotCreatedException, "InvalidArgumentError"
errors.SessionNotCreatedException, "InvalidArgumentError"
):
self.marionette.start_session({"pageLoadStrategy": value})
def test_set_window_rect(self):
with self.assertRaisesRegexp(
SessionNotCreatedException, "InvalidArgumentError"
errors.SessionNotCreatedException, "InvalidArgumentError"
):
self.marionette.start_session({"setWindowRect": False})
def test_timeouts(self):
for value in ["", 2.5, {}, []]:
print(" type {}".format(type(value)))
with self.assertRaises(SessionNotCreatedException):
with self.assertRaises(errors.SessionNotCreatedException):
self.marionette.start_session({"timeouts": {"pageLoad": value}})
self.delete_session()
@ -203,7 +206,7 @@ class TestCapabilityMatching(MarionetteTestCase):
def test_strict_file_interactability(self):
for value in ["", 2.5, {}, []]:
print(" type {}".format(type(value)))
with self.assertRaises(SessionNotCreatedException):
with self.assertRaises(errors.SessionNotCreatedException):
self.marionette.start_session({"strictFileInteractability": value})
self.delete_session()
@ -253,7 +256,7 @@ class TestCapabilityMatching(MarionetteTestCase):
for behavior in ["", "ACCEPT", True, 42, {}, []]:
print("invalid unhandled prompt behavior {}".format(behavior))
with self.assertRaisesRegexp(
SessionNotCreatedException, "InvalidArgumentError"
errors.SessionNotCreatedException, "InvalidArgumentError"
):
self.marionette.start_session({"unhandledPromptBehavior": behavior})

View File

@ -132,69 +132,3 @@ class TestPointerActions(BaseMouseAction):
lambda _: el.get_property("innerHTML") == "1",
message="Middle-click hasn't been fired",
)
class TestNonSpecCompliantPointerOrigin(BaseMouseAction):
def setUp(self):
super(TestNonSpecCompliantPointerOrigin, self).setUp()
self.marionette.delete_session()
self.marionette.start_session({"moz:useNonSpecCompliantPointerOrigin": True})
def tearDown(self):
self.marionette.delete_session()
self.marionette.start_session()
super(TestNonSpecCompliantPointerOrigin, self).tearDown()
def test_click_element_smaller_than_viewport(self):
self.marionette.navigate(
inline(
"""
<div id="div" style="width: 10vw; height: 10vh; background: green;"
onclick="window.click_x = event.clientX; window.click_y = event.clientY" />
"""
)
)
elem = self.marionette.find_element(By.ID, "div")
elem_center_point = self.get_element_center_point(elem)
self.mouse_chain.click(element=elem).perform()
click_position = Wait(self.marionette).until(
lambda _: self.click_position, message="No click event has been detected"
)
self.assertAlmostEqual(click_position["x"], elem_center_point["x"], delta=1)
self.assertAlmostEqual(click_position["y"], elem_center_point["y"], delta=1)
def test_click_element_larger_than_viewport_with_center_point_inside(self):
self.marionette.navigate(
inline(
"""
<div id="div" style="width: 150vw; height: 150vh; background: green;"
onclick="window.click_x = event.clientX; window.click_y = event.clientY" />
"""
)
)
elem = self.marionette.find_element(By.ID, "div")
elem_center_point = self.get_element_center_point(elem)
self.mouse_chain.click(element=elem).perform()
click_position = Wait(self.marionette).until(
lambda _: self.click_position, message="No click event has been detected"
)
self.assertAlmostEqual(click_position["x"], elem_center_point["x"], delta=1)
self.assertAlmostEqual(click_position["y"], elem_center_point["y"], delta=1)
def test_click_element_larger_than_viewport_with_center_point_outside(self):
self.marionette.navigate(
inline(
"""
<div id="div" style="width: 300vw; height: 300vh; background: green;"
onclick="window.click_x = event.clientX; window.click_y = event.clientY" />
"""
)
)
elem = self.marionette.find_element(By.ID, "div")
with self.assertRaises(errors.MoveTargetOutOfBoundsException):
self.mouse_chain.click(element=elem).perform()