diff --git a/examples/extensions/Cargo.toml b/examples/extensions/Cargo.toml new file mode 100644 index 0000000..98b3d3e --- /dev/null +++ b/examples/extensions/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "extensions" +version = "0.1.0" +authors = [""] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +fantoccini = {path="../../"} +futures = "0.3.0" +tokio = {version="0.2.21", features=["macros"]} +serde_json = "1.0.56" +serde = "1.0.114" diff --git a/examples/extensions/src/main.rs b/examples/extensions/src/main.rs new file mode 100644 index 0000000..d46b351 --- /dev/null +++ b/examples/extensions/src/main.rs @@ -0,0 +1,78 @@ +/// This example is only work with geckodriver +extern crate fantoccini; +extern crate tokio; +extern crate serde; +extern crate serde_json; + +use fantoccini::{Client, ExtensionCommand, Method, WebDriverExtensionCommand}; +use serde::Serialize; +use serde_json::Value; +use std::io::Error; +use std::thread::sleep; +use std::time::Duration; + +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct AddonInstallParameters { + pub path: String, + pub temporary: Option, +} + +#[derive(Clone, Debug, PartialEq, Serialize)] +pub struct AddonUninstallParameters { + pub id: String, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum GeckoExtensionCommand { + InstallAddon(AddonInstallParameters), + UninstallAddon(AddonUninstallParameters) +} + +impl ExtensionCommand for GeckoExtensionCommand { + fn method(&self) -> Method { + Method::POST + } + + fn endpoint(&self) -> &str { + match self { + Self::InstallAddon(_)=>"/moz/addon/install", + Self::UninstallAddon(_)=>"/moz/addon/uninstall" + } + } +} + +impl WebDriverExtensionCommand for GeckoExtensionCommand { + fn parameters_json(&self) -> Option { + Some(match self { + Self::InstallAddon(param)=>serde_json::to_value(param).unwrap(), + Self::UninstallAddon(param)=>serde_json::to_value(param).unwrap() + }) + } +} + +#[tokio::main] +async fn main()-> Result<(), Error> { + let mut client = Client::new("http://localhost:4444").await.unwrap(); + + let install_command = GeckoExtensionCommand::InstallAddon(AddonInstallParameters { + path: String::from("/path/to/addon.xpi"), + temporary: Some(true) + }); + let ins_res = client.extension_command(install_command).await.expect("Can not install the addon"); + + println!("Install Response: {:#?}", ins_res); + + let addon_id = ins_res.as_str().unwrap(); + + sleep(Duration::from_secs(5)); + + let uninstall_command = GeckoExtensionCommand::UninstallAddon(AddonUninstallParameters{ + id: String::from(addon_id) + }); + + let uns_res = client.extension_command(uninstall_command).await.expect("Can not uninstall the addon"); + + println!("Uninstall Reponse: {:#?}", uns_res); + + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs index 3fe6c5c..3508cd7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -193,25 +193,26 @@ impl<'a> From> for webdriver::command::LocatorParameters { } } -pub use crate::session::Client; +pub use crate::session::{Client, ExtensionCommand, VoidExtensionCommand}; +pub use webdriver::command::WebDriverExtensionCommand; /// A single element on the current page. #[derive(Clone, Debug, Serialize)] -pub struct Element { +pub struct Element { #[serde(skip_serializing)] - client: Client, + client: Client, #[serde(flatten)] element: webdriver::common::WebElement, } /// An HTML form on the current page. #[derive(Clone, Debug)] -pub struct Form { - client: Client, +pub struct Form { + client: Client, form: webdriver::common::WebElement, } -impl Client { +impl Client { /// Create a new `Client` associated with a new WebDriver session on the server at the given /// URL. /// @@ -671,7 +672,7 @@ impl Client { } /// Switches to the frame specified at the index. - pub async fn enter_frame(mut self, index: Option) -> Result { + pub async fn enter_frame(mut self, index: Option) -> Result, error::CmdError> { let params = SwitchToFrameParameters { id: index.map(FrameId::Short), }; @@ -680,18 +681,18 @@ impl Client { } /// Switches to the parent of the frame the client is currently contained within. - pub async fn enter_parent_frame(mut self) -> Result { + pub async fn enter_parent_frame(mut self) -> Result, error::CmdError> { self.issue(WebDriverCommand::SwitchToParentFrame).await?; Ok(self) } /// Find an element on the page. - pub async fn find(&mut self, search: Locator<'_>) -> Result { + pub async fn find(&mut self, search: Locator<'_>) -> Result, error::CmdError> { self.by(search.into()).await } /// Find elements on the page. - pub async fn find_all(&mut self, search: Locator<'_>) -> Result, error::CmdError> { + pub async fn find_all(&mut self, search: Locator<'_>) -> Result>, error::CmdError> { let res = self .issue(WebDriverCommand::FindElements(search.into())) .await?; @@ -713,7 +714,7 @@ impl Client { /// the page. pub async fn wait_for(&mut self, mut is_ready: F) -> Result<(), error::CmdError> where - F: FnMut(&mut Client) -> FF, + F: FnMut(&mut Client) -> FF, FF: Future>, { while !is_ready(self).await? {} @@ -726,7 +727,7 @@ impl Client { /// While this currently just spins and yields, it may be more efficient than this in the /// future. In particular, in time, it may only run `is_ready` again when an event occurs on /// the page. - pub async fn wait_for_find(&mut self, search: Locator<'_>) -> Result { + pub async fn wait_for_find(&mut self, search: Locator<'_>) -> Result, error::CmdError> { let s: webdriver::command::LocatorParameters = search.into(); loop { match self @@ -770,7 +771,7 @@ impl Client { /// Locate a form on the page. /// /// Through the returned `Form`, HTML forms can be filled out and submitted. - pub async fn form(&mut self, search: Locator<'_>) -> Result { + pub async fn form(&mut self, search: Locator<'_>) -> Result, error::CmdError> { let l = search.into(); let res = self.issue(WebDriverCommand::FindElement(l)).await?; let f = self.parse_lookup(res)?; @@ -864,12 +865,20 @@ impl Client { } } + /// Executes a browser specific extension command. + /// + /// You can install or uninstall browser extensions and control other browser + /// specific features with this method. + pub async fn extension_command(&mut self, command: T)->Result { + self.issue(WebDriverCommand::Extension(command)).await + } + // helpers async fn by( &mut self, locator: webdriver::command::LocatorParameters, - ) -> Result { + ) -> Result, error::CmdError> { let res = self.issue(WebDriverCommand::FindElement(locator)).await?; let e = self.parse_lookup(res)?; Ok(Element { @@ -943,7 +952,7 @@ impl Client { } } -impl Element { +impl Element { /// Look up an [attribute] value for this element by name. /// /// `Ok(None)` is returned if the element does not have the given attribute. @@ -999,7 +1008,7 @@ impl Element { } /// Find the first matching descendant element. - pub async fn find(&mut self, search: Locator<'_>) -> Result { + pub async fn find(&mut self, search: Locator<'_>) -> Result, error::CmdError> { let res = self .client .issue(WebDriverCommand::FindElementElement( @@ -1014,7 +1023,7 @@ impl Element { }) } /// Find all matching descendant elements. - pub async fn find_all(&mut self, search: Locator<'_>) -> Result, error::CmdError> { + pub async fn find_all(&mut self, search: Locator<'_>) -> Result>, error::CmdError> { let res = self .client .issue(WebDriverCommand::FindElementElements( @@ -1035,7 +1044,7 @@ impl Element { /// Simulate the user clicking on this element. /// /// Note that since this *may* result in navigation, we give up the handle to the element. - pub async fn click(mut self) -> Result { + pub async fn click(mut self) -> Result, error::CmdError> { let cmd = WebDriverCommand::ElementClick(self.element); let r = self.client.issue(cmd).await?; if r.is_null() || r.as_object().map(|o| o.is_empty()).unwrap_or(false) { @@ -1074,7 +1083,7 @@ impl Element { } /// Get back the [`Client`] hosting this `Element`. - pub fn client(self) -> Client { + pub fn client(self) -> Client { self.client } @@ -1082,7 +1091,7 @@ impl Element { /// click interaction. /// /// Note that since this *may* result in navigation, we give up the handle to the element. - pub async fn follow(mut self) -> Result { + pub async fn follow(mut self) -> Result, error::CmdError> { let cmd = WebDriverCommand::GetElementAttribute(self.element, "href".to_string()); let href = self.client.issue(cmd).await?; let href = match href { @@ -1104,7 +1113,7 @@ impl Element { } /// Find and click an `option` child element by its `value` attribute. - pub async fn select_by_value(mut self, value: &str) -> Result { + pub async fn select_by_value(mut self, value: &str) -> Result, error::CmdError> { let locator = format!("option[value='{}']", value); let locator = webdriver::command::LocatorParameters { using: webdriver::common::LocatorStrategy::CSSSelector, @@ -1122,7 +1131,7 @@ impl Element { } /// Switches to the frame contained within the element. - pub async fn enter_frame(self) -> Result { + pub async fn enter_frame(self) -> Result, error::CmdError> { let Self { mut client, element, @@ -1137,7 +1146,7 @@ impl Element { } } -impl Form { +impl Form { /// Find a form input using the given `locator` and set its value to `value`. pub async fn set( &mut self, @@ -1180,7 +1189,7 @@ impl Form { /// Submit this form using the first available submit button. /// /// `false` is returned if no submit button was not found. - pub async fn submit(self) -> Result { + pub async fn submit(self) -> Result, error::CmdError> { self.submit_with(Locator::Css("input[type=submit],button[type=submit]")) .await } @@ -1188,7 +1197,7 @@ impl Form { /// Submit this form using the button matched by the given selector. /// /// `false` is returned if a matching button was not found. - pub async fn submit_with(mut self, button: Locator<'_>) -> Result { + pub async fn submit_with(mut self, button: Locator<'_>) -> Result, error::CmdError> { let locator = WebDriverCommand::FindElementElement(self.form, button.into()); let res = self.client.issue(locator).await?; let submit = self.client.parse_lookup(res)?; @@ -1207,7 +1216,7 @@ impl Form { /// Submit this form using the form submit button with the given label (case-insensitive). /// /// `false` is returned if a matching button was not found. - pub async fn submit_using(self, button_label: &str) -> Result { + pub async fn submit_using(self, button_label: &str) -> Result, error::CmdError> { let escaped = button_label.replace('\\', "\\\\").replace('"', "\\\""); let btn = format!( "input[type=submit][value=\"{}\" i],\ @@ -1225,7 +1234,7 @@ impl Form { /// /// Note that since no button is actually clicked, the `name=value` pair for the submit button /// will not be submitted. This can be circumvented by using `submit_sneaky` instead. - pub async fn submit_direct(mut self) -> Result { + pub async fn submit_direct(mut self) -> Result, error::CmdError> { let mut args = vec![via_json!(&self.form)]; self.client.fixup_elements(&mut args); // some sites are silly, and name their submit button "submit". this ends up overwriting @@ -1260,7 +1269,7 @@ impl Form { mut self, field: &str, value: &str, - ) -> Result { + ) -> Result, error::CmdError> { let mut args = vec![via_json!(&self.form), Json::from(field), Json::from(value)]; self.client.fixup_elements(&mut args); let cmd = webdriver::command::JavascriptCommandParameters { @@ -1292,7 +1301,7 @@ impl Form { } /// Get back the [`Client`] hosting this `Form`. - pub fn client(self) -> Client { + pub fn client(self) -> Client { self.client } } diff --git a/src/session.rs b/src/session.rs index 257f992..d3db9ef 100644 --- a/src/session.rs +++ b/src/session.rs @@ -10,7 +10,7 @@ use std::pin::Pin; use std::task::Context; use std::task::Poll; use tokio::sync::{mpsc, oneshot}; -use webdriver::command::WebDriverCommand; +use webdriver::command::{WebDriverCommand, WebDriverExtensionCommand, VoidWebDriverExtensionCommand}; use webdriver::error::ErrorStatus; use webdriver::error::WebDriverError; @@ -18,16 +18,40 @@ type Ack = oneshot::Sender>; /// A WebDriver client tied to a single browser session. #[derive(Clone, Debug)] -pub struct Client { - tx: mpsc::UnboundedSender, +pub struct Client { + tx: mpsc::UnboundedSender>, is_legacy: bool, } -type Wcmd = WebDriverCommand; +/// Browser Specific extension commands +pub trait ExtensionCommand: WebDriverExtensionCommand { + /// Browser specific endpoint URL + /// + /// Example:- + /// Use `moz/addon/install` to install an addon on geckodriver + fn endpoint(&self) -> &str; + + /// Http method that using for calling to the endpoint + fn method(&self) -> http::Method; +} + +/// Extension command that does nothing. Use this type +/// when you don't want to use extension commands. +pub type VoidExtensionCommand = VoidWebDriverExtensionCommand; + +impl ExtensionCommand for VoidExtensionCommand { + fn endpoint(&self) -> &str { + panic!("No extensions implemented"); + } + + fn method(&self) -> http::Method { + panic!("No extensions implemented"); + } +} #[allow(clippy::large_enum_variant)] #[derive(Debug)] -pub(crate) enum Cmd { +pub(crate) enum Cmd { SetUA(String), GetSessionId, Shutdown, @@ -37,25 +61,25 @@ pub(crate) enum Cmd { req: hyper::Request, rsp: oneshot::Sender, hyper::Error>>, }, - WebDriver(Wcmd), + WebDriver(WebDriverCommand), } -impl From for Cmd { - fn from(o: Wcmd) -> Self { +impl From> for Cmd { + fn from(o: WebDriverCommand) -> Self { Cmd::WebDriver(o) } } #[derive(Debug)] -pub(crate) struct Task { - request: Cmd, +pub(crate) struct Task { + request: Cmd, ack: Ack, } -impl Client { +impl Client { pub(crate) fn issue(&mut self, cmd: C) -> impl Future> where - C: Into, + C: Into>, { let (tx, rx) = oneshot::channel(); let cmd = cmd.into(); @@ -178,9 +202,9 @@ impl Ongoing { } } -pub(crate) struct Session { +pub(crate) struct Session { ongoing: Ongoing, - rx: mpsc::UnboundedReceiver, + rx: mpsc::UnboundedReceiver>, client: hyper::Client, hyper::Body>, wdb: url::Url, session: Option, @@ -189,7 +213,7 @@ pub(crate) struct Session { persist: bool, } -impl Future for Session { +impl Future for Session { type Output = (); fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { @@ -269,7 +293,7 @@ impl Future for Session { } } -impl Session { +impl Session { fn shutdown(&mut self, ack: Option) { let url = { self.wdb @@ -329,7 +353,7 @@ impl Session { pub(crate) async fn with_capabilities( webdriver: &str, mut cap: webdriver::capabilities::Capabilities, - ) -> Result { + ) -> Result, error::NewSessionError> { // Where is the WebDriver server? let wdb = webdriver.parse::(); @@ -442,7 +466,7 @@ impl Session { /// Helper for determining what URL endpoint to use for various requests. /// /// This mapping is essentially that of https://www.w3.org/TR/webdriver/#list-of-endpoints. - fn endpoint_for(&self, cmd: &Wcmd) -> Result { + fn endpoint_for(&self, cmd: &WebDriverCommand) -> Result { if let WebDriverCommand::NewSession(..) = *cmd { return self.wdb.join("session"); } @@ -451,7 +475,7 @@ impl Session { self.wdb .join(&format!("session/{}/", self.session.as_ref().unwrap()))? }; - match *cmd { + match &*cmd { WebDriverCommand::NewSession(..) => unreachable!(), WebDriverCommand::DeleteSession => unreachable!(), WebDriverCommand::Get(..) | WebDriverCommand::GetCurrentUrl => base.join("url"), @@ -493,6 +517,11 @@ impl Session { WebDriverCommand::NewWindow(..) => base.join("window/new"), WebDriverCommand::SwitchToWindow(..) => base.join("window"), WebDriverCommand::CloseWindow => base.join("window"), + WebDriverCommand::Extension(extension_command) => { + let endpoint = extension_command.endpoint(); + let endpoint = endpoint.trim_start_matches("/"); + base.join(endpoint) + } _ => unimplemented!(), } } @@ -506,7 +535,7 @@ impl Session { /// [the spec]: https://www.w3.org/TR/webdriver/#list-of-endpoints fn issue_wd_cmd( &mut self, - cmd: WebDriverCommand, + cmd: WebDriverCommand, ) -> impl Future> { // TODO: make this an async fn // will take some doing as returned future must be independent of self @@ -523,7 +552,7 @@ impl Session { let mut body = None; // but some are special - match cmd { + match &cmd { WebDriverCommand::NewSession(command::NewSessionParameters::Spec(ref conf)) => { // TODO: awful hacks let mut also = String::new(); @@ -600,6 +629,12 @@ impl Session { WebDriverCommand::CloseWindow => { method = Method::DELETE; } + WebDriverCommand::Extension(ext_command) => { + method = ext_command.method(); + if let Some(param) = ext_command.parameters_json() { + body = Some(param.to_string()) + } + } _ => {} } diff --git a/tests/common.rs b/tests/common.rs index 3edcab3..4308469 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -3,20 +3,20 @@ extern crate fantoccini; extern crate futures_util; -use fantoccini::{error, Client}; +use fantoccini::{error, Client, VoidExtensionCommand}; use std::future::Future; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::path::PathBuf; use warp::Filter; -pub async fn select_client_type(s: &str) -> Result { +pub async fn select_client_type(s: &str) -> Result, error::NewSessionError> { match s { "firefox" => { let mut caps = serde_json::map::Map::new(); let opts = serde_json::json!({ "args": ["--headless"] }); caps.insert("moz:firefoxOptions".to_string(), opts.clone()); - Client::with_capabilities("http://localhost:4444", caps).await + Client::::with_capabilities("http://localhost:4444", caps).await } "chrome" => { let mut caps = serde_json::map::Map::new(); @@ -105,7 +105,7 @@ macro_rules! tester { macro_rules! local_tester { ($f:ident, $endpoint:expr) => {{ let port: u16 = common::setup_server(); - let f = move |c: Client| async move { $f(c, port).await }; + let f = move |c: Client| async move { $f(c, port).await }; tester!(f, $endpoint) }}; } diff --git a/tests/local.rs b/tests/local.rs index fc6f5c6..ae6d662 100644 --- a/tests/local.rs +++ b/tests/local.rs @@ -4,7 +4,7 @@ extern crate serial_test_derive; extern crate fantoccini; extern crate futures_util; -use fantoccini::{error, Client, Locator}; +use fantoccini::{error, Client, Locator, VoidExtensionCommand}; mod common; @@ -12,7 +12,7 @@ fn sample_page_url(port: u16) -> String { format!("http://localhost:{}/sample_page.html", port) } -async fn goto(mut c: Client, port: u16) -> Result<(), error::CmdError> { +async fn goto(mut c: Client, port: u16) -> Result<(), error::CmdError> { let url = sample_page_url(port); c.goto(&url).await?; let current_url = c.current_url().await?; @@ -20,7 +20,7 @@ async fn goto(mut c: Client, port: u16) -> Result<(), error::CmdError> { c.close().await } -async fn find_and_click_link(mut c: Client, port: u16) -> Result<(), error::CmdError> { +async fn find_and_click_link(mut c: Client, port: u16) -> Result<(), error::CmdError> { let url = sample_page_url(port); c.goto(&url).await?; c.find(Locator::Css("#other_page_id")) @@ -35,7 +35,7 @@ async fn find_and_click_link(mut c: Client, port: u16) -> Result<(), error::CmdE c.close().await } -async fn serialize_element(mut c: Client, port: u16) -> Result<(), error::CmdError> { +async fn serialize_element(mut c: Client, port: u16) -> Result<(), error::CmdError> { let url = sample_page_url(port); c.goto(&url).await?; let elem = c.find(Locator::Css("#other_page_id")).await?; @@ -59,7 +59,7 @@ async fn serialize_element(mut c: Client, port: u16) -> Result<(), error::CmdErr c.close().await } -async fn iframe_switch(mut c: Client, port: u16) -> Result<(), error::CmdError> { +async fn iframe_switch(mut c: Client, port: u16) -> Result<(), error::CmdError> { let url = sample_page_url(port); c.goto(&url).await?; // Go to the page that holds the iframe @@ -91,14 +91,14 @@ async fn iframe_switch(mut c: Client, port: u16) -> Result<(), error::CmdError> c.close().await } -async fn new_window(mut c: Client) -> Result<(), error::CmdError> { +async fn new_window(mut c: Client) -> Result<(), error::CmdError> { c.new_window(false).await?; let windows = c.windows().await?; assert_eq!(windows.len(), 2); c.close().await } -async fn new_window_switch(mut c: Client) -> Result<(), error::CmdError> { +async fn new_window_switch(mut c: Client) -> Result<(), error::CmdError> { let window_1 = c.window().await?; c.new_window(false).await?; let window_2 = c.window().await?; @@ -125,7 +125,7 @@ async fn new_window_switch(mut c: Client) -> Result<(), error::CmdError> { c.close().await } -async fn new_tab_switch(mut c: Client) -> Result<(), error::CmdError> { +async fn new_tab_switch(mut c: Client) -> Result<(), error::CmdError> { let window_1 = c.window().await?; c.new_window(true).await?; let window_2 = c.window().await?; @@ -152,7 +152,7 @@ async fn new_tab_switch(mut c: Client) -> Result<(), error::CmdError> { c.close().await } -async fn close_window(mut c: Client) -> Result<(), error::CmdError> { +async fn close_window(mut c: Client) -> Result<(), error::CmdError> { let window_1 = c.window().await?; c.new_window(true).await?; let window_2 = c.window().await?; @@ -182,7 +182,7 @@ async fn close_window(mut c: Client) -> Result<(), error::CmdError> { Ok(()) } -async fn close_window_twice_errors(mut c: Client) -> Result<(), error::CmdError> { +async fn close_window_twice_errors(mut c: Client) -> Result<(), error::CmdError> { c.close_window().await?; c.close_window() .await @@ -190,7 +190,7 @@ async fn close_window_twice_errors(mut c: Client) -> Result<(), error::CmdError> Ok(()) } -async fn stale_element(mut c: Client, port: u16) -> Result<(), error::CmdError> { +async fn stale_element(mut c: Client, port: u16) -> Result<(), error::CmdError> { let url = sample_page_url(port); c.goto(&url).await?; let elem = c.find(Locator::Css("#other_page_id")).await?; diff --git a/tests/remote.rs b/tests/remote.rs index 2ebf342..9eacafe 100644 --- a/tests/remote.rs +++ b/tests/remote.rs @@ -2,14 +2,14 @@ #[macro_use] extern crate serial_test_derive; -use fantoccini::{error, Client, Locator, Method}; +use fantoccini::{error, Client, Locator, Method, VoidExtensionCommand}; use futures_util::TryFutureExt; use std::time::Duration; use url::Url; mod common; -async fn works_inner(mut c: Client) -> Result<(), error::CmdError> { +async fn works_inner(mut c: Client) -> Result<(), error::CmdError> { // go to the Wikipedia page for Foobar c.goto("https://en.wikipedia.org/wiki/Foobar").await?; let mut e = c.find(Locator::Id("History_and_etymology")).await?; @@ -30,7 +30,7 @@ async fn works_inner(mut c: Client) -> Result<(), error::CmdError> { c.close().await } -async fn clicks_inner_by_locator(mut c: Client) -> Result<(), error::CmdError> { +async fn clicks_inner_by_locator(mut c: Client) -> Result<(), error::CmdError> { // go to the Wikipedia frontpage this time c.goto("https://www.wikipedia.org/").await?; @@ -48,7 +48,7 @@ async fn clicks_inner_by_locator(mut c: Client) -> Result<(), error::CmdError> { c.close().await } -async fn clicks_inner(mut c: Client) -> Result<(), error::CmdError> { +async fn clicks_inner(mut c: Client) -> Result<(), error::CmdError> { // go to the Wikipedia frontpage this time c.goto("https://www.wikipedia.org/").await?; @@ -64,7 +64,7 @@ async fn clicks_inner(mut c: Client) -> Result<(), error::CmdError> { c.close().await } -async fn send_keys_and_clear_input_inner(mut c: Client) -> Result<(), error::CmdError> { +async fn send_keys_and_clear_input_inner(mut c: Client) -> Result<(), error::CmdError> { // go to the Wikipedia frontpage this time c.goto("https://www.wikipedia.org/").await?; @@ -92,7 +92,7 @@ async fn send_keys_and_clear_input_inner(mut c: Client) -> Result<(), error::Cmd c.close().await } -async fn raw_inner(mut c: Client) -> Result<(), error::CmdError> { +async fn raw_inner(mut c: Client) -> Result<(), error::CmdError> { // go back to the frontpage c.goto("https://www.wikipedia.org/").await?; @@ -115,7 +115,7 @@ async fn raw_inner(mut c: Client) -> Result<(), error::CmdError> { c.close().await } -async fn window_size_inner(mut c: Client) -> Result<(), error::CmdError> { +async fn window_size_inner(mut c: Client) -> Result<(), error::CmdError> { c.goto("https://www.wikipedia.org/").await?; c.set_window_size(500, 400).await?; let (width, height) = c.get_window_size().await?; @@ -125,7 +125,7 @@ async fn window_size_inner(mut c: Client) -> Result<(), error::CmdError> { c.close().await } -async fn window_position_inner(mut c: Client) -> Result<(), error::CmdError> { +async fn window_position_inner(mut c: Client) -> Result<(), error::CmdError> { c.goto("https://www.wikipedia.org/").await?; c.set_window_size(200, 100).await?; c.set_window_position(0, 0).await?; @@ -137,7 +137,7 @@ async fn window_position_inner(mut c: Client) -> Result<(), error::CmdError> { c.close().await } -async fn window_rect_inner(mut c: Client) -> Result<(), error::CmdError> { +async fn window_rect_inner(mut c: Client) -> Result<(), error::CmdError> { c.goto("https://www.wikipedia.org/").await?; c.set_window_rect(0, 0, 500, 400).await?; let (x, y) = c.get_window_position().await?; @@ -157,7 +157,7 @@ async fn window_rect_inner(mut c: Client) -> Result<(), error::CmdError> { c.close().await } -async fn finds_all_inner(mut c: Client) -> Result<(), error::CmdError> { +async fn finds_all_inner(mut c: Client) -> Result<(), error::CmdError> { // go to the Wikipedia frontpage this time c.goto("https://en.wikipedia.org/").await?; let es = c.find_all(Locator::Css("#p-interaction li")).await?; @@ -180,7 +180,7 @@ async fn finds_all_inner(mut c: Client) -> Result<(), error::CmdError> { c.close().await } -async fn finds_sub_elements(mut c: Client) -> Result<(), error::CmdError> { +async fn finds_sub_elements(mut c: Client) -> Result<(), error::CmdError> { // Go to the Wikipedia front page c.goto("https://en.wikipedia.org/").await?; // Get the main sidebar panel @@ -214,14 +214,14 @@ async fn finds_sub_elements(mut c: Client) -> Result<(), error::CmdError> { c.close().await } -async fn persist_inner(mut c: Client) -> Result<(), error::CmdError> { +async fn persist_inner(mut c: Client) -> Result<(), error::CmdError> { c.goto("https://en.wikipedia.org/").await?; c.persist().await?; c.close().await } -async fn simple_wait_test(mut c: Client) -> Result<(), error::CmdError> { +async fn simple_wait_test(mut c: Client) -> Result<(), error::CmdError> { c.wait_for(move |_| { std::thread::sleep(Duration::from_secs(4)); async move { Ok(true) } @@ -231,7 +231,7 @@ async fn simple_wait_test(mut c: Client) -> Result<(), error::CmdError> { c.close().await } -async fn wait_for_navigation_test(mut c: Client) -> Result<(), error::CmdError> { +async fn wait_for_navigation_test(mut c: Client) -> Result<(), error::CmdError> { let mut path = std::env::current_dir().unwrap(); path.push("tests/redirect_test.html");