Rework on webdriver wait for navigation complete (#38234)

For current implementation, when a command may trigger a navigation,
webdriver only waits for document readiness state.
However, not all navigations make change in document.
This PR handles more cases for waiting for a navigation, and apply to
`element_click`.

- Before sending a command which may trigger a navigation, `webdriver`
sets `load status send` to `embedder`, `constelltation` and `script
thread` to listen to `navigation events`.
- Webdriver check if there is a navigation with `script thread`.
- If the navigation is loading a new url, webdriver checks if the
request is approved with `constellation`, then waits for document
readiness state.
- If the navigation is a hashchange, webdriver waits untill all new
generated dom events have been processed.

Testing: 
`tests/wpt/tests/webdriver/tests/classic/element_click/navigate.py`
`tests/wpt/tests/webdriver/tests/classic/element_click/user_prompts.py`
https://github.com/longvatrong111/servo/actions/runs/16488690749

cc: @xiaochengh

---------

Signed-off-by: batu_hoang <hoang.binh.trong@huawei.com>
This commit is contained in:
batu_hoang 2025-07-30 15:24:07 +08:00 committed by GitHub
parent 8b3e7b1c6a
commit 37ac4ffeb4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 188 additions and 125 deletions

View file

@ -8,7 +8,9 @@ use std::ptr::NonNull;
use base::id::{BrowsingContextId, PipelineId};
use cookie::Cookie;
use embedder_traits::{WebDriverFrameId, WebDriverJSError, WebDriverJSResult, WebDriverJSValue};
use embedder_traits::{
WebDriverFrameId, WebDriverJSError, WebDriverJSResult, WebDriverJSValue, WebDriverLoadStatus,
};
use euclid::default::{Point2D, Rect, Size2D};
use hyper_serde::Serde;
use ipc_channel::ipc::{self, IpcSender};
@ -33,9 +35,7 @@ use webdriver::error::ErrorStatus;
use crate::document_collection::DocumentCollection;
use crate::dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationMethods;
use crate::dom::bindings::codegen::Bindings::DOMRectBinding::DOMRectMethods;
use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
DocumentMethods, DocumentReadyState,
};
use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
use crate::dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
use crate::dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
@ -1926,19 +1926,23 @@ pub(crate) fn handle_is_selected(
.unwrap();
}
pub(crate) fn handle_try_wait_for_document_navigation(
pub(crate) fn handle_add_load_status_sender(
documents: &DocumentCollection,
pipeline: PipelineId,
reply: IpcSender<bool>,
reply: IpcSender<WebDriverLoadStatus>,
) {
let document = match documents.find_document(pipeline) {
Some(document) => document,
None => {
return reply.send(false).unwrap();
},
};
let wait_for_document_ready = document.ReadyState() != DocumentReadyState::Complete;
reply.send(wait_for_document_ready).unwrap();
if let Some(document) = documents.find_document(pipeline) {
let window = document.window();
window.set_webdriver_load_status_sender(Some(reply));
}
}
pub(crate) fn handle_remove_load_status_sender(
documents: &DocumentCollection,
pipeline: PipelineId,
) {
if let Some(document) = documents.find_document(pipeline) {
let window = document.window();
window.set_webdriver_load_status_sender(None);
}
}