use element::Element;
use element_structs::{ElementResponse, ElementsResponse, ExecuteScriptResponse};
use reqwest;
use session_structs::{NewSessionRequest, NewSessionResponse, TitleResponse};
use std::collections::HashMap;
use utils::*;
#[derive(Clone, Copy, Debug)]
pub enum Browser {
Chrome,
Firefox,
}
#[derive(Clone, Copy, Debug)]
pub enum Selector {
CSS,
LinkText,
PartialLinkText,
TagName,
XPath,
ID,
}
#[derive(Serialize, Deserialize)]
struct ElementRequest {
using: String,
value: String,
}
impl ElementRequest {
pub fn new(using: String, value: String) -> ElementRequest {
ElementRequest { using, value }
}
}
#[derive(Serialize)]
struct ExecuteScriptRequest {
script: String,
args: Vec<serde_json::Value>,
}
impl ExecuteScriptRequest {
pub fn new(script: String, args: Vec<serde_json::Value>) -> ExecuteScriptRequest {
ExecuteScriptRequest { script, args }
}
}
pub struct WebDriver {
browser: String,
client: reqwest::Client,
session_id: Option<String>,
}
impl WebDriver {
pub fn new(browser: Browser) -> WebDriver {
let browser = get_browser_string(browser);
WebDriver {
browser,
client: reqwest::Client::new(),
session_id: None,
}
}
}
impl WebDriver {
pub fn start_session(&mut self) -> reqwest::Result<()> {
let body = NewSessionRequest::new(&self.browser);
let url = construct_url(vec!["session/"]);
let response: NewSessionResponse = self.client
.post(url)
.json(&body)
.send()?
.error_for_status()?
.json()?;
self.session_id = Some(response.get_session_id());
Ok(())
}
pub fn get_current_url(&self) -> reqwest::Result<String> {
let url = construct_url(vec![
"session/",
&(self.session_id.clone().unwrap() + "/"),
"url",
]);
let response: TitleResponse = self.client.get(url).send()?.error_for_status()?.json()?;
Ok(response.get_title())
}
pub fn get_title(&self) -> reqwest::Result<String> {
let url = construct_url(vec![
"session/",
&(self.session_id.clone().unwrap() + "/"),
"title",
]);
let response: TitleResponse = self.client.get(url).send()?.error_for_status()?.json()?;
Ok(response.get_title())
}
}
impl WebDriver {
pub fn navigate(&self, url: &str) -> reqwest::Result<()> {
let sess_id = self.session_id.clone().unwrap();
let nav_url = construct_url(vec!["session/", &(sess_id + "/"), "url"]);
let mut payload = HashMap::new();
payload.insert("url", url);
self.client
.post(nav_url)
.json(&payload)
.send()?
.error_for_status()?;
Ok(())
}
pub fn forward(&self) -> reqwest::Result<()> {
let sess_id = self.session_id.clone().unwrap();
let nav_url = construct_url(vec!["session/", &(sess_id + "/"), "forward"]);
self.client.post(nav_url).send()?.error_for_status()?;
Ok(())
}
pub fn back(&self) -> reqwest::Result<()> {
let sess_id = self.session_id.clone().unwrap();
let nav_url = construct_url(vec!["session/", &(sess_id + "/"), "back"]);
self.client.post(nav_url).send()?.error_for_status()?;
Ok(())
}
}
impl WebDriver {
#[deprecated(since = "0.1.2", note = "query_element does not follow WebDriver naming convention, use find_element")]
pub fn query_element(&self, selector: Selector, query: &str) -> reqwest::Result<Element> {
self.find_element(selector, query)
}
pub fn find_element(&self, selector: Selector, query: &str) -> reqwest::Result<Element> {
let sess_id = self.session_id.clone().unwrap();
let url = construct_url(vec!["session/", &(sess_id + "/"), "element"]);
let payload = ElementRequest::new(str_for_selector(selector), query_string_for_selector(selector, query));
let response: ElementResponse = self.client
.post(url)
.json(&payload)
.send()?
.error_for_status()?
.json()?;
let element = response.parse_into_element(&self.client);
Ok(element)
}
#[deprecated(since = "0.1.2", note = "query_elements does not follow WebDriver naming convention, use find_elements")]
pub fn query_elements(&self, selector: Selector, query: &str) -> reqwest::Result<Vec<Element>> {
self.find_elements(selector, query)
}
pub fn find_elements(&self, selector: Selector, query: &str) -> reqwest::Result<Vec<Element>> {
let sess_id = self.session_id.clone().unwrap();
let url = construct_url(vec!["session/", &(sess_id + "/"), "elements"]);
let payload = ElementRequest::new(str_for_selector(selector), query.to_string());
let response: ElementsResponse = self.client
.post(url)
.json(&payload)
.send()?
.error_for_status()?
.json()?;
let elements = response.parse_into_elements(&self.client);
Ok(elements)
}
}
impl WebDriver {
pub fn execute_script<T: serde::de::DeserializeOwned>(&self, script: &str, args: &[serde_json::Value]) -> reqwest::Result<T> {
let sess_id = self.session_id.clone().unwrap();
let url = construct_url(vec!["session/", &(sess_id + "/"), "execute/sync"]);
let payload = ExecuteScriptRequest::new(script.to_string(), args.to_owned());
let response: ExecuteScriptResponse<T> = self.client
.post(url)
.json(&payload)
.send()?
.error_for_status()?
.json()?;
Ok(response.value)
}
}
impl Drop for WebDriver {
fn drop(&mut self) {
if let Some(ref id) = self.session_id {
let url = construct_url(vec!["session/", id]);
let _ = self.client.delete(url).send();
}
}
}