mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 20:12:43 +00:00 
			
		
		
		
	WebDriver: Implement POST /session/{session id}/execute/sync endpoint
				
					
				
			This commit is contained in:
		
							parent
							
								
									6e1131e6de
								
							
						
					
					
						commit
						f88a0c51a3
					
				
					 4 changed files with 87 additions and 0 deletions
				
			
		|  | @ -49,6 +49,7 @@ Vector<Client::Route> Client::s_routes = { | |||
|     { HTTP::HttpRequest::Method::GET, { "session", ":session_id", "element", ":element_id", "css", ":property_name" }, &Client::handle_get_element_css_value }, | ||||
|     { HTTP::HttpRequest::Method::GET, { "session", ":session_id", "element", ":element_id", "text" }, &Client::handle_get_element_text }, | ||||
|     { HTTP::HttpRequest::Method::GET, { "session", ":session_id", "element", ":element_id", "name" }, &Client::handle_get_element_tag_name }, | ||||
|     { HTTP::HttpRequest::Method::POST, { "session", ":session_id", "execute", "sync" }, &Client::handle_execute_script }, | ||||
|     { HTTP::HttpRequest::Method::GET, { "session", ":session_id", "cookie" }, &Client::handle_get_all_cookies }, | ||||
|     { HTTP::HttpRequest::Method::GET, { "session", ":session_id", "cookie", ":name" }, &Client::handle_get_named_cookie }, | ||||
|     { HTTP::HttpRequest::Method::POST, { "session", ":session_id", "cookie" }, &Client::handle_add_cookie }, | ||||
|  | @ -685,6 +686,16 @@ ErrorOr<JsonValue, WebDriverError> Client::handle_get_element_tag_name(Vector<St | |||
|     return make_json_value(result); | ||||
| } | ||||
| 
 | ||||
| // 13.2.1 Execute Script, https://w3c.github.io/webdriver/#dfn-execute-script
 | ||||
| // POST /session/{session id}/execute/sync
 | ||||
| ErrorOr<JsonValue, WebDriverError> Client::handle_execute_script(Vector<StringView> const& parameters, JsonValue const& payload) | ||||
| { | ||||
|     dbgln_if(WEBDRIVER_DEBUG, "Handling POST /session/<session_id>/execute/sync"); | ||||
|     auto* session = TRY(find_session_with_id(parameters[0])); | ||||
|     auto result = TRY(session->execute_script(payload)); | ||||
|     return make_json_value(result); | ||||
| } | ||||
| 
 | ||||
| // 14.1 Get All Cookies, https://w3c.github.io/webdriver/#dfn-get-all-cookies
 | ||||
| // GET /session/{session id}/cookie
 | ||||
| ErrorOr<JsonValue, WebDriverError> Client::handle_get_all_cookies(Vector<StringView> const& parameters, JsonValue const&) | ||||
|  |  | |||
|  | @ -74,6 +74,7 @@ private: | |||
|     ErrorOr<JsonValue, WebDriverError> handle_get_element_css_value(Vector<StringView> const&, JsonValue const& payload); | ||||
|     ErrorOr<JsonValue, WebDriverError> handle_get_element_text(Vector<StringView> const&, JsonValue const& payload); | ||||
|     ErrorOr<JsonValue, WebDriverError> handle_get_element_tag_name(Vector<StringView> const&, JsonValue const& payload); | ||||
|     ErrorOr<JsonValue, WebDriverError> handle_execute_script(Vector<StringView> const&, JsonValue const& payload); | ||||
|     ErrorOr<JsonValue, WebDriverError> handle_get_all_cookies(Vector<StringView> const&, JsonValue const& payload); | ||||
|     ErrorOr<JsonValue, WebDriverError> handle_get_named_cookie(Vector<StringView> const&, JsonValue const& payload); | ||||
|     ErrorOr<JsonValue, WebDriverError> handle_add_cookie(Vector<StringView> const&, JsonValue const& payload); | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ | |||
| #include <LibGfx/Size.h> | ||||
| #include <LibWeb/Cookie/Cookie.h> | ||||
| #include <LibWeb/Cookie/ParsedCookie.h> | ||||
| #include <LibWeb/WebDriver/ExecuteScript.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| namespace WebDriver { | ||||
|  | @ -899,6 +900,79 @@ ErrorOr<JsonValue, WebDriverError> Session::get_element_tag_name(JsonValue const | |||
|     return JsonValue(qualified_name); | ||||
| } | ||||
| 
 | ||||
| struct ScriptArguments { | ||||
|     String script; | ||||
|     JsonArray const& arguments; | ||||
| }; | ||||
| 
 | ||||
| // https://w3c.github.io/webdriver/#dfn-extract-the-script-arguments-from-a-request
 | ||||
| static ErrorOr<ScriptArguments, WebDriverError> extract_the_script_arguments_from_a_request(JsonValue const& payload) | ||||
| { | ||||
|     if (!payload.is_object()) | ||||
|         return WebDriverError::from_code(ErrorCode::InvalidArgument, "Payload is not a JSON object"); | ||||
| 
 | ||||
|     auto const& properties = payload.as_object(); | ||||
| 
 | ||||
|     // 1. Let script be the result of getting a property named script from the parameters.
 | ||||
|     // 2. If script is not a String, return error with error code invalid argument.
 | ||||
|     if (!properties.has_string("script"sv)) | ||||
|         return WebDriverError::from_code(ErrorCode::InvalidArgument, "Payload doesn't have a 'script' string property"); | ||||
|     auto script = properties.get("script"sv).as_string(); | ||||
| 
 | ||||
|     // 3. Let args be the result of getting a property named args from the parameters.
 | ||||
|     // 4. If args is not an Array return error with error code invalid argument.
 | ||||
|     if (!properties.has_array("args"sv)) | ||||
|         return WebDriverError::from_code(ErrorCode::InvalidArgument, "Payload doesn't have an 'args' string property"); | ||||
|     auto const& args = properties.get("args"sv).as_array(); | ||||
| 
 | ||||
|     // 5. Let arguments be the result of calling the JSON deserialize algorithm with arguments args.
 | ||||
|     // NOTE: We forward the JSON array to the Browser and then WebContent process over IPC, so this is not necessary.
 | ||||
| 
 | ||||
|     // 6. Return success with data script and arguments.
 | ||||
|     return ScriptArguments { script, args }; | ||||
| } | ||||
| 
 | ||||
| // 13.2.1 Execute Script, https://w3c.github.io/webdriver/#dfn-execute-script
 | ||||
| ErrorOr<JsonValue, WebDriverError> Session::execute_script(JsonValue const& payload) | ||||
| { | ||||
|     // 1. Let body and arguments be the result of trying to extract the script arguments from a request with argument parameters.
 | ||||
|     auto const& [body, arguments] = TRY(extract_the_script_arguments_from_a_request(payload)); | ||||
| 
 | ||||
|     // 2. If the current browsing context is no longer open, return error with error code no such window.
 | ||||
|     TRY(check_for_open_top_level_browsing_context_or_return_error()); | ||||
| 
 | ||||
|     // FIXME: 3. Handle any user prompts, and return its value if it is an error.
 | ||||
| 
 | ||||
|     // 4., 5.1-5.3.
 | ||||
|     Vector<String> json_arguments; | ||||
|     arguments.for_each([&](JsonValue const& json_value) { | ||||
|         // NOTE: serialized() instead of to_string() ensures proper quoting.
 | ||||
|         json_arguments.append(json_value.serialized<StringBuilder>()); | ||||
|     }); | ||||
| 
 | ||||
|     dbgln("Executing script with 'args': [{}] / 'body':\n{}", String::join(", "sv, json_arguments), body); | ||||
|     auto execute_script_response = m_browser_connection->execute_script(body, json_arguments, m_timeouts_configuration.script_timeout, false); | ||||
|     dbgln("Executing script returned: {}", execute_script_response.json_result()); | ||||
| 
 | ||||
|     // NOTE: This is assumed to be a valid JSON value.
 | ||||
|     auto result = MUST(JsonValue::from_string(execute_script_response.json_result())); | ||||
| 
 | ||||
|     switch (execute_script_response.result_type()) { | ||||
|     // 6. If promise is still pending and the session script timeout is reached, return error with error code script timeout.
 | ||||
|     case Web::WebDriver::ExecuteScriptResultType::Timeout: | ||||
|         return WebDriverError::from_code(ErrorCode::ScriptTimeoutError, "Script timed out"); | ||||
|     // 7. Upon fulfillment of promise with value v, let result be a JSON clone of v, and return success with data result.
 | ||||
|     case Web::WebDriver::ExecuteScriptResultType::PromiseResolved: | ||||
|         return result; | ||||
|     // 8. Upon rejection of promise with reason r, let result be a JSON clone of r, and return error with error code javascript error and data result.
 | ||||
|     case Web::WebDriver::ExecuteScriptResultType::PromiseRejected: | ||||
|     case Web::WebDriver::ExecuteScriptResultType::JavaScriptError: | ||||
|         return WebDriverError::from_code(ErrorCode::JavascriptError, "Script returned an error", move(result)); | ||||
|     default: | ||||
|         VERIFY_NOT_REACHED(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // https://w3c.github.io/webdriver/#dfn-serialized-cookie
 | ||||
| static JsonObject serialize_cookie(Web::Cookie::Cookie const& cookie) | ||||
| { | ||||
|  |  | |||
|  | @ -63,6 +63,7 @@ public: | |||
|     ErrorOr<JsonValue, WebDriverError> get_element_css_value(JsonValue const& payload, StringView element_id, StringView property_name); | ||||
|     ErrorOr<JsonValue, WebDriverError> get_element_text(JsonValue const& payload, StringView element_id); | ||||
|     ErrorOr<JsonValue, WebDriverError> get_element_tag_name(JsonValue const& payload, StringView element_id); | ||||
|     ErrorOr<JsonValue, WebDriverError> execute_script(JsonValue const& payload); | ||||
|     ErrorOr<JsonValue, WebDriverError> get_all_cookies(); | ||||
|     ErrorOr<JsonValue, WebDriverError> get_named_cookie(String const& name); | ||||
|     ErrorOr<JsonValue, WebDriverError> add_cookie(JsonValue const& payload); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Linus Groh
						Linus Groh