mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-31 19:10:36 +00:00
Bug 1490258 - [marionette] Remove moz:useNonSpecCompliantPointerOrigin capability. r=webdriver-reviewers,jgraham
Differential Revision: https://phabricator.services.mozilla.com/D181280
This commit is contained in:
parent
446672d058
commit
1f4f920af8
@ -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);
|
||||
|
||||
|
@ -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(),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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" },
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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})
|
||||
|
||||
|
@ -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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user