mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-11-04 05:59:48 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			603 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			603 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
use std::{collections::HashMap, env, io::Read, path::MAIN_SEPARATOR, time::Duration};
 | 
						|
 | 
						|
use async_trait::async_trait;
 | 
						|
use thirtyfour::{components::SelectElement, prelude::*, WebDriver};
 | 
						|
 | 
						|
use crate::connector_auth;
 | 
						|
 | 
						|
#[derive(Clone)]
 | 
						|
pub enum Event<'a> {
 | 
						|
    RunIf(Assert<'a>, Vec<Event<'a>>),
 | 
						|
    EitherOr(Assert<'a>, Vec<Event<'a>>, Vec<Event<'a>>),
 | 
						|
    Assert(Assert<'a>),
 | 
						|
    Trigger(Trigger<'a>),
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Clone)]
 | 
						|
#[allow(dead_code)]
 | 
						|
pub enum Trigger<'a> {
 | 
						|
    Goto(&'a str),
 | 
						|
    Click(By),
 | 
						|
    ClickNth(By, usize),
 | 
						|
    SelectOption(By, &'a str),
 | 
						|
    ChangeQueryParam(&'a str, &'a str),
 | 
						|
    SwitchTab(Position),
 | 
						|
    SwitchFrame(By),
 | 
						|
    Find(By),
 | 
						|
    Query(By),
 | 
						|
    SendKeys(By, &'a str),
 | 
						|
    Sleep(u64),
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Clone)]
 | 
						|
pub enum Position {
 | 
						|
    Prev,
 | 
						|
    Next,
 | 
						|
}
 | 
						|
#[derive(Clone)]
 | 
						|
pub enum Selector {
 | 
						|
    Title,
 | 
						|
    QueryParamStr,
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Clone)]
 | 
						|
pub enum Assert<'a> {
 | 
						|
    Eq(Selector, &'a str),
 | 
						|
    Contains(Selector, &'a str),
 | 
						|
    ContainsAny(Selector, Vec<&'a str>),
 | 
						|
    IsPresent(&'a str),
 | 
						|
    IsElePresent(By),
 | 
						|
    IsPresentNow(&'a str),
 | 
						|
}
 | 
						|
 | 
						|
pub static CHEKOUT_BASE_URL: &str = "https://hs-payments-test.netlify.app";
 | 
						|
#[async_trait]
 | 
						|
pub trait SeleniumTest {
 | 
						|
    fn get_saved_testcases(&self) -> serde_json::Value {
 | 
						|
        let env_value = env::var("CONNECTOR_TESTS_FILE_PATH").ok();
 | 
						|
        if env_value.is_none() {
 | 
						|
            return serde_json::json!("");
 | 
						|
        }
 | 
						|
        let path = env_value.unwrap();
 | 
						|
        let mut file = &std::fs::File::open(path).expect("Failed to open file");
 | 
						|
        let mut contents = String::new();
 | 
						|
        file.read_to_string(&mut contents)
 | 
						|
            .expect("Failed to read file");
 | 
						|
 | 
						|
        // Parse the JSON data
 | 
						|
        serde_json::from_str(&contents).expect("Failed to parse JSON")
 | 
						|
    }
 | 
						|
    fn get_configs(&self) -> connector_auth::ConnectorAuthentication {
 | 
						|
        let path = env::var("CONNECTOR_AUTH_FILE_PATH")
 | 
						|
            .expect("connector authentication file path not set");
 | 
						|
        toml::from_str(
 | 
						|
            &std::fs::read_to_string(path).expect("connector authentication config file not found"),
 | 
						|
        )
 | 
						|
        .expect("Failed to read connector authentication config file")
 | 
						|
    }
 | 
						|
    fn get_connector_name(&self) -> String;
 | 
						|
    async fn complete_actions(
 | 
						|
        &self,
 | 
						|
        driver: &WebDriver,
 | 
						|
        actions: Vec<Event<'_>>,
 | 
						|
    ) -> Result<(), WebDriverError> {
 | 
						|
        for action in actions {
 | 
						|
            match action {
 | 
						|
                Event::Assert(assert) => match assert {
 | 
						|
                    Assert::Contains(selector, text) => match selector {
 | 
						|
                        Selector::QueryParamStr => {
 | 
						|
                            let url = driver.current_url().await?;
 | 
						|
                            assert!(url.query().unwrap().contains(text))
 | 
						|
                        }
 | 
						|
                        _ => assert!(driver.title().await?.contains(text)),
 | 
						|
                    },
 | 
						|
                    Assert::ContainsAny(selector, search_keys) => match selector {
 | 
						|
                        Selector::QueryParamStr => {
 | 
						|
                            let url = driver.current_url().await?;
 | 
						|
                            assert!(search_keys
 | 
						|
                                .iter()
 | 
						|
                                .any(|key| url.query().unwrap().contains(key)))
 | 
						|
                        }
 | 
						|
                        _ => assert!(driver.title().await?.contains(search_keys.first().unwrap())),
 | 
						|
                    },
 | 
						|
                    Assert::Eq(_selector, text) => assert_eq!(driver.title().await?, text),
 | 
						|
                    Assert::IsPresent(text) => {
 | 
						|
                        assert!(is_text_present(driver, text).await?)
 | 
						|
                    }
 | 
						|
                    Assert::IsElePresent(selector) => {
 | 
						|
                        assert!(is_element_present(driver, selector).await?)
 | 
						|
                    }
 | 
						|
                    Assert::IsPresentNow(text) => {
 | 
						|
                        assert!(is_text_present_now(driver, text).await?)
 | 
						|
                    }
 | 
						|
                },
 | 
						|
                Event::RunIf(con_event, events) => match con_event {
 | 
						|
                    Assert::Contains(selector, text) => match selector {
 | 
						|
                        Selector::QueryParamStr => {
 | 
						|
                            let url = driver.current_url().await?;
 | 
						|
                            if url.query().unwrap().contains(text) {
 | 
						|
                                self.complete_actions(driver, events).await?;
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                        _ => assert!(driver.title().await?.contains(text)),
 | 
						|
                    },
 | 
						|
                    Assert::ContainsAny(selector, keys) => match selector {
 | 
						|
                        Selector::QueryParamStr => {
 | 
						|
                            let url = driver.current_url().await?;
 | 
						|
                            if keys.iter().any(|key| url.query().unwrap().contains(key)) {
 | 
						|
                                self.complete_actions(driver, events).await?;
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                        _ => assert!(driver.title().await?.contains(keys.first().unwrap())),
 | 
						|
                    },
 | 
						|
                    Assert::Eq(_selector, text) => {
 | 
						|
                        if text == driver.title().await? {
 | 
						|
                            self.complete_actions(driver, events).await?;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    Assert::IsPresent(text) => {
 | 
						|
                        if is_text_present(driver, text).await.is_ok() {
 | 
						|
                            self.complete_actions(driver, events).await?;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    Assert::IsElePresent(text) => {
 | 
						|
                        if is_element_present(driver, text).await.is_ok() {
 | 
						|
                            self.complete_actions(driver, events).await?;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    Assert::IsPresentNow(text) => {
 | 
						|
                        if is_text_present_now(driver, text).await.is_ok() {
 | 
						|
                            self.complete_actions(driver, events).await?;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                },
 | 
						|
                Event::EitherOr(con_event, success, failure) => match con_event {
 | 
						|
                    Assert::Contains(selector, text) => match selector {
 | 
						|
                        Selector::QueryParamStr => {
 | 
						|
                            let url = driver.current_url().await?;
 | 
						|
                            self.complete_actions(
 | 
						|
                                driver,
 | 
						|
                                if url.query().unwrap().contains(text) {
 | 
						|
                                    success
 | 
						|
                                } else {
 | 
						|
                                    failure
 | 
						|
                                },
 | 
						|
                            )
 | 
						|
                            .await?;
 | 
						|
                        }
 | 
						|
                        _ => assert!(driver.title().await?.contains(text)),
 | 
						|
                    },
 | 
						|
                    Assert::ContainsAny(selector, keys) => match selector {
 | 
						|
                        Selector::QueryParamStr => {
 | 
						|
                            let url = driver.current_url().await?;
 | 
						|
                            self.complete_actions(
 | 
						|
                                driver,
 | 
						|
                                if keys.iter().any(|key| url.query().unwrap().contains(key)) {
 | 
						|
                                    success
 | 
						|
                                } else {
 | 
						|
                                    failure
 | 
						|
                                },
 | 
						|
                            )
 | 
						|
                            .await?;
 | 
						|
                        }
 | 
						|
                        _ => assert!(driver.title().await?.contains(keys.first().unwrap())),
 | 
						|
                    },
 | 
						|
                    Assert::Eq(_selector, text) => {
 | 
						|
                        self.complete_actions(
 | 
						|
                            driver,
 | 
						|
                            if text == driver.title().await? {
 | 
						|
                                success
 | 
						|
                            } else {
 | 
						|
                                failure
 | 
						|
                            },
 | 
						|
                        )
 | 
						|
                        .await?;
 | 
						|
                    }
 | 
						|
                    Assert::IsPresent(text) => {
 | 
						|
                        self.complete_actions(
 | 
						|
                            driver,
 | 
						|
                            if is_text_present(driver, text).await.is_ok() {
 | 
						|
                                success
 | 
						|
                            } else {
 | 
						|
                                failure
 | 
						|
                            },
 | 
						|
                        )
 | 
						|
                        .await?;
 | 
						|
                    }
 | 
						|
                    Assert::IsElePresent(by) => {
 | 
						|
                        self.complete_actions(
 | 
						|
                            driver,
 | 
						|
                            if is_element_present(driver, by).await.is_ok() {
 | 
						|
                                success
 | 
						|
                            } else {
 | 
						|
                                failure
 | 
						|
                            },
 | 
						|
                        )
 | 
						|
                        .await?;
 | 
						|
                    }
 | 
						|
                    Assert::IsPresentNow(text) => {
 | 
						|
                        self.complete_actions(
 | 
						|
                            driver,
 | 
						|
                            if is_text_present_now(driver, text).await.is_ok() {
 | 
						|
                                success
 | 
						|
                            } else {
 | 
						|
                                failure
 | 
						|
                            },
 | 
						|
                        )
 | 
						|
                        .await?;
 | 
						|
                    }
 | 
						|
                },
 | 
						|
                Event::Trigger(trigger) => match trigger {
 | 
						|
                    Trigger::Goto(url) => {
 | 
						|
                        let saved_tests =
 | 
						|
                            serde_json::to_string(&self.get_saved_testcases()).unwrap();
 | 
						|
                        let conf = serde_json::to_string(&self.get_configs()).unwrap();
 | 
						|
                        let hs_base_url = self
 | 
						|
                            .get_configs()
 | 
						|
                            .automation_configs
 | 
						|
                            .unwrap()
 | 
						|
                            .hs_base_url
 | 
						|
                            .unwrap_or_else(|| "http://localhost:8080".to_string());
 | 
						|
                        let configs_url = self
 | 
						|
                            .get_configs()
 | 
						|
                            .automation_configs
 | 
						|
                            .unwrap()
 | 
						|
                            .configs_url
 | 
						|
                            .unwrap();
 | 
						|
                        let script = &[
 | 
						|
                            format!("localStorage.configs='{configs_url}'").as_str(),
 | 
						|
                            "localStorage.current_env='local'",
 | 
						|
                            "localStorage.hs_api_key=''",
 | 
						|
                            "localStorage.hs_api_keys=''",
 | 
						|
                            format!("localStorage.base_url='{hs_base_url}'").as_str(),
 | 
						|
                            format!("localStorage.hs_api_configs='{conf}'").as_str(),
 | 
						|
                            format!("localStorage.saved_payments=JSON.stringify({saved_tests})")
 | 
						|
                                .as_str(),
 | 
						|
                            "localStorage.force_sync='true'",
 | 
						|
                            format!(
 | 
						|
                                "localStorage.current_connector=\"{}\";",
 | 
						|
                                self.get_connector_name().clone()
 | 
						|
                            )
 | 
						|
                            .as_str(),
 | 
						|
                        ]
 | 
						|
                        .join(";");
 | 
						|
                        driver.goto(url).await?;
 | 
						|
                        driver.execute(script, Vec::new()).await?;
 | 
						|
                    }
 | 
						|
                    Trigger::Click(by) => {
 | 
						|
                        let ele = driver.query(by).first().await?;
 | 
						|
                        ele.wait_until().enabled().await?;
 | 
						|
                        ele.wait_until().displayed().await?;
 | 
						|
                        ele.wait_until().clickable().await?;
 | 
						|
                        ele.scroll_into_view().await?;
 | 
						|
                        ele.click().await?;
 | 
						|
                    }
 | 
						|
                    Trigger::ClickNth(by, n) => {
 | 
						|
                        let ele = driver.query(by).all().await?.into_iter().nth(n).unwrap();
 | 
						|
                        ele.wait_until().enabled().await?;
 | 
						|
                        ele.wait_until().displayed().await?;
 | 
						|
                        ele.wait_until().clickable().await?;
 | 
						|
                        ele.scroll_into_view().await?;
 | 
						|
                        ele.click().await?;
 | 
						|
                    }
 | 
						|
                    Trigger::Find(by) => {
 | 
						|
                        driver.find(by).await?;
 | 
						|
                    }
 | 
						|
                    Trigger::Query(by) => {
 | 
						|
                        driver.query(by).first().await?;
 | 
						|
                    }
 | 
						|
                    Trigger::SendKeys(by, input) => {
 | 
						|
                        let ele = driver.query(by).first().await?;
 | 
						|
                        ele.wait_until().displayed().await?;
 | 
						|
                        ele.send_keys(&input).await?;
 | 
						|
                    }
 | 
						|
                    Trigger::SelectOption(by, input) => {
 | 
						|
                        let ele = driver.query(by).first().await?;
 | 
						|
                        let select_element = SelectElement::new(&ele).await?;
 | 
						|
                        select_element.select_by_partial_text(input).await?;
 | 
						|
                    }
 | 
						|
                    Trigger::ChangeQueryParam(param, value) => {
 | 
						|
                        let mut url = driver.current_url().await?;
 | 
						|
                        let mut hash_query: HashMap<String, String> =
 | 
						|
                            url.query_pairs().into_owned().collect();
 | 
						|
                        hash_query.insert(param.to_string(), value.to_string());
 | 
						|
                        let url_str = serde_urlencoded::to_string(hash_query)
 | 
						|
                            .expect("Query Param update failed");
 | 
						|
                        url.set_query(Some(&url_str));
 | 
						|
                        driver.goto(url.as_str()).await?;
 | 
						|
                    }
 | 
						|
                    Trigger::Sleep(seconds) => {
 | 
						|
                        tokio::time::sleep(Duration::from_secs(seconds)).await;
 | 
						|
                    }
 | 
						|
                    Trigger::SwitchTab(position) => match position {
 | 
						|
                        Position::Next => {
 | 
						|
                            let windows = driver.windows().await?;
 | 
						|
                            if let Some(window) = windows.iter().rev().next() {
 | 
						|
                                driver.switch_to_window(window.to_owned()).await?;
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                        Position::Prev => {
 | 
						|
                            let windows = driver.windows().await?;
 | 
						|
                            if let Some(window) = windows.into_iter().next() {
 | 
						|
                                driver.switch_to_window(window.to_owned()).await?;
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    },
 | 
						|
                    Trigger::SwitchFrame(by) => {
 | 
						|
                        let iframe = driver.query(by).first().await?;
 | 
						|
                        iframe.wait_until().displayed().await?;
 | 
						|
                        iframe.clone().enter_frame().await?;
 | 
						|
                    }
 | 
						|
                },
 | 
						|
            }
 | 
						|
        }
 | 
						|
        Ok(())
 | 
						|
    }
 | 
						|
 | 
						|
    async fn make_redirection_payment(
 | 
						|
        &self,
 | 
						|
        c: WebDriver,
 | 
						|
        actions: Vec<Event<'_>>,
 | 
						|
    ) -> Result<(), WebDriverError> {
 | 
						|
        let config = self.get_configs().automation_configs.unwrap();
 | 
						|
        if config.run_minimum_steps.unwrap() {
 | 
						|
            self.complete_actions(&c, actions[..3].to_vec()).await
 | 
						|
        } else {
 | 
						|
            println!("Run all steps");
 | 
						|
            self.complete_actions(&c, actions).await
 | 
						|
        }
 | 
						|
    }
 | 
						|
    async fn make_gpay_payment(
 | 
						|
        &self,
 | 
						|
        c: WebDriver,
 | 
						|
        url: &str,
 | 
						|
        actions: Vec<Event<'_>>,
 | 
						|
    ) -> Result<(), WebDriverError> {
 | 
						|
        let config = self.get_configs().automation_configs.unwrap();
 | 
						|
        let (email, pass) = (&config.gmail_email.unwrap(), &config.gmail_pass.unwrap());
 | 
						|
        let default_actions = vec![
 | 
						|
            Event::Trigger(Trigger::Goto(url)),
 | 
						|
            Event::Trigger(Trigger::Click(By::Css(".gpay-button"))),
 | 
						|
            Event::Trigger(Trigger::SwitchTab(Position::Next)),
 | 
						|
            Event::Trigger(Trigger::Sleep(5)),
 | 
						|
            Event::RunIf(
 | 
						|
                Assert::IsPresentNow("Sign in"),
 | 
						|
                vec![
 | 
						|
                    Event::Trigger(Trigger::SendKeys(By::Id("identifierId"), email)),
 | 
						|
                    Event::Trigger(Trigger::ClickNth(By::Tag("button"), 2)),
 | 
						|
                    Event::EitherOr(
 | 
						|
                        Assert::IsPresent("Welcome"),
 | 
						|
                        vec![
 | 
						|
                            Event::Trigger(Trigger::SendKeys(By::Name("Passwd"), pass)),
 | 
						|
                            Event::Trigger(Trigger::Sleep(2)),
 | 
						|
                            Event::Trigger(Trigger::Click(By::Id("passwordNext"))),
 | 
						|
                            Event::Trigger(Trigger::Sleep(10)),
 | 
						|
                        ],
 | 
						|
                        vec![
 | 
						|
                            Event::Trigger(Trigger::SendKeys(By::Id("identifierId"), email)),
 | 
						|
                            Event::Trigger(Trigger::ClickNth(By::Tag("button"), 2)),
 | 
						|
                            Event::Trigger(Trigger::SendKeys(By::Name("Passwd"), pass)),
 | 
						|
                            Event::Trigger(Trigger::Sleep(2)),
 | 
						|
                            Event::Trigger(Trigger::Click(By::Id("passwordNext"))),
 | 
						|
                            Event::Trigger(Trigger::Sleep(10)),
 | 
						|
                        ],
 | 
						|
                    ),
 | 
						|
                ],
 | 
						|
            ),
 | 
						|
            Event::Trigger(Trigger::SwitchFrame(By::Id("sM432dIframe"))),
 | 
						|
            Event::Assert(Assert::IsPresent("Gpay Tester")),
 | 
						|
            Event::Trigger(Trigger::Click(By::ClassName("jfk-button-action"))),
 | 
						|
            Event::Trigger(Trigger::SwitchTab(Position::Prev)),
 | 
						|
        ];
 | 
						|
        self.complete_actions(&c, default_actions).await?;
 | 
						|
        self.complete_actions(&c, actions).await
 | 
						|
    }
 | 
						|
    async fn make_paypal_payment(
 | 
						|
        &self,
 | 
						|
        c: WebDriver,
 | 
						|
        url: &str,
 | 
						|
        actions: Vec<Event<'_>>,
 | 
						|
    ) -> Result<(), WebDriverError> {
 | 
						|
        self.complete_actions(
 | 
						|
            &c,
 | 
						|
            vec![
 | 
						|
                Event::Trigger(Trigger::Goto(url)),
 | 
						|
                Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
 | 
						|
            ],
 | 
						|
        )
 | 
						|
        .await?;
 | 
						|
        let (email, pass) = (
 | 
						|
            &self
 | 
						|
                .get_configs()
 | 
						|
                .automation_configs
 | 
						|
                .unwrap()
 | 
						|
                .pypl_email
 | 
						|
                .unwrap(),
 | 
						|
            &self
 | 
						|
                .get_configs()
 | 
						|
                .automation_configs
 | 
						|
                .unwrap()
 | 
						|
                .pypl_pass
 | 
						|
                .unwrap(),
 | 
						|
        );
 | 
						|
        let mut pypl_actions = vec![
 | 
						|
            Event::RunIf(
 | 
						|
                Assert::IsPresent("Enter your email address to get started."),
 | 
						|
                vec![
 | 
						|
                    Event::Trigger(Trigger::SendKeys(By::Id("email"), email)),
 | 
						|
                    Event::Trigger(Trigger::Click(By::Id("btnNext"))),
 | 
						|
                ],
 | 
						|
            ),
 | 
						|
            Event::EitherOr(
 | 
						|
                Assert::IsPresent("Password"),
 | 
						|
                vec![
 | 
						|
                    Event::Trigger(Trigger::SendKeys(By::Id("password"), pass)),
 | 
						|
                    Event::Trigger(Trigger::Click(By::Id("btnLogin"))),
 | 
						|
                ],
 | 
						|
                vec![
 | 
						|
                    Event::Trigger(Trigger::SendKeys(By::Id("email"), email)),
 | 
						|
                    Event::Trigger(Trigger::Click(By::Id("btnNext"))),
 | 
						|
                    Event::Trigger(Trigger::SendKeys(By::Id("password"), pass)),
 | 
						|
                    Event::Trigger(Trigger::Click(By::Id("btnLogin"))),
 | 
						|
                ],
 | 
						|
            ),
 | 
						|
            Event::Trigger(Trigger::Click(By::Id("payment-submit-btn"))),
 | 
						|
        ];
 | 
						|
        pypl_actions.extend(actions);
 | 
						|
        self.complete_actions(&c, pypl_actions).await
 | 
						|
    }
 | 
						|
}
 | 
						|
async fn is_text_present_now(driver: &WebDriver, key: &str) -> WebDriverResult<bool> {
 | 
						|
    let mut xpath = "//*[contains(text(),'".to_owned();
 | 
						|
    xpath.push_str(key);
 | 
						|
    xpath.push_str("')]");
 | 
						|
    let result = driver.find(By::XPath(&xpath)).await?;
 | 
						|
    result.is_present().await
 | 
						|
}
 | 
						|
async fn is_text_present(driver: &WebDriver, key: &str) -> WebDriverResult<bool> {
 | 
						|
    let mut xpath = "//*[contains(text(),'".to_owned();
 | 
						|
    xpath.push_str(key);
 | 
						|
    xpath.push_str("')]");
 | 
						|
    let result = driver.query(By::XPath(&xpath)).first().await?;
 | 
						|
    result.is_present().await
 | 
						|
}
 | 
						|
async fn is_element_present(driver: &WebDriver, by: By) -> WebDriverResult<bool> {
 | 
						|
    let element = driver.query(by).first().await?;
 | 
						|
    element.is_present().await
 | 
						|
}
 | 
						|
 | 
						|
#[macro_export]
 | 
						|
macro_rules! tester_inner {
 | 
						|
    ($execute:ident, $webdriver:expr) => {{
 | 
						|
        use std::{
 | 
						|
            sync::{Arc, Mutex},
 | 
						|
            thread,
 | 
						|
        };
 | 
						|
 | 
						|
        let driver = $webdriver;
 | 
						|
 | 
						|
        // we'll need the session_id from the thread
 | 
						|
        // NOTE: even if it panics, so can't just return it
 | 
						|
        let session_id = Arc::new(Mutex::new(None));
 | 
						|
 | 
						|
        // run test in its own thread to catch panics
 | 
						|
        let sid = session_id.clone();
 | 
						|
        let res = thread::spawn(move || {
 | 
						|
            let runtime = tokio::runtime::Builder::new_current_thread()
 | 
						|
                .enable_all()
 | 
						|
                .build()
 | 
						|
                .unwrap();
 | 
						|
            let driver = runtime
 | 
						|
                .block_on(driver)
 | 
						|
                .expect("failed to construct test WebDriver");
 | 
						|
            *sid.lock().unwrap() = runtime.block_on(driver.session_id()).ok();
 | 
						|
            // make sure we close, even if an assertion fails
 | 
						|
            let client = driver.clone();
 | 
						|
            let x = runtime.block_on(async move {
 | 
						|
                let r = tokio::spawn($execute(driver)).await;
 | 
						|
                let _ = client.quit().await;
 | 
						|
                r
 | 
						|
            });
 | 
						|
            drop(runtime);
 | 
						|
            x.expect("test panicked")
 | 
						|
        })
 | 
						|
        .join();
 | 
						|
        let success = handle_test_error(res);
 | 
						|
        assert!(success);
 | 
						|
    }};
 | 
						|
}
 | 
						|
 | 
						|
#[macro_export]
 | 
						|
macro_rules! tester {
 | 
						|
    ($f:ident) => {{
 | 
						|
        use $crate::tester_inner;
 | 
						|
        let browser = get_browser();
 | 
						|
        let url = make_url(&browser);
 | 
						|
        let caps = make_capabilities(&browser);
 | 
						|
        tester_inner!($f, WebDriver::new(url, caps));
 | 
						|
    }};
 | 
						|
}
 | 
						|
 | 
						|
pub fn get_browser() -> String {
 | 
						|
    "firefox".to_string()
 | 
						|
}
 | 
						|
 | 
						|
pub fn make_capabilities(s: &str) -> Capabilities {
 | 
						|
    match s {
 | 
						|
        "firefox" => {
 | 
						|
            let mut caps = DesiredCapabilities::firefox();
 | 
						|
            let ignore_profile = env::var("IGNORE_BROWSER_PROFILE").ok();
 | 
						|
            if ignore_profile.is_none() {
 | 
						|
                let profile_path = &format!("-profile={}", get_firefox_profile_path().unwrap());
 | 
						|
                caps.add_firefox_arg(profile_path).unwrap();
 | 
						|
            } else {
 | 
						|
                caps.add_firefox_arg("--headless").ok();
 | 
						|
            }
 | 
						|
            caps.into()
 | 
						|
        }
 | 
						|
        "chrome" => {
 | 
						|
            let mut caps = DesiredCapabilities::chrome();
 | 
						|
            let profile_path = &format!("user-data-dir={}", get_chrome_profile_path().unwrap());
 | 
						|
            caps.add_chrome_arg(profile_path).unwrap();
 | 
						|
            caps.into()
 | 
						|
        }
 | 
						|
        &_ => DesiredCapabilities::safari().into(),
 | 
						|
    }
 | 
						|
}
 | 
						|
fn get_chrome_profile_path() -> Result<String, WebDriverError> {
 | 
						|
    let exe = env::current_exe()?;
 | 
						|
    let dir = exe.parent().expect("Executable must be in some directory");
 | 
						|
    let mut base_path = dir
 | 
						|
        .to_str()
 | 
						|
        .map(|str| {
 | 
						|
            let mut fp = str.split(MAIN_SEPARATOR).collect::<Vec<_>>();
 | 
						|
            fp.truncate(3);
 | 
						|
            fp.join(&MAIN_SEPARATOR.to_string())
 | 
						|
        })
 | 
						|
        .unwrap();
 | 
						|
    base_path.push_str(r#"/Library/Application\ Support/Google/Chrome/Default"#); //Issue: 1573
 | 
						|
    Ok(base_path)
 | 
						|
}
 | 
						|
fn get_firefox_profile_path() -> Result<String, WebDriverError> {
 | 
						|
    let exe = env::current_exe()?;
 | 
						|
    let dir = exe.parent().expect("Executable must be in some directory");
 | 
						|
    let mut base_path = dir
 | 
						|
        .to_str()
 | 
						|
        .map(|str| {
 | 
						|
            let mut fp = str.split(MAIN_SEPARATOR).collect::<Vec<_>>();
 | 
						|
            fp.truncate(3);
 | 
						|
            fp.join(&MAIN_SEPARATOR.to_string())
 | 
						|
        })
 | 
						|
        .unwrap();
 | 
						|
    base_path.push_str(r#"/Library/Application Support/Firefox/Profiles/hs-test"#); //Issue: 1573
 | 
						|
    Ok(base_path)
 | 
						|
}
 | 
						|
 | 
						|
pub fn make_url(s: &str) -> &'static str {
 | 
						|
    match s {
 | 
						|
        "firefox" => "http://localhost:4444",
 | 
						|
        "chrome" => "http://localhost:9515",
 | 
						|
        &_ => "",
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
pub fn handle_test_error(
 | 
						|
    res: Result<Result<(), WebDriverError>, Box<dyn std::any::Any + Send>>,
 | 
						|
) -> bool {
 | 
						|
    match res {
 | 
						|
        Ok(Ok(_)) => true,
 | 
						|
        Ok(Err(e)) => {
 | 
						|
            eprintln!("test future failed to resolve: {:?}", e);
 | 
						|
            false
 | 
						|
        }
 | 
						|
        Err(e) => {
 | 
						|
            if let Some(e) = e.downcast_ref::<WebDriverError>() {
 | 
						|
                eprintln!("test future panicked: {:?}", e);
 | 
						|
            } else {
 | 
						|
                eprintln!("test future panicked; an assertion probably failed");
 | 
						|
            }
 | 
						|
            false
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |