1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/*! 

    Element enables most of the site interaction, and wraps user interactions such as typing text and clicking
    on things. Note that each element is tied to the specific session (currently, we
    can't hold on to the same element across sessions).


    # Example - Inspecting attributes of an element 

    ```rust 
        use selenium_rs::webdriver::{Selector, Browser, WebDriver};
        use selenium_rs::element::Element;

        let mut driver = WebDriver::new(Browser::Chrome);
        driver.start_session();
        driver.navigate("http://www.google.com");
        let search_form =  driver.query_element(Selector::CSS, "#searchform").unwrap();

        assert!(search_form.get_css_value("min-width").unwrap() == "980px");
    ```
*/

use element_structs::*;
use reqwest;
use utils::construct_url;

/// Element provides an interface from which to inspect and interact with the requested elements
/// on the page. The general flow involves navigating to your webpage in question, and then
/// requesting a specific element through the query API, and then using the returned element to
/// inspect the element on the page
#[derive(Debug)]
pub struct Element<'a> {
    element_id: String,
    session_id: String,
    client: &'a reqwest::Client,
}

impl<'a> Element<'a> {
    pub fn new(element_id: String, session_id: String, client: &'a reqwest::Client) -> Element<'a> {
        Element {
            element_id,
            session_id,
            client,
        }
    }
}

// Contains implementation for attribute interaction for the element
impl<'a> Element<'a> {
    pub fn is_selected(&self) -> reqwest::Result<bool> {
        let url = construct_url(vec![
            "session/",
            &(self.session_id.clone() + "/"),
            "element/",
            &(self.element_id.clone() + "/"),
            "selected",
        ]);
        let response: SelectedResponse = self.client.get(url).send()?.error_for_status()?.json()?;
        Ok(response.value)
    }

    /// gets an element attribute for the given element
    pub fn get_attribute(&self, attribute: &str) -> reqwest::Result<String> {
        let url = construct_url(vec![
            "session/",
            &(self.session_id.clone() + "/"),
            "element/",
            &(self.element_id.clone() + "/"),
            "attribute/",
            attribute,
        ]);
        let result: AttributeResponse = self.client.get(url).send()?.error_for_status()?.json()?;

        Ok(result.value)
    }

    /// retrieves the property value for the given element, if it exists
    pub fn get_property(&self, property: &str) -> reqwest::Result<String> {
        let url = construct_url(vec![
            "session/",
            &(self.session_id.clone() + "/"),
            "element/",
            &(self.element_id.clone() + "/"),
            "property/",
            property,
        ]);
        let result: AttributeResponse = self.client.get(url).send()?.error_for_status()?.json()?;

        Ok(result.value)
    }

    /// Gets a css property for the given element, if it exists
    pub fn get_css_value(&self, css_property: &str) -> reqwest::Result<String> {
        let url = construct_url(vec![
            "session/",
            &(self.session_id.clone() + "/"),
            "element/",
            &(self.element_id.clone() + "/"),
            "css/",
            css_property,
        ]);
        let result: AttributeResponse = self.client.get(url).send()?.error_for_status()?.json()?;

        Ok(result.value)
    }

    /// Gets the text for a given element, if it exists or makes sense
    pub fn get_text(&self) -> reqwest::Result<String> {
        let url = construct_url(vec![
            "session/",
            &(self.session_id.clone() + "/"),
            "element/",
            &(self.element_id.clone() + "/"),
            "text",
        ]);
        let result: AttributeResponse = self.client.get(url).send()?.error_for_status()?.json()?;

        Ok(result.value)
    }
}

// Implements Element Interactability

impl<'a> Element<'a> {
    pub fn click(&self) -> reqwest::Result<()> {
        let url = construct_url(vec![
            "session/",
            &(self.session_id.clone() + "/"),
            "element/",
            &(self.element_id.clone() + "/"),
            "click",
        ]);
        self.client.post(url).send()?.error_for_status()?;
        Ok(())
    }

    /// Clears a content editable element's text value, or returns an error
    pub fn clear(&self) -> reqwest::Result<()> {
        let url = construct_url(vec![
            "session/",
            &(self.session_id.clone() + "/"),
            "element/",
            &(self.element_id.clone() + "/"),
            "clear",
        ]);
        self.client.post(url).send()?.error_for_status()?;

        Ok(())
    }

    /// Tries to type into a content editable element
    pub fn type_text(&self, input: &str) -> reqwest::Result<()> {
        let url = construct_url(vec![
            "session/",
            &(self.session_id.clone() + "/"),
            "element/",
            &(self.element_id.clone() + "/"),
            "value",
        ]);

        println!("{:?}", url);

        let data = ValueRequest::new(input);
        self.client
            .post(url)
            .json(&data)
            .send()?
            .error_for_status()?;

        Ok(())
    }
}