mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
Implement webdriver element in view (#38329)
Implement step 6 of `ElementClick`: https://w3c.github.io/webdriver/#dfn-element-click Tests: `tests/wpt/tests/webdriver/tests/classic/element_click/interactability.py` cc: @xiaochengh Signed-off-by: batu_hoang <hoang.binh.trong@huawei.com>
This commit is contained in:
parent
8008d5aa85
commit
8e27fd48cc
3 changed files with 52 additions and 29 deletions
|
@ -28,6 +28,7 @@ use net_traits::CoreResourceMsg::{
|
||||||
use net_traits::IpcSend;
|
use net_traits::IpcSend;
|
||||||
use script_bindings::codegen::GenericBindings::ShadowRootBinding::ShadowRootMethods;
|
use script_bindings::codegen::GenericBindings::ShadowRootBinding::ShadowRootMethods;
|
||||||
use script_bindings::conversions::is_array_like;
|
use script_bindings::conversions::is_array_like;
|
||||||
|
use script_bindings::num::Finite;
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use webdriver::common::{WebElement, WebFrame, WebWindow};
|
use webdriver::common::{WebElement, WebFrame, WebWindow};
|
||||||
use webdriver::error::ErrorStatus;
|
use webdriver::error::ErrorStatus;
|
||||||
|
@ -1829,10 +1830,16 @@ pub(crate) fn handle_element_click(
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 5
|
// Step 5
|
||||||
// TODO: scroll into view
|
// TODO: scroll into view is not implemented in Servo
|
||||||
|
|
||||||
// Step 6
|
// Step 6. If element's container is still not in view
|
||||||
// TODO: return error if still not in view
|
// return error with error code element not interactable.
|
||||||
|
let document = documents
|
||||||
|
.find_document(pipeline)
|
||||||
|
.expect("Document existence guaranteed by `get_known_element`");
|
||||||
|
if !is_element_in_view(&element, &document, can_gc) {
|
||||||
|
return Err(ErrorStatus::ElementNotInteractable);
|
||||||
|
}
|
||||||
|
|
||||||
// Step 7
|
// Step 7
|
||||||
// TODO: return error if obscured
|
// TODO: return error if obscured
|
||||||
|
@ -1889,6 +1896,40 @@ pub(crate) fn handle_element_click(
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <https://w3c.github.io/webdriver/#dfn-in-view>
|
||||||
|
fn is_element_in_view(element: &Element, document: &Document, can_gc: CanGc) -> bool {
|
||||||
|
element.enabled_state() &&
|
||||||
|
get_element_pointer_interactable_paint_tree(element, document, can_gc)
|
||||||
|
.contains(&DomRoot::from_ref(element))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://w3c.github.io/webdriver/#dfn-pointer-interactable-paint-tree>
|
||||||
|
fn get_element_pointer_interactable_paint_tree(
|
||||||
|
element: &Element,
|
||||||
|
document: &Document,
|
||||||
|
can_gc: CanGc,
|
||||||
|
) -> Vec<DomRoot<Element>> {
|
||||||
|
// Step 2. Let rectangles be the DOMRect sequence returned by calling getClientRects()
|
||||||
|
let rect = element.GetClientRects(can_gc);
|
||||||
|
|
||||||
|
if rect.first().is_some() {
|
||||||
|
// Step 4. Let center point be the in-view center point of
|
||||||
|
// the first indexed element in rectangles.
|
||||||
|
match get_element_in_view_center_point(element, can_gc) {
|
||||||
|
// Step 5. Return the elements from point given the coordinates center point
|
||||||
|
Some(center_point) => document.ElementsFromPoint(
|
||||||
|
Finite::wrap(center_point.x as f64),
|
||||||
|
Finite::wrap(center_point.y as f64),
|
||||||
|
can_gc,
|
||||||
|
),
|
||||||
|
None => Vec::new(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Step 3. If rectangles has the length of 0, return an empty sequence
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn handle_is_enabled(
|
pub(crate) fn handle_is_enabled(
|
||||||
documents: &DocumentCollection,
|
documents: &DocumentCollection,
|
||||||
pipeline: PipelineId,
|
pipeline: PipelineId,
|
||||||
|
|
|
@ -2141,7 +2141,7 @@ impl Handler {
|
||||||
|
|
||||||
let (sender, receiver) = ipc::channel().unwrap();
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
|
|
||||||
// Steps 1 - 7 + Step 8 for <option>
|
// Steps 3-7 + Step 8 for <option> are handled in script thread.
|
||||||
let cmd = WebDriverScriptCommand::ElementClick(element.to_string(), sender);
|
let cmd = WebDriverScriptCommand::ElementClick(element.to_string(), sender);
|
||||||
self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;
|
self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::No)?;
|
||||||
|
|
||||||
|
|
|
@ -1,33 +1,15 @@
|
||||||
[interactability.py]
|
[interactability.py]
|
||||||
[test_display_none]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_visibility_hidden]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_hidden]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_element_not_interactable_css_transform[translate(-100px, -100px)\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_element_not_interactable_css_transform[rotate(50deg)\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_element_not_interactable_out_of_view]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_zero_sized_element[div\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_zero_sized_element[span\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_element_intercepted]
|
[test_element_intercepted]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[test_element_intercepted_no_pointer_events]
|
[test_element_intercepted_no_pointer_events]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[test_element_not_visible_overflow_hidden]
|
[test_disabled]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_element_interactable_css_transform[translate(100px, 100px)\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_element_interactable_css_transform[rotate(50deg)\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue