1#![allow(non_snake_case)]
4
5use ::util::merge_json_mut;
6use serde::{Serialize, Deserialize, Serializer, Deserializer};
7use serde::de::{Visitor, MapAccess};
8use serde::de::Error as DeError;
9use serde::ser::SerializeStruct;
10use serde_json::Value as JsonValue;
11use std::fmt;
12use std::collections::BTreeMap;
13
14#[derive(Debug)]
15pub enum LocationStrategy {
16 Css,
17 LinkText,
18 PartialLinkText,
19 XPath,
20}
21
22impl Serialize for LocationStrategy {
23 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
24 match self {
25 &LocationStrategy::Css => s.serialize_str("css selector"),
26 &LocationStrategy::LinkText => s.serialize_str("link text"),
27 &LocationStrategy::PartialLinkText => s.serialize_str("partial link text"),
28 &LocationStrategy::XPath => s.serialize_str("xpath"),
29 }
30 }
31}
32
33#[derive(Debug, Deserialize)]
34pub struct WebDriverError {
35 pub error: String,
36 pub message: String,
37 pub stacktrace: Option<String>,
38}
39
40#[derive(Serialize, Default)]
41struct Capabilities {
42 alwaysMatch: JsonValue,
43}
44
45#[derive(Serialize)]
50pub struct NewSessionCmd {
51 capabilities: Capabilities,
52}
53
54impl NewSessionCmd {
55 pub fn always_match(&mut self, key: &str, value: JsonValue) -> &mut Self {
61 merge_json_mut(&mut self.capabilities.alwaysMatch,
62 &json!({ key: value }));
63 self
64 }
65
66 pub fn reset_always_match(&mut self) -> &mut Self {
68 self.capabilities.alwaysMatch = json!({});
69 self
70 }
71}
72
73impl Default for NewSessionCmd {
74 fn default() -> Self {
75 NewSessionCmd {
76 capabilities: Capabilities {
77 alwaysMatch: json!({
78
79 "goog:chromeOptions": {
83 "w3c": true
84 }
85 })
86 },
87 }
88 }
89}
90
91#[derive(Debug, Deserialize)]
92pub struct Session {
93 pub sessionId: String,
94 pub capabilities: BTreeMap<String, JsonValue>,
95}
96
97#[derive(Serialize)]
98pub struct GoCmd {
99 pub url: String,
100}
101
102#[derive(Debug, Deserialize)]
103pub struct Value<T> {
104 pub value: T,
105}
106
107#[derive(Debug, Deserialize)]
108pub struct CurrentTitle {
109 pub title: String,
110}
111
112#[derive(Serialize)]
113pub struct SwitchFrameCmd {
114 pub id: JsonValue,
115}
116
117impl SwitchFrameCmd {
118 pub fn from(id: JsonValue) -> Self {
119 SwitchFrameCmd { id: id }
120 }
121}
122
123#[derive(Serialize)]
124pub struct SwitchWindowCmd {
125 handle: String,
126}
127
128impl SwitchWindowCmd {
129 pub fn from(handle: &str) -> Self {
130 SwitchWindowCmd { handle: handle.to_string() }
131 }
132}
133
134#[derive(Debug, Deserialize, Serialize)]
135pub struct Empty {}
136
137#[derive(Serialize)]
138pub struct FindElementCmd<'a> {
139 pub using: LocationStrategy,
140 pub value: &'a str,
141}
142
143#[derive(PartialEq, Debug)]
144pub struct ElementReference {
145 pub reference: String,
146}
147
148impl ElementReference {
149 pub fn from_str(handle: &str) -> ElementReference {
150 ElementReference { reference: handle.to_string() }
151 }
152}
153
154impl Serialize for ElementReference {
155 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
156 let mut ss = s.serialize_struct("ElementReference", 1)?;
157 ss.serialize_field("element-6066-11e4-a52e-4f735466cecf", &self.reference)?;
158 ss.serialize_field("ELEMENT", &self.reference)?;
160 ss.end()
161 }
162}
163
164impl<'de> Deserialize<'de> for ElementReference {
165 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
166 enum Field { Reference };
167
168 impl<'de> Deserialize<'de> for Field {
169 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
170 struct FieldVisitor;
171 impl<'de> Visitor<'de> for FieldVisitor {
172 type Value = Field;
173 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
174 formatter.write_str("element-6066-11e4-a52e-4f735466cecf")
175 }
176
177 fn visit_str<E: DeError>(self, value: &str) -> Result<Field, E>
178 {
179 match value {
180 "element-6066-11e4-a52e-4f735466cecf" => Ok(Field::Reference),
181 _ => Err(DeError::unknown_field(value, FIELDS)),
182 }
183 }
184 }
185
186 d.deserialize_identifier(FieldVisitor)
187 }
188 }
189
190 struct ElementReferenceVisitor;
191 impl<'de> Visitor<'de> for ElementReferenceVisitor {
192 type Value = ElementReference;
193
194 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
195 formatter.write_str("struct ElementReference")
196 }
197
198 fn visit_map<V>(self, mut visitor: V) -> Result<ElementReference, V::Error>
199 where V: MapAccess<'de>
200 {
201 let mut reference = None;
202 while let Some(key) = visitor.next_key()? {
203 match key {
204 Field::Reference => {
205 if reference.is_some() {
206 return Err(DeError::duplicate_field("element-6066-11e4-a52e-4f735466cecf"));
207 }
208 reference = Some(visitor.next_value()?);
209 }
210 }
211 }
212 match reference {
213 Some(r) => Ok(ElementReference { reference: r }),
214 None => return Err(DeError::missing_field("element-6066-11e4-a52e-4f735466cecf")),
215 }
216 }
217 }
218
219 const FIELDS: &'static [&'static str] = &["element-6066-11e4-a52e-4f735466cecf"];
220 d.deserialize_struct("ElementReference", FIELDS, ElementReferenceVisitor)
221 }
222}
223
224#[derive(Debug, Deserialize)]
225pub struct Cookie {
226 pub name: String,
227 pub value: String,
228 pub path: String,
229 pub domain: String,
230 pub secure: bool,
231 pub httpOnly: bool,
232 }
234
235#[derive(Serialize)]
236pub struct ExecuteCmd {
237 pub script: String,
238 pub args: Vec<JsonValue>,
239}
240
241#[derive(Serialize)]
242pub struct SendAlertTextCmd {
243 pub text: String,
244}
245
246#[cfg(test)]
247mod tests {
248 use super::NewSessionCmd;
249 #[test]
250 fn capability_extend() {
251 let mut session = NewSessionCmd::default();
252 session.always_match("cap", json!({"a": true}));
253 assert_eq!(session.capabilities.alwaysMatch.get("cap").unwrap(), &json!({"a": true}));
254
255 session.always_match("cap", json!({"b": false}));
256 assert_eq!(session.capabilities.alwaysMatch.get("cap").unwrap(), &json!({"a": true, "b": false}));
257
258 session.always_match("cap", json!({"a": false}));
259 assert_eq!(session.capabilities.alwaysMatch.get("cap").unwrap(), &json!({"a": false, "b": false}));
260 }
261 #[test]
262 fn capability_extend_replaces_non_obj() {
263 let mut session = NewSessionCmd::default();
264 session.always_match("cap", json!("value"));
265 assert_eq!(session.capabilities.alwaysMatch.get("cap").unwrap(), &json!("value"));
266
267 session.always_match("cap", json!({"a": false}));
268 assert_eq!(session.capabilities.alwaysMatch.get("cap").unwrap(), &json!({"a": false}));
269 }
270 #[test]
271 fn capability_extend_replaces_obj_with_non_obj() {
272 let mut session = NewSessionCmd::default();
273 session.always_match("cap", json!({"value": true}))
274 .always_match("cap", json!("new"));
275 assert_eq!(session.capabilities.alwaysMatch.get("cap").unwrap(), &json!("new"));
276 }
277}