diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 87c66b5655a..84043dde0f6 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -2280,15 +2280,6 @@ impl ScriptThread { can_gc, ) }, - WebDriverScriptCommand::FocusElement(element_id, reply) => { - webdriver_handlers::handle_focus_element( - &documents, - pipeline_id, - element_id, - reply, - can_gc, - ) - }, WebDriverScriptCommand::ElementClick(element_id, reply) => { webdriver_handlers::handle_element_click( &documents, @@ -2394,6 +2385,20 @@ impl ScriptThread { WebDriverScriptCommand::GetTitle(reply) => { webdriver_handlers::handle_get_title(&documents, pipeline_id, reply) }, + WebDriverScriptCommand::WillSendKeys( + strict_file_interactability, + text, + element_id, + reply, + ) => webdriver_handlers::handle_will_send_keys( + &documents, + pipeline_id, + element_id, + text, + strict_file_interactability, + reply, + can_gc, + ), _ => (), } } diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs index 980c924e5e4..c81dcbd85fd 100644 --- a/components/script/webdriver_handlers.rs +++ b/components/script/webdriver_handlers.rs @@ -843,24 +843,66 @@ pub(crate) fn handle_find_element_elements_tag_name( .unwrap(); } -pub(crate) fn handle_focus_element( +pub(crate) fn handle_will_send_keys( documents: &DocumentCollection, pipeline: PipelineId, element_id: String, - reply: IpcSender>, + text: String, + strict_file_interactability: bool, + reply: IpcSender>, can_gc: CanGc, ) { reply .send( find_node_by_unique_id(documents, pipeline, element_id).and_then(|node| { - match node.downcast::() { - Some(element) => { - // Need a way to find if this actually succeeded - element.Focus(can_gc); - Ok(()) - }, - None => Err(ErrorStatus::UnknownError), + // Step 6: Let file be true if element is input element + // in the file upload state, or false otherwise + let file_input = node + .downcast::() + .filter(|&input_element| input_element.input_type() == InputType::File); + + // Step 7: If file is false or the session's strict file interactability + if file_input.is_none() || strict_file_interactability { + match node.downcast::() { + Some(element) => { + // Need a way to find if this actually succeeded + element.Focus(can_gc); + }, + None => return Err(ErrorStatus::UnknownError), + } } + + // Step 8 (file input) + if let Some(file_input) = file_input { + // Step 8.1: Let files be the result of splitting text + // on the newline (\n) character. + let files: Vec = text.split("\n").map(|s| s.into()).collect(); + + // Step 8.2 + if files.is_empty() { + return Err(ErrorStatus::InvalidArgument); + } + + // Step 8.3 - 8.4 + if !file_input.Multiple() && files.len() > 1 { + return Err(ErrorStatus::InvalidArgument); + } + + // Step 8.5 + // TODO: Should return invalid argument error if file doesn't exist + + // Step 8.6 - 8.7 + // Input and change event already fired in `htmlinputelement.rs`. + file_input.SelectFiles(files, can_gc); + + // Step 8.8 + return Ok(false); + } + + // TODO: Check non-typeable form control + // TODO: Check content editable + + Ok(true) }), ) .unwrap(); diff --git a/components/shared/embedder/webdriver.rs b/components/shared/embedder/webdriver.rs index 7b0f02bc26a..0444001a2cd 100644 --- a/components/shared/embedder/webdriver.rs +++ b/components/shared/embedder/webdriver.rs @@ -130,7 +130,6 @@ pub enum WebDriverScriptCommand { IpcSender, ErrorStatus>>, ), FindElementElementsTagName(String, String, IpcSender, ErrorStatus>>), - FocusElement(String, IpcSender>), ElementClick(String, IpcSender, ErrorStatus>>), GetActiveElement(IpcSender>), GetComputedRole(String, IpcSender, ErrorStatus>>), @@ -161,6 +160,8 @@ pub enum WebDriverScriptCommand { IsEnabled(String, IpcSender>), IsSelected(String, IpcSender>), GetTitle(IpcSender), + /// Match the element type before sending the event for webdriver `element send keys`. + WillSendKeys(bool, String, String, IpcSender>), } #[derive(Debug, Deserialize, Serialize)] diff --git a/components/webdriver_server/lib.rs b/components/webdriver_server/lib.rs index 8551080d347..b8769eb21e8 100644 --- a/components/webdriver_server/lib.rs +++ b/components/webdriver_server/lib.rs @@ -1619,14 +1619,23 @@ impl Handler { let (sender, receiver) = ipc::channel().unwrap(); - let cmd = WebDriverScriptCommand::FocusElement(element.to_string(), sender); + let cmd = WebDriverScriptCommand::WillSendKeys( + self.session()?.strict_file_interactability, + keys.text.to_string(), + element.to_string(), + sender, + ); let cmd_msg = WebDriverCommandMsg::ScriptCommand(browsing_context_id, cmd); self.constellation_chan .send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg)) .unwrap(); // TODO: distinguish the not found and not focusable cases - wait_for_script_response(receiver)?.map_err(|error| WebDriverError::new(error, ""))?; + // File input and non-typeable form control should have + // been handled in `webdriver_handler.rs`. + if wait_for_script_response(receiver)?.map_err(|error| WebDriverError::new(error, ""))? { + return Ok(WebDriverResponse::Void); + } let input_events = send_keys(&keys.text); diff --git a/tests/wpt/meta/webdriver/tests/classic/element_send_keys/events.py.ini b/tests/wpt/meta/webdriver/tests/classic/element_send_keys/events.py.ini index 26b3aaa641b..5e4543ef0e9 100644 --- a/tests/wpt/meta/webdriver/tests/classic/element_send_keys/events.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/element_send_keys/events.py.ini @@ -1,7 +1,4 @@ [events.py] - [test_file_upload] - expected: FAIL - [test_form_control_send_text[input\]] expected: FAIL diff --git a/tests/wpt/meta/webdriver/tests/classic/element_send_keys/file_upload.py.ini b/tests/wpt/meta/webdriver/tests/classic/element_send_keys/file_upload.py.ini index 4fd4b29e87f..40a4a701288 100644 --- a/tests/wpt/meta/webdriver/tests/classic/element_send_keys/file_upload.py.ini +++ b/tests/wpt/meta/webdriver/tests/classic/element_send_keys/file_upload.py.ini @@ -1,50 +1,19 @@ [file_upload.py] - expected: TIMEOUT [test_empty_text] expected: FAIL - [test_multiple_files] - expected: FAIL - [test_multiple_files_last_path_not_found] expected: FAIL - [test_multiple_files_without_multiple_attribute] - expected: FAIL - [test_multiple_files_send_twice] expected: FAIL [test_multiple_files_reset_with_element_clear] expected: FAIL - [test_single_file] - expected: FAIL - - [test_single_file_replaces_without_multiple_attribute] - expected: FAIL - [test_single_file_appends_with_multiple_attribute] expected: FAIL - [test_transparent] - expected: FAIL - - [test_obscured] - expected: FAIL - - [test_outside_viewport] - expected: FAIL - - [test_hidden] - expected: FAIL - - [test_display_none] - expected: FAIL - - [test_not_focused] - expected: FAIL - [test_focused] expected: ERROR