embedder_traits/
webdriver.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5#![allow(missing_docs)]
6
7use std::collections::HashMap;
8
9use base::generic_channel::GenericSender;
10use base::id::{BrowsingContextId, WebViewId};
11use cookie::Cookie;
12use crossbeam_channel::Sender;
13use euclid::default::Rect as UntypedRect;
14use euclid::{Rect, Size2D};
15use hyper_serde::Serde;
16use image::RgbaImage;
17use ipc_channel::ipc::IpcSender;
18use malloc_size_of_derive::MallocSizeOf;
19use rustc_hash::FxHashMap;
20use serde::{Deserialize, Serialize};
21use servo_geometry::DeviceIndependentIntRect;
22use style_traits::CSSPixel;
23use url::Url;
24use webdriver::error::ErrorStatus;
25use webrender_api::units::DevicePixel;
26
27use crate::{InputEvent, JSValue, JavaScriptEvaluationError, ScreenshotCaptureError, TraversalId};
28
29#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
30pub enum WebDriverUserPrompt {
31    Alert,
32    BeforeUnload,
33    Confirm,
34    Default,
35    File,
36    Prompt,
37    FallbackDefault,
38}
39
40impl WebDriverUserPrompt {
41    pub fn new_from_str(s: &str) -> Option<Self> {
42        match s {
43            "alert" => Some(WebDriverUserPrompt::Alert),
44            "beforeUnload" => Some(WebDriverUserPrompt::BeforeUnload),
45            "confirm" => Some(WebDriverUserPrompt::Confirm),
46            "default" => Some(WebDriverUserPrompt::Default),
47            "file" => Some(WebDriverUserPrompt::File),
48            "prompt" => Some(WebDriverUserPrompt::Prompt),
49            "fallbackDefault" => Some(WebDriverUserPrompt::FallbackDefault),
50            _ => None,
51        }
52    }
53}
54
55#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
56pub enum WebDriverUserPromptAction {
57    Accept,
58    Dismiss,
59    Ignore,
60}
61
62impl WebDriverUserPromptAction {
63    pub fn new_from_str(s: &str) -> Option<Self> {
64        match s {
65            "accept" => Some(WebDriverUserPromptAction::Accept),
66            "dismiss" => Some(WebDriverUserPromptAction::Dismiss),
67            "ignore" => Some(WebDriverUserPromptAction::Ignore),
68            _ => None,
69        }
70    }
71}
72
73/// <https://html.spec.whatwg.org/multipage/#registerprotocolhandler()-automation-mode>
74#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
75pub enum CustomHandlersAutomationMode {
76    AutoAccept,
77    AutoReject,
78    #[default]
79    None,
80}
81
82/// Messages to the constellation originating from the WebDriver server.
83#[derive(Debug)]
84pub enum WebDriverCommandMsg {
85    /// Get the window rectangle.
86    GetWindowRect(WebViewId, IpcSender<DeviceIndependentIntRect>),
87    /// Get the viewport size.
88    GetViewportSize(WebViewId, IpcSender<Size2D<u32, DevicePixel>>),
89    /// Load a URL in the top-level browsing context with the given ID.
90    LoadUrl(WebViewId, Url, GenericSender<WebDriverLoadStatus>),
91    /// Refresh the top-level browsing context with the given ID.
92    Refresh(WebViewId, GenericSender<WebDriverLoadStatus>),
93    /// Navigate the webview with the given ID to the previous page in the browsing context's history.
94    GoBack(WebViewId, GenericSender<WebDriverLoadStatus>),
95    /// Navigate the webview with the given ID to the next page in the browsing context's history.
96    GoForward(WebViewId, GenericSender<WebDriverLoadStatus>),
97    /// Pass a webdriver command to the script thread of the current pipeline
98    /// of a browsing context.
99    ScriptCommand(BrowsingContextId, WebDriverScriptCommand),
100    /// Dispatch an input event to the given [`WebView`]. Once the event has been handled in the
101    /// page DOM a single message should be sent through the [`Sender`], if provided, informing the
102    /// WebDriver server that the inpute event has been handled.
103    InputEvent(WebViewId, InputEvent, Option<Sender<()>>),
104    /// Set the outer window rectangle.
105    SetWindowRect(
106        WebViewId,
107        DeviceIndependentIntRect,
108        IpcSender<DeviceIndependentIntRect>,
109    ),
110    /// Maximize the window. Send back result window rectangle.
111    MaximizeWebView(WebViewId, IpcSender<DeviceIndependentIntRect>),
112    /// Take a screenshot of the viewport.
113    TakeScreenshot(
114        WebViewId,
115        Option<Rect<f32, CSSPixel>>,
116        Sender<Result<RgbaImage, ScreenshotCaptureError>>,
117    ),
118    /// Create a new webview that loads about:blank. The embedder will use
119    /// the provided channels to return the top level browsing context id
120    /// associated with the new webview, and sets a "load status sender" if provided.
121    NewWebView(
122        IpcSender<WebViewId>,
123        Option<GenericSender<WebDriverLoadStatus>>,
124    ),
125    /// Close the webview associated with the provided id.
126    CloseWebView(WebViewId, IpcSender<()>),
127    /// Focus the webview associated with the provided id.
128    FocusWebView(WebViewId),
129    /// Get focused webview. For now, this is only used when start new session.
130    GetFocusedWebView(IpcSender<Option<WebViewId>>),
131    /// Get webviews state
132    GetAllWebViews(IpcSender<Vec<WebViewId>>),
133    /// Check whether top-level browsing context is open.
134    IsWebViewOpen(WebViewId, IpcSender<bool>),
135    /// Check whether browsing context is open.
136    IsBrowsingContextOpen(BrowsingContextId, IpcSender<bool>),
137    CurrentUserPrompt(WebViewId, IpcSender<Option<WebDriverUserPrompt>>),
138    HandleUserPrompt(
139        WebViewId,
140        WebDriverUserPromptAction,
141        IpcSender<Result<String, ()>>,
142    ),
143    GetAlertText(WebViewId, IpcSender<Result<String, ()>>),
144    SendAlertText(WebViewId, String),
145    FocusBrowsingContext(BrowsingContextId),
146    Shutdown,
147    ResetAllCookies(Sender<()>),
148}
149
150#[derive(Debug, Deserialize, Serialize)]
151pub enum WebDriverScriptCommand {
152    AddCookie(
153        #[serde(
154            deserialize_with = "::hyper_serde::deserialize",
155            serialize_with = "::hyper_serde::serialize"
156        )]
157        Cookie<'static>,
158        IpcSender<Result<(), ErrorStatus>>,
159    ),
160    DeleteCookies(IpcSender<Result<(), ErrorStatus>>),
161    DeleteCookie(String, IpcSender<Result<(), ErrorStatus>>),
162    ElementClear(String, IpcSender<Result<(), ErrorStatus>>),
163    ExecuteScript(String, IpcSender<WebDriverJSResult>),
164    ExecuteAsyncScript(String, IpcSender<WebDriverJSResult>),
165    FindElementsCSSSelector(String, IpcSender<Result<Vec<String>, ErrorStatus>>),
166    FindElementsLinkText(String, bool, IpcSender<Result<Vec<String>, ErrorStatus>>),
167    FindElementsTagName(String, IpcSender<Result<Vec<String>, ErrorStatus>>),
168    FindElementsXpathSelector(String, IpcSender<Result<Vec<String>, ErrorStatus>>),
169    FindElementElementsCSSSelector(String, String, IpcSender<Result<Vec<String>, ErrorStatus>>),
170    FindElementElementsLinkText(
171        String,
172        String,
173        bool,
174        IpcSender<Result<Vec<String>, ErrorStatus>>,
175    ),
176    FindElementElementsTagName(String, String, IpcSender<Result<Vec<String>, ErrorStatus>>),
177    FindElementElementsXPathSelector(String, String, IpcSender<Result<Vec<String>, ErrorStatus>>),
178    FindShadowElementsCSSSelector(String, String, IpcSender<Result<Vec<String>, ErrorStatus>>),
179    FindShadowElementsLinkText(
180        String,
181        String,
182        bool,
183        IpcSender<Result<Vec<String>, ErrorStatus>>,
184    ),
185    FindShadowElementsTagName(String, String, IpcSender<Result<Vec<String>, ErrorStatus>>),
186    FindShadowElementsXPathSelector(String, String, IpcSender<Result<Vec<String>, ErrorStatus>>),
187    GetElementShadowRoot(String, IpcSender<Result<Option<String>, ErrorStatus>>),
188    ElementClick(String, IpcSender<Result<Option<String>, ErrorStatus>>),
189    GetKnownElement(String, IpcSender<Result<(), ErrorStatus>>),
190    GetKnownShadowRoot(String, IpcSender<Result<(), ErrorStatus>>),
191    GetKnownWindow(String, IpcSender<Result<(), ErrorStatus>>),
192    GetActiveElement(IpcSender<Option<String>>),
193    GetComputedRole(String, IpcSender<Result<Option<String>, ErrorStatus>>),
194    GetCookie(
195        String,
196        IpcSender<Result<Vec<Serde<Cookie<'static>>>, ErrorStatus>>,
197    ),
198    GetCookies(IpcSender<Result<Vec<Serde<Cookie<'static>>>, ErrorStatus>>),
199    GetElementAttribute(
200        String,
201        String,
202        IpcSender<Result<Option<String>, ErrorStatus>>,
203    ),
204    GetElementProperty(String, String, IpcSender<Result<JSValue, ErrorStatus>>),
205    GetElementCSS(String, String, IpcSender<Result<String, ErrorStatus>>),
206    GetElementRect(String, IpcSender<Result<UntypedRect<f64>, ErrorStatus>>),
207    GetElementTagName(String, IpcSender<Result<String, ErrorStatus>>),
208    GetElementText(String, IpcSender<Result<String, ErrorStatus>>),
209    GetElementInViewCenterPoint(String, IpcSender<Result<Option<(i64, i64)>, ErrorStatus>>),
210    ScrollAndGetBoundingClientRect(String, IpcSender<Result<UntypedRect<f32>, ErrorStatus>>),
211    GetBrowsingContextId(
212        WebDriverFrameId,
213        IpcSender<Result<BrowsingContextId, ErrorStatus>>,
214    ),
215    GetParentFrameId(IpcSender<Result<BrowsingContextId, ErrorStatus>>),
216    GetUrl(IpcSender<String>),
217    GetPageSource(IpcSender<Result<String, ErrorStatus>>),
218    IsEnabled(String, IpcSender<Result<bool, ErrorStatus>>),
219    IsSelected(String, IpcSender<Result<bool, ErrorStatus>>),
220    GetTitle(IpcSender<String>),
221    /// Deal with the case of input element for Element Send Keys, which does not send keys.
222    WillSendKeys(String, String, bool, IpcSender<Result<bool, ErrorStatus>>),
223    AddLoadStatusSender(WebViewId, GenericSender<WebDriverLoadStatus>),
224    RemoveLoadStatusSender(WebViewId),
225    SetProtocolHandlerAutomationMode(CustomHandlersAutomationMode),
226}
227
228pub type WebDriverJSResult = Result<JSValue, JavaScriptEvaluationError>;
229
230#[derive(Debug, Deserialize, Serialize)]
231pub enum WebDriverFrameId {
232    Short(u16),
233    Element(String),
234}
235
236#[derive(Debug, Deserialize, Serialize)]
237pub enum WebDriverLoadStatus {
238    NavigationStart,
239    // Navigation stops for any reason
240    NavigationStop,
241    // Document ready state is complete
242    Complete,
243    // Load timeout
244    Timeout,
245    // Navigation is blocked by a user prompt
246    Blocked,
247}
248
249/// A collection of [`IpcSender`]s that are used to asynchronously communicate
250/// to a WebDriver server with information about application state.
251#[derive(Clone, Default)]
252pub struct WebDriverSenders {
253    pub load_status_senders: FxHashMap<WebViewId, GenericSender<WebDriverLoadStatus>>,
254    pub script_evaluation_interrupt_sender: Option<IpcSender<WebDriverJSResult>>,
255    pub pending_traversals: HashMap<TraversalId, GenericSender<WebDriverLoadStatus>>,
256}