1use crate::actions::ActionSequence;
6use crate::capabilities::{
7 BrowserCapabilities, Capabilities, CapabilitiesMatching, SpecNewSessionParameters,
8};
9use crate::common::{
10 Credentials, Date, FrameId, LocatorStrategy, ShadowRoot, WebElement, MAX_SAFE_INTEGER,
11};
12use crate::error::{ErrorStatus, WebDriverError, WebDriverResult};
13use crate::httpapi::{Route, VoidWebDriverExtensionRoute, WebDriverExtensionRoute};
14use crate::Parameters;
15use serde::de::{self, Deserialize, Deserializer};
16use serde_json::Value;
17
18#[derive(Debug, PartialEq)]
19pub enum WebDriverCommand<T: WebDriverExtensionCommand> {
20 NewSession(NewSessionParameters),
21 DeleteSession,
22 Get(GetParameters),
23 GetCurrentUrl,
24 GoBack,
25 GoForward,
26 Refresh,
27 GetTitle,
28 GetPageSource,
29 GetWindowHandle,
30 GetWindowHandles,
31 NewWindow(NewWindowParameters),
32 CloseWindow,
33 GetWindowRect,
34 SetWindowRect(WindowRectParameters),
35 MinimizeWindow,
36 MaximizeWindow,
37 FullscreenWindow,
38 SwitchToWindow(SwitchToWindowParameters),
39 SwitchToFrame(SwitchToFrameParameters),
40 SwitchToParentFrame,
41 FindElement(LocatorParameters),
42 FindElements(LocatorParameters),
43 FindElementElement(WebElement, LocatorParameters),
44 FindElementElements(WebElement, LocatorParameters),
45 FindShadowRootElement(ShadowRoot, LocatorParameters),
46 FindShadowRootElements(ShadowRoot, LocatorParameters),
47 GetActiveElement,
48 GetComputedLabel(WebElement),
49 GetComputedRole(WebElement),
50 GetShadowRoot(WebElement),
51 IsDisplayed(WebElement),
52 IsSelected(WebElement),
53 GetElementAttribute(WebElement, String),
54 GetElementProperty(WebElement, String),
55 GetCSSValue(WebElement, String),
56 GetElementText(WebElement),
57 GetElementTagName(WebElement),
58 GetElementRect(WebElement),
59 IsEnabled(WebElement),
60 ExecuteScript(JavascriptCommandParameters),
61 ExecuteAsyncScript(JavascriptCommandParameters),
62 GetCookies,
63 GetNamedCookie(String),
64 AddCookie(AddCookieParameters),
65 DeleteCookies,
66 DeleteCookie(String),
67 GetTimeouts,
68 SetTimeouts(TimeoutsParameters),
69 ElementClick(WebElement),
70 ElementClear(WebElement),
71 ElementSendKeys(WebElement, SendKeysParameters),
72 PerformActions(ActionsParameters),
73 ReleaseActions,
74 DismissAlert,
75 AcceptAlert,
76 GetAlertText,
77 SendAlertText(SendKeysParameters),
78 TakeScreenshot,
79 TakeElementScreenshot(WebElement),
80 Print(PrintParameters),
81 SetPermission(SetPermissionParameters),
82 Status,
83 Extension(T),
84 GPCSetGlobalPrivacyControl(GlobalPrivacyControlParameters),
85 GPCGetGlobalPrivacyControl,
86 WebAuthnAddCredential(String, Credentials),
87 WebAuthnAddVirtualAuthenticator(AuthenticatorParameters),
88 WebAuthnGetCredentials(String),
89 WebAuthnRemoveAllCredentials(String),
90 WebAuthnRemoveCredential(String, String),
91 WebAuthnRemoveVirtualAuthenticator(String),
92 WebAuthnSetUserVerified(String, UserVerificationParameters),
93}
94
95pub trait WebDriverExtensionCommand: Clone + Send {
96 fn parameters_json(&self) -> Option<Value>;
97}
98
99#[derive(Clone, Debug)]
100pub struct VoidWebDriverExtensionCommand;
101
102impl WebDriverExtensionCommand for VoidWebDriverExtensionCommand {
103 fn parameters_json(&self) -> Option<Value> {
104 panic!("No extensions implemented");
105 }
106}
107
108#[derive(Debug, PartialEq)]
109pub struct WebDriverMessage<U: WebDriverExtensionRoute = VoidWebDriverExtensionRoute> {
110 pub session_id: Option<String>,
111 pub command: WebDriverCommand<U::Command>,
112}
113
114impl<U: WebDriverExtensionRoute> WebDriverMessage<U> {
115 pub fn new(
116 session_id: Option<String>,
117 command: WebDriverCommand<U::Command>,
118 ) -> WebDriverMessage<U> {
119 WebDriverMessage {
120 session_id,
121 command,
122 }
123 }
124
125 pub fn from_http(
126 match_type: Route<U>,
127 params: &Parameters,
128 raw_body: &str,
129 requires_body: bool,
130 ) -> WebDriverResult<WebDriverMessage<U>> {
131 let session_id = WebDriverMessage::<U>::get_session_id(params);
132 let body_data = WebDriverMessage::<U>::decode_body(raw_body, requires_body)?;
133 let command = match match_type {
134 Route::NewSession => WebDriverCommand::NewSession(serde_json::from_str(raw_body)?),
135 Route::DeleteSession => WebDriverCommand::DeleteSession,
136 Route::Get => WebDriverCommand::Get(serde_json::from_str(raw_body)?),
137 Route::GetCurrentUrl => WebDriverCommand::GetCurrentUrl,
138 Route::GoBack => WebDriverCommand::GoBack,
139 Route::GoForward => WebDriverCommand::GoForward,
140 Route::Refresh => WebDriverCommand::Refresh,
141 Route::GetTitle => WebDriverCommand::GetTitle,
142 Route::GetPageSource => WebDriverCommand::GetPageSource,
143 Route::GetWindowHandle => WebDriverCommand::GetWindowHandle,
144 Route::GetWindowHandles => WebDriverCommand::GetWindowHandles,
145 Route::NewWindow => WebDriverCommand::NewWindow(serde_json::from_str(raw_body)?),
146 Route::CloseWindow => WebDriverCommand::CloseWindow,
147 Route::GetTimeouts => WebDriverCommand::GetTimeouts,
148 Route::SetTimeouts => WebDriverCommand::SetTimeouts(serde_json::from_str(raw_body)?),
149 Route::GetWindowRect | Route::GetWindowPosition | Route::GetWindowSize => {
150 WebDriverCommand::GetWindowRect
151 }
152 Route::SetWindowRect | Route::SetWindowPosition | Route::SetWindowSize => {
153 WebDriverCommand::SetWindowRect(serde_json::from_str(raw_body)?)
154 }
155 Route::MinimizeWindow => WebDriverCommand::MinimizeWindow,
156 Route::MaximizeWindow => WebDriverCommand::MaximizeWindow,
157 Route::FullscreenWindow => WebDriverCommand::FullscreenWindow,
158 Route::SwitchToWindow => {
159 WebDriverCommand::SwitchToWindow(serde_json::from_str(raw_body)?)
160 }
161 Route::SwitchToFrame => {
162 WebDriverCommand::SwitchToFrame(serde_json::from_str(raw_body)?)
163 }
164 Route::SwitchToParentFrame => WebDriverCommand::SwitchToParentFrame,
165 Route::FindElement => WebDriverCommand::FindElement(serde_json::from_str(raw_body)?),
166 Route::FindElements => WebDriverCommand::FindElements(serde_json::from_str(raw_body)?),
167 Route::FindElementElement => {
168 let element_id = try_opt!(
169 params.get("elementId"),
170 ErrorStatus::InvalidArgument,
171 "Missing elementId parameter"
172 );
173 let element = WebElement(element_id.as_str().into());
174 WebDriverCommand::FindElementElement(element, serde_json::from_str(raw_body)?)
175 }
176 Route::FindElementElements => {
177 let element_id = try_opt!(
178 params.get("elementId"),
179 ErrorStatus::InvalidArgument,
180 "Missing elementId parameter"
181 );
182 let element = WebElement(element_id.as_str().into());
183 WebDriverCommand::FindElementElements(element, serde_json::from_str(raw_body)?)
184 }
185 Route::FindShadowRootElement => {
186 let shadow_id = try_opt!(
187 params.get("shadowId"),
188 ErrorStatus::InvalidArgument,
189 "Missing shadowId parameter"
190 );
191 let shadow_root = ShadowRoot(shadow_id.as_str().into());
192 WebDriverCommand::FindShadowRootElement(
193 shadow_root,
194 serde_json::from_str(raw_body)?,
195 )
196 }
197 Route::FindShadowRootElements => {
198 let shadow_id = try_opt!(
199 params.get("shadowId"),
200 ErrorStatus::InvalidArgument,
201 "Missing shadowId parameter"
202 );
203 let shadow_root = ShadowRoot(shadow_id.as_str().into());
204 WebDriverCommand::FindShadowRootElements(
205 shadow_root,
206 serde_json::from_str(raw_body)?,
207 )
208 }
209 Route::GetActiveElement => WebDriverCommand::GetActiveElement,
210 Route::GetShadowRoot => {
211 let element_id = try_opt!(
212 params.get("elementId"),
213 ErrorStatus::InvalidArgument,
214 "Missing elementId parameter"
215 );
216 let element = WebElement(element_id.as_str().into());
217 WebDriverCommand::GetShadowRoot(element)
218 }
219 Route::GetComputedLabel => {
220 let element_id = try_opt!(
221 params.get("elementId"),
222 ErrorStatus::InvalidArgument,
223 "Missing elementId parameter"
224 );
225 let element = WebElement(element_id.as_str().into());
226 WebDriverCommand::GetComputedLabel(element)
227 }
228 Route::GetComputedRole => {
229 let element_id = try_opt!(
230 params.get("elementId"),
231 ErrorStatus::InvalidArgument,
232 "Missing elementId parameter"
233 );
234 let element = WebElement(element_id.as_str().into());
235 WebDriverCommand::GetComputedRole(element)
236 }
237 Route::IsDisplayed => {
238 let element_id = try_opt!(
239 params.get("elementId"),
240 ErrorStatus::InvalidArgument,
241 "Missing elementId parameter"
242 );
243 let element = WebElement(element_id.as_str().into());
244 WebDriverCommand::IsDisplayed(element)
245 }
246 Route::IsSelected => {
247 let element_id = try_opt!(
248 params.get("elementId"),
249 ErrorStatus::InvalidArgument,
250 "Missing elementId parameter"
251 );
252 let element = WebElement(element_id.as_str().into());
253 WebDriverCommand::IsSelected(element)
254 }
255 Route::GetElementAttribute => {
256 let element_id = try_opt!(
257 params.get("elementId"),
258 ErrorStatus::InvalidArgument,
259 "Missing elementId parameter"
260 );
261 let element = WebElement(element_id.as_str().into());
262 let attr = try_opt!(
263 params.get("name"),
264 ErrorStatus::InvalidArgument,
265 "Missing name parameter"
266 )
267 .as_str();
268 WebDriverCommand::GetElementAttribute(element, attr.into())
269 }
270 Route::GetElementProperty => {
271 let element_id = try_opt!(
272 params.get("elementId"),
273 ErrorStatus::InvalidArgument,
274 "Missing elementId parameter"
275 );
276 let element = WebElement(element_id.as_str().into());
277 let property = try_opt!(
278 params.get("name"),
279 ErrorStatus::InvalidArgument,
280 "Missing name parameter"
281 )
282 .as_str();
283 WebDriverCommand::GetElementProperty(element, property.into())
284 }
285 Route::GetCSSValue => {
286 let element_id = try_opt!(
287 params.get("elementId"),
288 ErrorStatus::InvalidArgument,
289 "Missing elementId parameter"
290 );
291 let element = WebElement(element_id.as_str().into());
292 let property = try_opt!(
293 params.get("propertyName"),
294 ErrorStatus::InvalidArgument,
295 "Missing propertyName parameter"
296 )
297 .as_str();
298 WebDriverCommand::GetCSSValue(element, property.into())
299 }
300 Route::GetElementText => {
301 let element_id = try_opt!(
302 params.get("elementId"),
303 ErrorStatus::InvalidArgument,
304 "Missing elementId parameter"
305 );
306 let element = WebElement(element_id.as_str().into());
307 WebDriverCommand::GetElementText(element)
308 }
309 Route::GetElementTagName => {
310 let element_id = try_opt!(
311 params.get("elementId"),
312 ErrorStatus::InvalidArgument,
313 "Missing elementId parameter"
314 );
315 let element = WebElement(element_id.as_str().into());
316 WebDriverCommand::GetElementTagName(element)
317 }
318 Route::GetElementRect => {
319 let element_id = try_opt!(
320 params.get("elementId"),
321 ErrorStatus::InvalidArgument,
322 "Missing elementId parameter"
323 );
324 let element = WebElement(element_id.as_str().into());
325 WebDriverCommand::GetElementRect(element)
326 }
327 Route::IsEnabled => {
328 let element_id = try_opt!(
329 params.get("elementId"),
330 ErrorStatus::InvalidArgument,
331 "Missing elementId parameter"
332 );
333 let element = WebElement(element_id.as_str().into());
334 WebDriverCommand::IsEnabled(element)
335 }
336 Route::ElementClick => {
337 let element_id = try_opt!(
338 params.get("elementId"),
339 ErrorStatus::InvalidArgument,
340 "Missing elementId parameter"
341 );
342 let element = WebElement(element_id.as_str().into());
343 WebDriverCommand::ElementClick(element)
344 }
345 Route::ElementClear => {
346 let element_id = try_opt!(
347 params.get("elementId"),
348 ErrorStatus::InvalidArgument,
349 "Missing elementId parameter"
350 );
351 let element = WebElement(element_id.as_str().into());
352 WebDriverCommand::ElementClear(element)
353 }
354 Route::ElementSendKeys => {
355 let element_id = try_opt!(
356 params.get("elementId"),
357 ErrorStatus::InvalidArgument,
358 "Missing elementId parameter"
359 );
360 let element = WebElement(element_id.as_str().into());
361 WebDriverCommand::ElementSendKeys(element, serde_json::from_str(raw_body)?)
362 }
363 Route::ExecuteScript => {
364 WebDriverCommand::ExecuteScript(serde_json::from_str(raw_body)?)
365 }
366 Route::ExecuteAsyncScript => {
367 WebDriverCommand::ExecuteAsyncScript(serde_json::from_str(raw_body)?)
368 }
369 Route::GetCookies => WebDriverCommand::GetCookies,
370 Route::GetNamedCookie => {
371 let name = try_opt!(
372 params.get("name"),
373 ErrorStatus::InvalidArgument,
374 "Missing 'name' parameter"
375 )
376 .as_str()
377 .into();
378 WebDriverCommand::GetNamedCookie(name)
379 }
380 Route::AddCookie => WebDriverCommand::AddCookie(serde_json::from_str(raw_body)?),
381 Route::DeleteCookies => WebDriverCommand::DeleteCookies,
382 Route::DeleteCookie => {
383 let name = try_opt!(
384 params.get("name"),
385 ErrorStatus::InvalidArgument,
386 "Missing name parameter"
387 )
388 .as_str()
389 .into();
390 WebDriverCommand::DeleteCookie(name)
391 }
392 Route::PerformActions => {
393 WebDriverCommand::PerformActions(serde_json::from_str(raw_body)?)
394 }
395 Route::ReleaseActions => WebDriverCommand::ReleaseActions,
396 Route::DismissAlert => WebDriverCommand::DismissAlert,
397 Route::AcceptAlert => WebDriverCommand::AcceptAlert,
398 Route::GetAlertText => WebDriverCommand::GetAlertText,
399 Route::SendAlertText => {
400 WebDriverCommand::SendAlertText(serde_json::from_str(raw_body)?)
401 }
402 Route::TakeScreenshot => WebDriverCommand::TakeScreenshot,
403 Route::TakeElementScreenshot => {
404 let element_id = try_opt!(
405 params.get("elementId"),
406 ErrorStatus::InvalidArgument,
407 "Missing elementId parameter"
408 );
409 let element = WebElement(element_id.as_str().into());
410 WebDriverCommand::TakeElementScreenshot(element)
411 }
412 Route::Print => WebDriverCommand::Print(serde_json::from_str(raw_body)?),
413 Route::SetPermission => {
414 WebDriverCommand::SetPermission(serde_json::from_str(raw_body)?)
415 }
416 Route::Status => WebDriverCommand::Status,
417 Route::Extension(ref extension) => extension.command(params, &body_data)?,
418 Route::GPCGetGlobalPrivacyControl => WebDriverCommand::GPCGetGlobalPrivacyControl,
419 Route::GPCSetGlobalPrivacyControl => {
420 WebDriverCommand::GPCSetGlobalPrivacyControl(serde_json::from_str(raw_body)?)
421 }
422 Route::WebAuthnAddCredential => {
423 let authenticator_id = try_opt!(
424 params.get("authenticatorId"),
425 ErrorStatus::InvalidArgument,
426 "Missing authenticator parameter"
427 );
428 WebDriverCommand::WebAuthnAddCredential(
429 authenticator_id.into(),
430 serde_json::from_str(raw_body)?,
431 )
432 }
433 Route::WebAuthnAddVirtualAuthenticator => {
434 WebDriverCommand::WebAuthnAddVirtualAuthenticator(serde_json::from_str(raw_body)?)
435 }
436 Route::WebAuthnGetCredentials => {
437 let authenticator_id = try_opt!(
438 params.get("authenticatorId"),
439 ErrorStatus::InvalidArgument,
440 "Missing authenticator parameter"
441 );
442 WebDriverCommand::WebAuthnGetCredentials(authenticator_id.into())
443 }
444 Route::WebAuthnRemoveAllCredentials => {
445 let authenticator_id = try_opt!(
446 params.get("authenticatorId"),
447 ErrorStatus::InvalidArgument,
448 "Missing authenticator parameter"
449 );
450 WebDriverCommand::WebAuthnRemoveAllCredentials(authenticator_id.into())
451 }
452 Route::WebAuthnRemoveCredential => {
453 let authenticator_id = try_opt!(
454 params.get("authenticatorId"),
455 ErrorStatus::InvalidArgument,
456 "Missing authenticator parameter"
457 );
458 let credential_id = try_opt!(
459 params.get("credentialId"),
460 ErrorStatus::InvalidArgument,
461 "Missing credential parameter"
462 );
463 WebDriverCommand::WebAuthnRemoveCredential(
464 authenticator_id.into(),
465 credential_id.into(),
466 )
467 }
468 Route::WebAuthnRemoveVirtualAuthenticator => {
469 let authenticator_id = try_opt!(
470 params.get("authenticatorId"),
471 ErrorStatus::InvalidArgument,
472 "Missing authenticator parameter"
473 );
474 WebDriverCommand::WebAuthnRemoveVirtualAuthenticator(authenticator_id.into())
475 }
476 Route::WebAuthnSetUserVerified => {
477 let authenticator_id = try_opt!(
478 params.get("authenticatorId"),
479 ErrorStatus::InvalidArgument,
480 "Missing authenticator parameter"
481 );
482 WebDriverCommand::WebAuthnSetUserVerified(
483 authenticator_id.into(),
484 serde_json::from_str(raw_body)?,
485 )
486 }
487 };
488 Ok(WebDriverMessage::new(session_id, command))
489 }
490
491 fn get_session_id(params: &Parameters) -> Option<String> {
492 params.get("sessionId").cloned()
493 }
494
495 fn decode_body(body: &str, requires_body: bool) -> WebDriverResult<Value> {
496 if requires_body {
497 match serde_json::from_str(body) {
498 Ok(x @ Value::Object(_)) => Ok(x),
499 Ok(_) => Err(WebDriverError::new(
500 ErrorStatus::InvalidArgument,
501 "Body was not a JSON Object",
502 )),
503 Err(e) => {
504 if e.is_io() {
505 Err(WebDriverError::new(
506 ErrorStatus::InvalidArgument,
507 format!("I/O error whilst decoding body: {}", e),
508 ))
509 } else {
510 let msg = format!("Failed to decode request as JSON: {}", body);
511 let stack = format!("Syntax error at :{}:{}", e.line(), e.column());
512 Err(WebDriverError::new_with_data(
513 ErrorStatus::InvalidArgument,
514 msg,
515 None,
516 Some(stack),
517 ))
518 }
519 }
520 }
521 } else {
522 Ok(Value::Null)
523 }
524 }
525}
526
527#[derive(Debug, PartialEq, Serialize, Deserialize)]
528pub struct ActionsParameters {
529 pub actions: Vec<ActionSequence>,
530}
531
532#[derive(Debug, PartialEq, Serialize, Deserialize)]
533#[serde(remote = "Self")]
534pub struct AddCookieParameters {
535 pub name: String,
536 pub value: String,
537 pub path: Option<String>,
538 pub domain: Option<String>,
539 #[serde(default)]
540 pub secure: bool,
541 #[serde(default)]
542 pub httpOnly: bool,
543 #[serde(skip_serializing_if = "Option::is_none")]
544 pub expiry: Option<Date>,
545 pub sameSite: Option<String>,
546}
547
548impl<'de> Deserialize<'de> for AddCookieParameters {
549 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
550 where
551 D: Deserializer<'de>,
552 {
553 #[derive(Deserialize)]
554 struct Wrapper {
555 #[serde(with = "AddCookieParameters")]
556 cookie: AddCookieParameters,
557 }
558
559 Wrapper::deserialize(deserializer).map(|wrapper| wrapper.cookie)
560 }
561}
562
563#[derive(Debug, PartialEq, Serialize, Deserialize)]
564pub struct GetParameters {
565 pub url: String,
566}
567
568#[derive(Debug, PartialEq, Serialize, Deserialize)]
569pub struct GetNamedCookieParameters {
570 pub name: Option<String>,
571}
572
573#[derive(Debug, PartialEq, Serialize, Deserialize)]
574pub struct JavascriptCommandParameters {
575 pub script: String,
576 pub args: Option<Vec<Value>>,
577}
578
579#[derive(Debug, PartialEq, Serialize, Deserialize)]
580pub struct LocatorParameters {
581 pub using: LocatorStrategy,
582 pub value: String,
583}
584
585#[derive(Debug, PartialEq, Serialize)]
586pub struct NewSessionParameters {
587 pub capabilities: SpecNewSessionParameters,
588}
589
590impl<'de> Deserialize<'de> for NewSessionParameters {
593 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
594 where
595 D: Deserializer<'de>,
596 {
597 let value = serde_json::Value::deserialize(deserializer)?;
598 let caps = value
599 .get("capabilities")
600 .ok_or(de::Error::missing_field("capabilities"))?;
601 if !caps.is_object() {
602 return Err(de::Error::custom("capabilities must be objects"));
603 }
604 let capabilities =
605 SpecNewSessionParameters::deserialize(caps).map_err(de::Error::custom)?;
606 Ok(NewSessionParameters { capabilities })
607 }
608}
609
610impl CapabilitiesMatching for NewSessionParameters {
611 fn match_browser<T: BrowserCapabilities>(
612 &self,
613 browser_capabilities: &mut T,
614 ) -> WebDriverResult<Option<Capabilities>> {
615 self.capabilities.match_browser(browser_capabilities)
616 }
617}
618
619#[derive(Debug, PartialEq, Serialize, Deserialize)]
620pub struct NewWindowParameters {
621 #[serde(rename = "type")]
622 pub type_hint: Option<String>,
623}
624
625#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
626#[serde(untagged)]
627pub enum PrintPageRange {
628 Integer(u64),
629 Range(String),
630}
631
632#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
633#[serde(default, rename_all = "camelCase")]
634pub struct PrintParameters {
635 pub orientation: PrintOrientation,
636 #[serde(deserialize_with = "deserialize_to_print_scale_f64")]
637 pub scale: f64,
638 pub background: bool,
639 pub page: PrintPage,
640 pub margin: PrintMargins,
641 pub page_ranges: Vec<PrintPageRange>,
642 pub shrink_to_fit: bool,
643}
644
645impl Default for PrintParameters {
646 fn default() -> Self {
647 PrintParameters {
648 orientation: PrintOrientation::default(),
649 scale: 1.0,
650 background: false,
651 page: PrintPage::default(),
652 margin: PrintMargins::default(),
653 page_ranges: Vec::new(),
654 shrink_to_fit: true,
655 }
656 }
657}
658
659#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
660#[serde(rename_all = "lowercase")]
661pub enum PrintOrientation {
662 Landscape,
663 #[default]
664 Portrait,
665}
666
667#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
668#[serde(default)]
669pub struct PrintPage {
670 #[serde(deserialize_with = "deserialize_to_positive_f64")]
671 pub width: f64,
672 #[serde(deserialize_with = "deserialize_to_positive_f64")]
673 pub height: f64,
674}
675
676impl Default for PrintPage {
677 fn default() -> Self {
678 PrintPage {
679 width: 21.59,
680 height: 27.94,
681 }
682 }
683}
684
685#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
686#[serde(default)]
687pub struct PrintMargins {
688 #[serde(deserialize_with = "deserialize_to_positive_f64")]
689 pub top: f64,
690 #[serde(deserialize_with = "deserialize_to_positive_f64")]
691 pub bottom: f64,
692 #[serde(deserialize_with = "deserialize_to_positive_f64")]
693 pub left: f64,
694 #[serde(deserialize_with = "deserialize_to_positive_f64")]
695 pub right: f64,
696}
697
698impl Default for PrintMargins {
699 fn default() -> Self {
700 PrintMargins {
701 top: 1.0,
702 bottom: 1.0,
703 left: 1.0,
704 right: 1.0,
705 }
706 }
707}
708
709#[derive(Debug, PartialEq, Serialize, Deserialize)]
710pub struct SetPermissionParameters {
711 pub descriptor: SetPermissionDescriptor,
712 pub state: SetPermissionState,
713}
714
715#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
716pub struct SetPermissionDescriptor {
717 pub name: String,
718}
719
720#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
721#[serde(rename_all = "lowercase")]
722pub enum SetPermissionState {
723 Denied,
724 Granted,
725 Prompt,
726}
727
728#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
729pub enum AuthenticatorProtocol {
730 #[serde(rename = "ctap1/u2f")]
731 Ctap1U2f,
732 #[serde(rename = "ctap2")]
733 Ctap2,
734 #[serde(rename = "ctap2_1")]
735 Ctap2_1,
736}
737
738#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
739#[serde(rename_all = "kebab-case")]
740pub enum AuthenticatorTransport {
741 Usb,
742 Nfc,
743 Ble,
744 SmartCard,
745 Hybrid,
746 Internal,
747}
748
749fn default_as_true() -> bool {
750 true
751}
752
753#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
754#[serde(rename_all = "camelCase")]
755pub struct AuthenticatorParameters {
756 pub protocol: AuthenticatorProtocol,
757 pub transport: AuthenticatorTransport,
758 #[serde(default)]
759 pub has_resident_key: bool,
760 #[serde(default)]
761 pub has_user_verification: bool,
762 #[serde(default = "default_as_true")]
763 pub is_user_consenting: bool,
764 #[serde(default)]
765 pub is_user_verified: bool,
766}
767
768#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
769#[serde(rename_all = "camelCase")]
770pub struct UserVerificationParameters {
771 pub is_user_verified: bool,
772}
773
774#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
775pub struct GlobalPrivacyControlParameters {
776 pub gpc: bool,
777}
778
779fn deserialize_to_positive_f64<'de, D>(deserializer: D) -> Result<f64, D::Error>
780where
781 D: Deserializer<'de>,
782{
783 let val = f64::deserialize(deserializer)?;
784 if val < 0.0 {
785 return Err(de::Error::custom(format!("{} is negative", val)));
786 };
787 Ok(val)
788}
789
790fn deserialize_to_print_scale_f64<'de, D>(deserializer: D) -> Result<f64, D::Error>
791where
792 D: Deserializer<'de>,
793{
794 let val = f64::deserialize(deserializer)?;
795 if !(0.1..=2.0).contains(&val) {
796 return Err(de::Error::custom(format!("{} is outside range 0.1-2", val)));
797 };
798 Ok(val)
799}
800
801#[derive(Debug, PartialEq, Serialize, Deserialize)]
802pub struct SendKeysParameters {
803 pub text: String,
804}
805
806#[derive(Debug, PartialEq, Serialize, Deserialize)]
807pub struct SwitchToFrameParameters {
808 pub id: FrameId,
809}
810
811#[derive(Debug, PartialEq, Serialize, Deserialize)]
812pub struct SwitchToWindowParameters {
813 pub handle: String,
814}
815
816#[derive(Debug, PartialEq, Serialize, Deserialize)]
817pub struct TakeScreenshotParameters {
818 pub element: Option<WebElement>,
819}
820
821#[derive(Debug, PartialEq, Serialize, Deserialize)]
822pub struct TimeoutsParameters {
823 #[serde(
824 default,
825 skip_serializing_if = "Option::is_none",
826 deserialize_with = "deserialize_to_nullable_u64"
827 )]
828 #[allow(clippy::option_option)]
829 pub implicit: Option<Option<u64>>,
830 #[serde(
831 default,
832 rename = "pageLoad",
833 skip_serializing_if = "Option::is_none",
834 deserialize_with = "deserialize_to_nullable_u64"
835 )]
836 #[allow(clippy::option_option)]
837 pub page_load: Option<Option<u64>>,
838 #[serde(
839 default,
840 skip_serializing_if = "Option::is_none",
841 deserialize_with = "deserialize_to_nullable_u64"
842 )]
843 #[allow(clippy::option_option)]
844 pub script: Option<Option<u64>>,
845}
846
847#[allow(clippy::option_option)]
848fn deserialize_to_nullable_u64<'de, D>(deserializer: D) -> Result<Option<Option<u64>>, D::Error>
849where
850 D: Deserializer<'de>,
851{
852 let opt: Option<f64> = Option::deserialize(deserializer)?;
853 let value = match opt {
854 Some(n) => {
855 if n < 0.0 || n.fract() != 0.0 {
856 return Err(de::Error::custom(format!(
857 "{} is not a positive Integer",
858 n
859 )));
860 }
861 if (n as u64) > MAX_SAFE_INTEGER {
862 return Err(de::Error::custom(format!(
863 "{} is greater than maximum safe integer",
864 n
865 )));
866 }
867 Some(Some(n as u64))
868 }
869 None => Some(None),
870 };
871
872 Ok(value)
873}
874
875#[derive(Debug, PartialEq, Serialize, Deserialize)]
886pub struct WindowRectParameters {
887 #[serde(
888 default,
889 skip_serializing_if = "Option::is_none",
890 deserialize_with = "deserialize_to_i32"
891 )]
892 pub x: Option<i32>,
893 #[serde(
894 default,
895 skip_serializing_if = "Option::is_none",
896 deserialize_with = "deserialize_to_i32"
897 )]
898 pub y: Option<i32>,
899 #[serde(
900 default,
901 skip_serializing_if = "Option::is_none",
902 deserialize_with = "deserialize_to_positive_i32"
903 )]
904 pub width: Option<i32>,
905 #[serde(
906 default,
907 skip_serializing_if = "Option::is_none",
908 deserialize_with = "deserialize_to_positive_i32"
909 )]
910 pub height: Option<i32>,
911}
912
913fn deserialize_to_i32<'de, D>(deserializer: D) -> Result<Option<i32>, D::Error>
914where
915 D: Deserializer<'de>,
916{
917 let opt = Option::deserialize(deserializer)?.map(|value: f64| value as i64);
918 let value = match opt {
919 Some(n) => {
920 if n < i64::from(i32::MIN) || n > i64::from(i32::MAX) {
921 return Err(de::Error::custom(format!("'{}' is larger than i32", n)));
922 }
923 Some(n as i32)
924 }
925 None => None,
926 };
927
928 Ok(value)
929}
930
931fn deserialize_to_positive_i32<'de, D>(deserializer: D) -> Result<Option<i32>, D::Error>
932where
933 D: Deserializer<'de>,
934{
935 let opt = Option::deserialize(deserializer)?.map(|value: f64| value as i64);
936 let value = match opt {
937 Some(n) => {
938 if n < 0 || n > i64::from(i32::MAX) {
939 return Err(de::Error::custom(format!("'{}' is outside of i32", n)));
940 }
941 Some(n as i32)
942 }
943 None => None,
944 };
945
946 Ok(value)
947}
948
949#[cfg(test)]
950mod tests {
951 use super::*;
952 use crate::capabilities::SpecNewSessionParameters;
953 use crate::common::ELEMENT_KEY;
954 use crate::test::assert_de;
955 use serde_json::{self, json};
956
957 #[test]
958 fn test_json_actions_parameters_missing_actions_field() {
959 assert!(serde_json::from_value::<ActionsParameters>(json!({})).is_err());
960 }
961
962 #[test]
963 fn test_json_actions_parameters_invalid() {
964 assert!(serde_json::from_value::<ActionsParameters>(json!({ "actions": null })).is_err());
965 }
966
967 #[test]
968 fn test_json_action_parameters_empty_list() {
969 assert_de(
970 &ActionsParameters { actions: vec![] },
971 json!({"actions": []}),
972 );
973 }
974
975 #[test]
976 fn test_json_action_parameters_with_unknown_field() {
977 assert_de(
978 &ActionsParameters { actions: vec![] },
979 json!({"actions": [], "foo": "bar"}),
980 );
981 }
982
983 #[test]
984 fn test_json_add_cookie_parameters_with_values() {
985 let json = json!({"cookie": {
986 "name": "foo",
987 "value": "bar",
988 "path": "/",
989 "domain": "foo.bar",
990 "expiry": 123,
991 "secure": true,
992 "httpOnly": false,
993 "sameSite": "Lax",
994 }});
995 let cookie = AddCookieParameters {
996 name: "foo".into(),
997 value: "bar".into(),
998 path: Some("/".into()),
999 domain: Some("foo.bar".into()),
1000 expiry: Some(Date(123)),
1001 secure: true,
1002 httpOnly: false,
1003 sameSite: Some("Lax".into()),
1004 };
1005
1006 assert_de(&cookie, json);
1007 }
1008
1009 #[test]
1010 fn test_json_add_cookie_parameters_with_optional_null_fields() {
1011 let json = json!({"cookie": {
1012 "name": "foo",
1013 "value": "bar",
1014 "path": null,
1015 "domain": null,
1016 "expiry": null,
1017 "secure": true,
1018 "httpOnly": false,
1019 "sameSite": null,
1020 }});
1021 let cookie = AddCookieParameters {
1022 name: "foo".into(),
1023 value: "bar".into(),
1024 path: None,
1025 domain: None,
1026 expiry: None,
1027 secure: true,
1028 httpOnly: false,
1029 sameSite: None,
1030 };
1031
1032 assert_de(&cookie, json);
1033 }
1034
1035 #[test]
1036 fn test_json_add_cookie_parameters_without_optional_fields() {
1037 let json = json!({"cookie": {
1038 "name": "foo",
1039 "value": "bar",
1040 "secure": true,
1041 "httpOnly": false,
1042 }});
1043 let cookie = AddCookieParameters {
1044 name: "foo".into(),
1045 value: "bar".into(),
1046 path: None,
1047 domain: None,
1048 expiry: None,
1049 secure: true,
1050 httpOnly: false,
1051 sameSite: None,
1052 };
1053
1054 assert_de(&cookie, json);
1055 }
1056
1057 #[test]
1058 fn test_json_add_cookie_parameters_with_invalid_cookie_field() {
1059 assert!(serde_json::from_value::<AddCookieParameters>(json!({"name": "foo"})).is_err());
1060 }
1061
1062 #[test]
1063 fn test_json_add_cookie_parameters_with_unknown_field() {
1064 let json = json!({"cookie": {
1065 "name": "foo",
1066 "value": "bar",
1067 "secure": true,
1068 "httpOnly": false,
1069 "foo": "bar",
1070 }, "baz": "bah"});
1071 let cookie = AddCookieParameters {
1072 name: "foo".into(),
1073 value: "bar".into(),
1074 path: None,
1075 domain: None,
1076 expiry: None,
1077 secure: true,
1078 httpOnly: false,
1079 sameSite: None,
1080 };
1081
1082 assert_de(&cookie, json);
1083 }
1084
1085 #[test]
1086 fn test_json_get_parameters_with_url() {
1087 assert_de(
1088 &GetParameters {
1089 url: "foo.bar".into(),
1090 },
1091 json!({"url": "foo.bar"}),
1092 );
1093 }
1094
1095 #[test]
1096 fn test_json_get_parameters_with_invalid_url_value() {
1097 assert!(serde_json::from_value::<GetParameters>(json!({"url": 3})).is_err());
1098 }
1099
1100 #[test]
1101 fn test_json_get_parameters_with_invalid_url_field() {
1102 assert!(serde_json::from_value::<GetParameters>(json!({"foo": "bar"})).is_err());
1103 }
1104
1105 #[test]
1106 fn test_json_get_parameters_with_unknown_field() {
1107 assert_de(
1108 &GetParameters {
1109 url: "foo.bar".into(),
1110 },
1111 json!({"url": "foo.bar", "foo": "bar"}),
1112 );
1113 }
1114
1115 #[test]
1116 fn test_json_get_named_cookie_parameters_with_value() {
1117 assert_de(
1118 &GetNamedCookieParameters {
1119 name: Some("foo".into()),
1120 },
1121 json!({"name": "foo"}),
1122 );
1123 }
1124
1125 #[test]
1126 fn test_json_get_named_cookie_parameters_with_optional_null_field() {
1127 assert_de(
1128 &GetNamedCookieParameters { name: None },
1129 json!({ "name": null }),
1130 );
1131 }
1132
1133 #[test]
1134 fn test_json_get_named_cookie_parameters_without_optional_null_field() {
1135 assert_de(&GetNamedCookieParameters { name: None }, json!({}));
1136 }
1137
1138 #[test]
1139 fn test_json_get_named_cookie_parameters_with_invalid_name_field() {
1140 assert!(serde_json::from_value::<GetNamedCookieParameters>(json!({"name": 3})).is_err());
1141 }
1142
1143 #[test]
1144 fn test_json_get_named_cookie_parameters_with_unknown_field() {
1145 assert_de(
1146 &GetNamedCookieParameters {
1147 name: Some("foo".into()),
1148 },
1149 json!({"name": "foo", "foo": "bar"}),
1150 );
1151 }
1152
1153 #[test]
1154 fn test_json_javascript_command_parameters_with_values() {
1155 let json = json!({
1156 "script": "foo",
1157 "args": ["1", 2],
1158 });
1159 let execute_script = JavascriptCommandParameters {
1160 script: "foo".into(),
1161 args: Some(vec!["1".into(), 2.into()]),
1162 };
1163
1164 assert_de(&execute_script, json);
1165 }
1166
1167 #[test]
1168 fn test_json_javascript_command_parameters_with_optional_null_field() {
1169 let json = json!({
1170 "script": "foo",
1171 "args": null,
1172 });
1173 let execute_script = JavascriptCommandParameters {
1174 script: "foo".into(),
1175 args: None,
1176 };
1177
1178 assert_de(&execute_script, json);
1179 }
1180
1181 #[test]
1182 fn test_json_javascript_command_parameters_without_optional_null_field() {
1183 let execute_script = JavascriptCommandParameters {
1184 script: "foo".into(),
1185 args: None,
1186 };
1187 assert_de(&execute_script, json!({"script": "foo"}));
1188 }
1189
1190 #[test]
1191 fn test_json_javascript_command_parameters_invalid_script_field() {
1192 let json = json!({ "script": null });
1193 assert!(serde_json::from_value::<JavascriptCommandParameters>(json).is_err());
1194 }
1195
1196 #[test]
1197 fn test_json_javascript_command_parameters_invalid_args_field() {
1198 let json = json!({
1199 "script": null,
1200 "args": "1",
1201 });
1202 assert!(serde_json::from_value::<JavascriptCommandParameters>(json).is_err());
1203 }
1204
1205 #[test]
1206 fn test_json_javascript_command_parameters_missing_script_field() {
1207 let json = json!({ "args": null });
1208 assert!(serde_json::from_value::<JavascriptCommandParameters>(json).is_err());
1209 }
1210
1211 #[test]
1212 fn test_json_javascript_command_parameters_with_unknown_field() {
1213 let json = json!({
1214 "script": "foo",
1215 "foo": "bar",
1216 });
1217 let execute_script = JavascriptCommandParameters {
1218 script: "foo".into(),
1219 args: None,
1220 };
1221
1222 assert_de(&execute_script, json);
1223 }
1224
1225 #[test]
1226 fn test_json_locator_parameters_with_values() {
1227 let json = json!({
1228 "using": "xpath",
1229 "value": "bar",
1230 });
1231 let locator = LocatorParameters {
1232 using: LocatorStrategy::XPath,
1233 value: "bar".into(),
1234 };
1235
1236 assert_de(&locator, json);
1237 }
1238
1239 #[test]
1240 fn test_json_locator_parameters_invalid_using_field() {
1241 let json = json!({
1242 "using": "foo",
1243 "value": "bar",
1244 });
1245 assert!(serde_json::from_value::<LocatorParameters>(json).is_err());
1246 }
1247
1248 #[test]
1249 fn test_json_locator_parameters_invalid_value_field() {
1250 let json = json!({
1251 "using": "xpath",
1252 "value": 3,
1253 });
1254 assert!(serde_json::from_value::<LocatorParameters>(json).is_err());
1255 }
1256
1257 #[test]
1258 fn test_json_locator_parameters_missing_using_field() {
1259 assert!(serde_json::from_value::<LocatorParameters>(json!({"value": "bar"})).is_err());
1260 }
1261
1262 #[test]
1263 fn test_json_locator_parameters_missing_value_field() {
1264 assert!(serde_json::from_value::<LocatorParameters>(json!({"using": "xpath"})).is_err());
1265 }
1266
1267 #[test]
1268 fn test_json_locator_parameters_with_unknown_field() {
1269 let json = json!({
1270 "using": "xpath",
1271 "value": "bar",
1272 "foo": "bar",
1273 });
1274 let locator = LocatorParameters {
1275 using: LocatorStrategy::XPath,
1276 value: "bar".into(),
1277 };
1278
1279 assert_de(&locator, json);
1280 }
1281
1282 #[test]
1283 fn test_json_new_session_parameters_spec() {
1284 let json = json!({"capabilities": {
1285 "alwaysMatch": {},
1286 "firstMatch": [{}],
1287 }});
1288 let caps = NewSessionParameters {
1289 capabilities: SpecNewSessionParameters {
1290 alwaysMatch: Capabilities::new(),
1291 firstMatch: vec![Capabilities::new()],
1292 },
1293 };
1294
1295 assert_de(&caps, json);
1296 }
1297
1298 #[test]
1299 fn test_json_new_session_parameters_capabilities_null() {
1300 let json = json!({ "capabilities": null });
1301 assert!(serde_json::from_value::<NewSessionParameters>(json).is_err());
1302 }
1303
1304 #[test]
1305 fn test_json_new_session_parameters_capabilities_empty_list() {
1306 let json = json!({ "capabilities": []});
1307 assert!(serde_json::from_value::<NewSessionParameters>(json).is_err());
1308 }
1309
1310 #[test]
1311 fn test_json_new_session_parameters_legacy() {
1312 let json = json!({
1313 "desiredCapabilities": {},
1314 "requiredCapabilities": {},
1315 });
1316 assert!(serde_json::from_value::<NewSessionParameters>(json).is_err());
1317 }
1318
1319 #[test]
1320 fn test_json_new_session_parameters_spec_and_legacy() {
1321 let json = json!({
1322 "capabilities": {
1323 "alwaysMatch": {},
1324 "firstMatch": [{}],
1325 },
1326 "desiredCapabilities": {},
1327 "requiredCapabilities": {},
1328 });
1329 let caps = NewSessionParameters {
1330 capabilities: SpecNewSessionParameters {
1331 alwaysMatch: Capabilities::new(),
1332 firstMatch: vec![Capabilities::new()],
1333 },
1334 };
1335
1336 assert_de(&caps, json);
1337 }
1338
1339 #[test]
1340 fn test_json_new_session_parameters_with_unknown_field() {
1341 let json = json!({
1342 "capabilities": {
1343 "alwaysMatch": {},
1344 "firstMatch": [{}]
1345 },
1346 "foo": "bar",
1347 });
1348 let caps = NewSessionParameters {
1349 capabilities: SpecNewSessionParameters {
1350 alwaysMatch: Capabilities::new(),
1351 firstMatch: vec![Capabilities::new()],
1352 },
1353 };
1354
1355 assert_de(&caps, json);
1356 }
1357
1358 #[test]
1359 fn test_json_new_window_parameters_without_type() {
1360 assert_de(&NewWindowParameters { type_hint: None }, json!({}));
1361 }
1362
1363 #[test]
1364 fn test_json_new_window_parameters_with_optional_null_type() {
1365 assert_de(
1366 &NewWindowParameters { type_hint: None },
1367 json!({ "type": null }),
1368 );
1369 }
1370
1371 #[test]
1372 fn test_json_new_window_parameters_with_supported_type() {
1373 assert_de(
1374 &NewWindowParameters {
1375 type_hint: Some("tab".into()),
1376 },
1377 json!({"type": "tab"}),
1378 );
1379 }
1380
1381 #[test]
1382 fn test_json_new_window_parameters_with_unknown_type() {
1383 assert_de(
1384 &NewWindowParameters {
1385 type_hint: Some("foo".into()),
1386 },
1387 json!({"type": "foo"}),
1388 );
1389 }
1390
1391 #[test]
1392 fn test_json_new_window_parameters_with_invalid_type() {
1393 assert!(serde_json::from_value::<NewWindowParameters>(json!({"type": 3})).is_err());
1394 }
1395
1396 #[test]
1397 fn test_json_new_window_parameters_with_unknown_field() {
1398 let json = json!({
1399 "type": "tab",
1400 "foo": "bar",
1401 });
1402 let new_window = NewWindowParameters {
1403 type_hint: Some("tab".into()),
1404 };
1405
1406 assert_de(&new_window, json);
1407 }
1408
1409 #[test]
1410 fn test_json_print_defaults() {
1411 let params = PrintParameters::default();
1412 assert_de(¶ms, json!({}));
1413 }
1414
1415 #[test]
1416 fn test_json_print() {
1417 let params = PrintParameters {
1418 orientation: PrintOrientation::Landscape,
1419 page: PrintPage {
1420 width: 10.0,
1421 ..Default::default()
1422 },
1423 margin: PrintMargins {
1424 top: 10.0,
1425 ..Default::default()
1426 },
1427 scale: 1.5,
1428 ..Default::default()
1429 };
1430 assert_de(
1431 ¶ms,
1432 json!({"orientation": "landscape", "page": {"width": 10}, "margin": {"top": 10}, "scale": 1.5}),
1433 );
1434 }
1435
1436 #[test]
1437 fn test_json_scale_invalid() {
1438 assert!(serde_json::from_value::<PrintParameters>(json!({"scale": 3})).is_err());
1439 }
1440
1441 #[test]
1442 fn test_json_permission() {
1443 let params: SetPermissionParameters = SetPermissionParameters {
1444 descriptor: SetPermissionDescriptor {
1445 name: "push".into(),
1446 },
1447 state: SetPermissionState::Granted,
1448 };
1449 assert_de(
1450 ¶ms,
1451 json!({"descriptor": {"name": "push"}, "state": "granted"}),
1452 );
1453 }
1454
1455 #[test]
1456 fn test_json_permission_parameters_invalid() {
1457 assert!(serde_json::from_value::<SetPermissionParameters>(json!({"test": 3})).is_err());
1458 }
1459
1460 #[test]
1461 fn test_json_permission_descriptor_invalid_type() {
1462 assert!(serde_json::from_value::<SetPermissionParameters>(
1463 json!({"descriptor": "test", "state": "granted"})
1464 )
1465 .is_err());
1466 }
1467
1468 #[test]
1469 fn test_json_permission_state_invalid_type() {
1470 assert!(serde_json::from_value::<SetPermissionParameters>(
1471 json!({"descriptor": {"name": "push"}, "state": 3})
1472 )
1473 .is_err());
1474 }
1475
1476 #[test]
1477 fn test_json_permission_state_invalid_value() {
1478 assert!(serde_json::from_value::<SetPermissionParameters>(
1479 json!({"descriptor": {"name": "push"}, "state": "invalid"})
1480 )
1481 .is_err());
1482 }
1483
1484 #[test]
1485 fn test_json_send_keys_parameters_with_value() {
1486 assert_de(
1487 &SendKeysParameters { text: "foo".into() },
1488 json!({"text": "foo"}),
1489 );
1490 }
1491
1492 #[test]
1493 fn test_json_send_keys_parameters_invalid_text_field() {
1494 assert!(serde_json::from_value::<SendKeysParameters>(json!({"text": 3})).is_err());
1495 }
1496
1497 #[test]
1498 fn test_json_send_keys_parameters_missing_text_field() {
1499 assert!(serde_json::from_value::<SendKeysParameters>(json!({})).is_err());
1500 }
1501
1502 #[test]
1503 fn test_json_send_keys_parameters_with_unknown_field() {
1504 let json = json!({
1505 "text": "foo",
1506 "foo": "bar",
1507 });
1508 let send_keys = SendKeysParameters { text: "foo".into() };
1509
1510 assert_de(&send_keys, json);
1511 }
1512
1513 #[test]
1514 fn test_json_switch_to_frame_parameters_with_number() {
1515 assert_de(
1516 &SwitchToFrameParameters {
1517 id: FrameId::Short(3),
1518 },
1519 json!({"id": 3}),
1520 );
1521 }
1522
1523 #[test]
1524 fn test_json_switch_to_frame_parameters_with_null() {
1525 assert_de(
1526 &SwitchToFrameParameters { id: FrameId::Top },
1527 json!({"id": null}),
1528 );
1529 }
1530
1531 #[test]
1532 fn test_json_switch_to_frame_parameters_with_web_element() {
1533 assert_de(
1534 &SwitchToFrameParameters {
1535 id: FrameId::Element(WebElement("foo".to_string())),
1536 },
1537 json!({"id": {"element-6066-11e4-a52e-4f735466cecf": "foo"}}),
1538 );
1539 }
1540
1541 #[test]
1542 fn test_json_switch_to_frame_parameters_with_missing_id() {
1543 assert!(serde_json::from_value::<SwitchToFrameParameters>(json!({})).is_err())
1544 }
1545
1546 #[test]
1547 fn test_json_switch_to_frame_parameters_with_invalid_id_field() {
1548 assert!(serde_json::from_value::<SwitchToFrameParameters>(json!({"id": "3"})).is_err());
1549 }
1550
1551 #[test]
1552 fn test_json_switch_to_frame_parameters_with_unknown_field() {
1553 let json = json!({
1554 "id":3,
1555 "foo": "bar",
1556 });
1557 let switch_to_frame = SwitchToFrameParameters {
1558 id: FrameId::Short(3),
1559 };
1560
1561 assert_de(&switch_to_frame, json);
1562 }
1563
1564 #[test]
1565 fn test_json_switch_to_window_parameters_with_value() {
1566 assert_de(
1567 &SwitchToWindowParameters {
1568 handle: "foo".into(),
1569 },
1570 json!({"handle": "foo"}),
1571 );
1572 }
1573
1574 #[test]
1575 fn test_json_switch_to_window_parameters_invalid_handle_field() {
1576 assert!(serde_json::from_value::<SwitchToWindowParameters>(json!({"handle": 3})).is_err());
1577 }
1578
1579 #[test]
1580 fn test_json_switch_to_window_parameters_missing_handle_field() {
1581 assert!(serde_json::from_value::<SwitchToWindowParameters>(json!({})).is_err());
1582 }
1583
1584 #[test]
1585 fn test_json_switch_to_window_parameters_with_unknown_field() {
1586 let json = json!({
1587 "handle": "foo",
1588 "foo": "bar",
1589 });
1590 let switch_to_window = SwitchToWindowParameters {
1591 handle: "foo".into(),
1592 };
1593
1594 assert_de(&switch_to_window, json);
1595 }
1596
1597 #[test]
1598 fn test_json_take_screenshot_parameters_with_element() {
1599 assert_de(
1600 &TakeScreenshotParameters {
1601 element: Some(WebElement("elem".into())),
1602 },
1603 json!({"element": {ELEMENT_KEY: "elem"}}),
1604 );
1605 }
1606
1607 #[test]
1608 fn test_json_take_screenshot_parameters_with_optional_null_field() {
1609 assert_de(
1610 &TakeScreenshotParameters { element: None },
1611 json!({ "element": null }),
1612 );
1613 }
1614
1615 #[test]
1616 fn test_json_take_screenshot_parameters_without_optional_null_field() {
1617 assert_de(&TakeScreenshotParameters { element: None }, json!({}));
1618 }
1619
1620 #[test]
1621 fn test_json_take_screenshot_parameters_with_invalid_element_field() {
1622 assert!(
1623 serde_json::from_value::<TakeScreenshotParameters>(json!({"element": "foo"})).is_err()
1624 );
1625 }
1626
1627 #[test]
1628 fn test_json_take_screenshot_parameters_with_unknown_field() {
1629 let json = json!({
1630 "element": {ELEMENT_KEY: "elem"},
1631 "foo": "bar",
1632 });
1633 let take_screenshot = TakeScreenshotParameters {
1634 element: Some(WebElement("elem".into())),
1635 };
1636
1637 assert_de(&take_screenshot, json);
1638 }
1639
1640 #[test]
1641 fn test_json_timeout_parameters_without_optional_null_field() {
1642 let timeouts = TimeoutsParameters {
1643 implicit: None,
1644 page_load: None,
1645 script: None,
1646 };
1647 assert_de(&timeouts, json!({}));
1648 }
1649
1650 #[test]
1651 fn test_json_timeout_parameters_with_only_null() {
1652 let json = json!({
1653 "implicit": null,
1654 "pageLoad": null,
1655 "script": null
1656 });
1657
1658 let timeouts = TimeoutsParameters {
1659 implicit: Some(None),
1660 page_load: Some(None),
1661 script: Some(None),
1662 };
1663 assert_de(&timeouts, json);
1664 }
1665
1666 #[test]
1667 fn test_json_timeout_parameters_with_values() {
1668 let json = json!({
1669 "implicit": Some(300),
1670 "pageLoad": Some(3000),
1671 "script": Some(30000)
1672 });
1673
1674 let timeouts = TimeoutsParameters {
1675 implicit: Some(300.into()),
1676 page_load: Some(3000.into()),
1677 script: Some(30000.into()),
1678 };
1679 assert_de(&timeouts, json);
1680 }
1681
1682 #[test]
1683 fn test_json_timeout_parameters_with_unknown_field() {
1684 let json = json!({
1685 "script": 60000,
1686 "foo": "bar",
1687 });
1688 let timeouts = TimeoutsParameters {
1689 implicit: None,
1690 page_load: None,
1691 script: Some(Some(60000)),
1692 };
1693
1694 assert_de(&timeouts, json);
1695 }
1696
1697 #[test]
1698 fn test_json_window_rect_parameters_with_values() {
1699 let json = json!({
1700 "x": 0,
1701 "y": 1,
1702 "width": 2,
1703 "height": 3,
1704 });
1705 let rect = WindowRectParameters {
1706 x: Some(0i32),
1707 y: Some(1i32),
1708 width: Some(2i32),
1709 height: Some(3i32),
1710 };
1711
1712 assert_de(&rect, json);
1713 }
1714
1715 #[test]
1716 fn test_json_window_rect_parameters_with_optional_null_fields() {
1717 let json = json!({
1718 "x": null,
1719 "y": null,
1720 "width": null,
1721 "height": null,
1722 });
1723 let rect = WindowRectParameters {
1724 x: None,
1725 y: None,
1726 width: None,
1727 height: None,
1728 };
1729
1730 assert_de(&rect, json);
1731 }
1732
1733 #[test]
1734 fn test_json_window_rect_parameters_without_optional_fields() {
1735 let rect = WindowRectParameters {
1736 x: None,
1737 y: None,
1738 width: None,
1739 height: None,
1740 };
1741 assert_de(&rect, json!({}));
1742 }
1743
1744 #[test]
1745 fn test_json_window_rect_parameters_invalid_values_float() {
1746 let json = json!({
1747 "x": 1.1,
1748 "y": 2.2,
1749 "width": 3.3,
1750 "height": 4.4,
1751 });
1752 let rect = WindowRectParameters {
1753 x: Some(1),
1754 y: Some(2),
1755 width: Some(3),
1756 height: Some(4),
1757 };
1758
1759 assert_de(&rect, json);
1760 }
1761
1762 #[test]
1763 fn test_json_window_rect_parameters_with_unknown_field() {
1764 let json = json!({
1765 "x": 1.1,
1766 "y": 2.2,
1767 "foo": "bar",
1768 });
1769 let rect = WindowRectParameters {
1770 x: Some(1),
1771 y: Some(2),
1772 width: None,
1773 height: None,
1774 };
1775
1776 assert_de(&rect, json);
1777 }
1778
1779 #[test]
1782 fn test_webauthn_json_authenticator() {
1783 let params = AuthenticatorParameters {
1784 protocol: AuthenticatorProtocol::Ctap1U2f,
1785 transport: AuthenticatorTransport::Usb,
1786 has_resident_key: false,
1787 has_user_verification: false,
1788 is_user_consenting: false,
1789 is_user_verified: false,
1790 };
1791 assert_de(
1792 ¶ms,
1793 json!({
1794 "hasResidentKey": false,
1795 "hasUserVerification": false,
1796 "isUserConsenting": false,
1797 "isUserVerified": false,
1798 "protocol": "ctap1/u2f",
1799 "transport": "usb",
1800 }),
1801 );
1802 }
1803
1804 #[test]
1805 fn test_webauthn_json_credential() {
1806 use base64::{engine::general_purpose::URL_SAFE, Engine};
1807
1808 let encoded_string = URL_SAFE.encode(b"hello internet~");
1809 let params = Credentials {
1810 credential_id: r"c3VwZXIgcmVhZGVy".to_string(),
1811 is_resident_credential: true,
1812 large_blob: None,
1813 rp_id: "valid.rpid".to_string(),
1814 private_key: encoded_string.clone(),
1815 user_handle: Some(encoded_string.clone()),
1816 sign_count: 0,
1817 };
1818 assert_de(
1819 ¶ms,
1820 json!({
1821 "credentialId": r"c3VwZXIgcmVhZGVy",
1822 "isResidentCredential": true,
1823 "privateKey": encoded_string,
1824 "rpId": "valid.rpid",
1825 "signCount": 0,
1826 "userHandle": encoded_string,
1827 }),
1828 );
1829 }
1830
1831 #[test]
1832 fn test_webauthn_json_user_verification() {
1833 let params = UserVerificationParameters {
1834 is_user_verified: false,
1835 };
1836 assert_de(
1837 ¶ms,
1838 json!({
1839 "isUserVerified": false
1840 }),
1841 );
1842 }
1843}