actions.rs (41985B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 use crate::common::{WebElement, ELEMENT_KEY}; 6 use icu_segmenter::GraphemeClusterSegmenter; 7 use serde::de::{self, Deserialize, Deserializer}; 8 use serde::ser::{Serialize, Serializer}; 9 use serde_json::Value; 10 use std::default::Default; 11 use std::f64; 12 13 #[derive(Debug, PartialEq, Serialize, Deserialize)] 14 pub struct ActionSequence { 15 pub id: String, 16 #[serde(flatten)] 17 pub actions: ActionsType, 18 } 19 20 #[derive(Debug, PartialEq, Serialize, Deserialize)] 21 #[serde(tag = "type")] 22 pub enum ActionsType { 23 #[serde(rename = "none")] 24 Null { actions: Vec<NullActionItem> }, 25 #[serde(rename = "key")] 26 Key { actions: Vec<KeyActionItem> }, 27 #[serde(rename = "pointer")] 28 Pointer { 29 #[serde(default)] 30 parameters: PointerActionParameters, 31 actions: Vec<PointerActionItem>, 32 }, 33 #[serde(rename = "wheel")] 34 Wheel { actions: Vec<WheelActionItem> }, 35 } 36 37 #[derive(Debug, PartialEq, Serialize, Deserialize)] 38 #[serde(untagged)] 39 pub enum NullActionItem { 40 General(GeneralAction), 41 } 42 43 #[derive(Debug, PartialEq, Serialize, Deserialize)] 44 #[serde(tag = "type")] 45 pub enum GeneralAction { 46 #[serde(rename = "pause")] 47 Pause(PauseAction), 48 } 49 50 #[derive(Debug, PartialEq, Serialize, Deserialize)] 51 pub struct PauseAction { 52 #[serde( 53 default, 54 skip_serializing_if = "Option::is_none", 55 deserialize_with = "deserialize_to_option_u64" 56 )] 57 pub duration: Option<u64>, 58 } 59 60 #[derive(Debug, PartialEq, Serialize, Deserialize)] 61 #[serde(untagged)] 62 pub enum KeyActionItem { 63 General(GeneralAction), 64 Key(KeyAction), 65 } 66 67 #[derive(Debug, PartialEq, Serialize, Deserialize)] 68 #[serde(tag = "type")] 69 pub enum KeyAction { 70 #[serde(rename = "keyDown")] 71 Down(KeyDownAction), 72 #[serde(rename = "keyUp")] 73 Up(KeyUpAction), 74 } 75 76 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] 77 pub struct KeyDownAction { 78 #[serde(deserialize_with = "deserialize_key_action_value")] 79 pub value: String, 80 } 81 82 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] 83 pub struct KeyUpAction { 84 #[serde(deserialize_with = "deserialize_key_action_value")] 85 pub value: String, 86 } 87 88 fn deserialize_key_action_value<'de, D>(deserializer: D) -> Result<String, D::Error> 89 where 90 D: Deserializer<'de>, 91 { 92 String::deserialize(deserializer).map(|value| { 93 // Only a single Unicode grapheme cluster is allowed 94 if GraphemeClusterSegmenter::new().segment_str(&value).count() != 2 { 95 return Err(de::Error::custom(format!( 96 "'{}' should only contain a single Unicode code point", 97 value 98 ))); 99 } 100 101 Ok(value) 102 })? 103 } 104 105 #[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)] 106 #[serde(rename_all = "lowercase")] 107 pub enum PointerType { 108 #[default] 109 Mouse, 110 Pen, 111 Touch, 112 } 113 114 #[derive(Debug, Default, PartialEq, Serialize, Deserialize)] 115 pub struct PointerActionParameters { 116 #[serde(rename = "pointerType")] 117 pub pointer_type: PointerType, 118 } 119 120 #[derive(Debug, PartialEq, Serialize, Deserialize)] 121 #[serde(untagged)] 122 pub enum PointerActionItem { 123 General(GeneralAction), 124 Pointer(PointerAction), 125 } 126 127 #[derive(Debug, PartialEq, Serialize, Deserialize)] 128 #[serde(tag = "type")] 129 pub enum PointerAction { 130 #[serde(rename = "pointerCancel")] 131 Cancel, 132 #[serde(rename = "pointerDown")] 133 Down(PointerDownAction), 134 #[serde(rename = "pointerMove")] 135 Move(PointerMoveAction), 136 #[serde(rename = "pointerUp")] 137 Up(PointerUpAction), 138 } 139 140 #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] 141 pub struct PointerDownAction { 142 pub button: u64, 143 #[serde( 144 default, 145 skip_serializing_if = "Option::is_none", 146 deserialize_with = "deserialize_to_option_u64" 147 )] 148 pub width: Option<u64>, 149 #[serde( 150 default, 151 skip_serializing_if = "Option::is_none", 152 deserialize_with = "deserialize_to_option_u64" 153 )] 154 pub height: Option<u64>, 155 #[serde( 156 default, 157 skip_serializing_if = "Option::is_none", 158 deserialize_with = "deserialize_to_pressure" 159 )] 160 pub pressure: Option<f64>, 161 #[serde( 162 default, 163 skip_serializing_if = "Option::is_none", 164 deserialize_with = "deserialize_to_tangential_pressure" 165 )] 166 pub tangentialPressure: Option<f64>, 167 #[serde( 168 default, 169 skip_serializing_if = "Option::is_none", 170 deserialize_with = "deserialize_to_tilt" 171 )] 172 pub tiltX: Option<i64>, 173 #[serde( 174 default, 175 skip_serializing_if = "Option::is_none", 176 deserialize_with = "deserialize_to_tilt" 177 )] 178 pub tiltY: Option<i64>, 179 #[serde( 180 default, 181 skip_serializing_if = "Option::is_none", 182 deserialize_with = "deserialize_to_twist" 183 )] 184 pub twist: Option<u64>, 185 #[serde( 186 default, 187 skip_serializing_if = "Option::is_none", 188 deserialize_with = "deserialize_to_altitude_angle" 189 )] 190 pub altitudeAngle: Option<f64>, 191 #[serde( 192 default, 193 skip_serializing_if = "Option::is_none", 194 deserialize_with = "deserialize_to_azimuth_angle" 195 )] 196 pub azimuthAngle: Option<f64>, 197 } 198 199 #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] 200 pub struct PointerMoveAction { 201 #[serde( 202 default, 203 skip_serializing_if = "Option::is_none", 204 deserialize_with = "deserialize_to_option_u64" 205 )] 206 pub duration: Option<u64>, 207 #[serde(default)] 208 pub origin: PointerOrigin, 209 pub x: f64, 210 pub y: f64, 211 #[serde( 212 default, 213 skip_serializing_if = "Option::is_none", 214 deserialize_with = "deserialize_to_option_u64" 215 )] 216 pub width: Option<u64>, 217 #[serde( 218 default, 219 skip_serializing_if = "Option::is_none", 220 deserialize_with = "deserialize_to_option_u64" 221 )] 222 pub height: Option<u64>, 223 #[serde( 224 default, 225 skip_serializing_if = "Option::is_none", 226 deserialize_with = "deserialize_to_pressure" 227 )] 228 pub pressure: Option<f64>, 229 #[serde( 230 default, 231 skip_serializing_if = "Option::is_none", 232 deserialize_with = "deserialize_to_tangential_pressure" 233 )] 234 pub tangentialPressure: Option<f64>, 235 #[serde( 236 default, 237 skip_serializing_if = "Option::is_none", 238 deserialize_with = "deserialize_to_tilt" 239 )] 240 pub tiltX: Option<i64>, 241 #[serde( 242 default, 243 skip_serializing_if = "Option::is_none", 244 deserialize_with = "deserialize_to_tilt" 245 )] 246 pub tiltY: Option<i64>, 247 #[serde( 248 default, 249 skip_serializing_if = "Option::is_none", 250 deserialize_with = "deserialize_to_twist" 251 )] 252 pub twist: Option<u64>, 253 #[serde( 254 default, 255 skip_serializing_if = "Option::is_none", 256 deserialize_with = "deserialize_to_altitude_angle" 257 )] 258 pub altitudeAngle: Option<f64>, 259 #[serde( 260 default, 261 skip_serializing_if = "Option::is_none", 262 deserialize_with = "deserialize_to_azimuth_angle" 263 )] 264 pub azimuthAngle: Option<f64>, 265 } 266 267 #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] 268 pub struct PointerUpAction { 269 pub button: u64, 270 #[serde( 271 default, 272 skip_serializing_if = "Option::is_none", 273 deserialize_with = "deserialize_to_option_u64" 274 )] 275 pub width: Option<u64>, 276 #[serde( 277 default, 278 skip_serializing_if = "Option::is_none", 279 deserialize_with = "deserialize_to_option_u64" 280 )] 281 pub height: Option<u64>, 282 #[serde( 283 default, 284 skip_serializing_if = "Option::is_none", 285 deserialize_with = "deserialize_to_pressure" 286 )] 287 pub pressure: Option<f64>, 288 #[serde( 289 default, 290 skip_serializing_if = "Option::is_none", 291 deserialize_with = "deserialize_to_tangential_pressure" 292 )] 293 pub tangentialPressure: Option<f64>, 294 #[serde( 295 default, 296 skip_serializing_if = "Option::is_none", 297 deserialize_with = "deserialize_to_tilt" 298 )] 299 pub tiltX: Option<i64>, 300 #[serde( 301 default, 302 skip_serializing_if = "Option::is_none", 303 deserialize_with = "deserialize_to_tilt" 304 )] 305 pub tiltY: Option<i64>, 306 #[serde( 307 default, 308 skip_serializing_if = "Option::is_none", 309 deserialize_with = "deserialize_to_twist" 310 )] 311 pub twist: Option<u64>, 312 #[serde( 313 default, 314 skip_serializing_if = "Option::is_none", 315 deserialize_with = "deserialize_to_altitude_angle" 316 )] 317 pub altitudeAngle: Option<f64>, 318 #[serde( 319 default, 320 skip_serializing_if = "Option::is_none", 321 deserialize_with = "deserialize_to_azimuth_angle" 322 )] 323 pub azimuthAngle: Option<f64>, 324 } 325 326 #[derive(Clone, Debug, Default, PartialEq, Serialize)] 327 pub enum PointerOrigin { 328 #[serde( 329 rename = "element-6066-11e4-a52e-4f735466cecf", 330 serialize_with = "serialize_webelement_id" 331 )] 332 Element(WebElement), 333 #[serde(rename = "pointer")] 334 Pointer, 335 #[serde(rename = "viewport")] 336 #[default] 337 Viewport, 338 } 339 340 // TODO: The custom deserializer can be removed once the support of the legacy 341 // ELEMENT key has been removed from Selenium bindings 342 // See: https://github.com/SeleniumHQ/selenium/issues/6393 343 impl<'de> Deserialize<'de> for PointerOrigin { 344 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 345 where 346 D: Deserializer<'de>, 347 { 348 let value = Value::deserialize(deserializer)?; 349 if let Some(web_element) = value.get(ELEMENT_KEY) { 350 String::deserialize(web_element) 351 .map(|id| PointerOrigin::Element(WebElement(id))) 352 .map_err(de::Error::custom) 353 } else if value == "pointer" { 354 Ok(PointerOrigin::Pointer) 355 } else if value == "viewport" { 356 Ok(PointerOrigin::Viewport) 357 } else { 358 Err(de::Error::custom(format!( 359 "unknown value `{}`, expected `pointer`, `viewport`, or `element-6066-11e4-a52e-4f735466cecf`", 360 value 361 ))) 362 } 363 } 364 } 365 366 #[derive(Debug, PartialEq, Serialize, Deserialize)] 367 #[serde(untagged)] 368 pub enum WheelActionItem { 369 General(GeneralAction), 370 Wheel(WheelAction), 371 } 372 373 #[derive(Debug, PartialEq, Serialize, Deserialize)] 374 #[serde(tag = "type")] 375 pub enum WheelAction { 376 #[serde(rename = "scroll")] 377 Scroll(WheelScrollAction), 378 } 379 380 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] 381 pub struct WheelScrollAction { 382 #[serde( 383 default, 384 skip_serializing_if = "Option::is_none", 385 deserialize_with = "deserialize_to_option_u64" 386 )] 387 pub duration: Option<u64>, 388 #[serde(default)] 389 pub origin: PointerOrigin, 390 pub x: Option<i64>, 391 pub y: Option<i64>, 392 pub deltaX: Option<i64>, 393 pub deltaY: Option<i64>, 394 } 395 396 fn serialize_webelement_id<S>(element: &WebElement, serializer: S) -> Result<S::Ok, S::Error> 397 where 398 S: Serializer, 399 { 400 element.to_string().serialize(serializer) 401 } 402 403 fn deserialize_to_option_i64<'de, D>(deserializer: D) -> Result<Option<i64>, D::Error> 404 where 405 D: Deserializer<'de>, 406 { 407 Option::deserialize(deserializer)? 408 .ok_or_else(|| de::Error::custom("invalid type: null, expected i64")) 409 } 410 411 fn deserialize_to_option_u64<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error> 412 where 413 D: Deserializer<'de>, 414 { 415 Option::deserialize(deserializer)? 416 .ok_or_else(|| de::Error::custom("invalid type: null, expected i64")) 417 } 418 419 fn deserialize_to_option_f64<'de, D>(deserializer: D) -> Result<Option<f64>, D::Error> 420 where 421 D: Deserializer<'de>, 422 { 423 Option::deserialize(deserializer)? 424 .ok_or_else(|| de::Error::custom("invalid type: null, expected f64")) 425 } 426 427 fn deserialize_to_pressure<'de, D>(deserializer: D) -> Result<Option<f64>, D::Error> 428 where 429 D: Deserializer<'de>, 430 { 431 let opt_value = deserialize_to_option_f64(deserializer)?; 432 if let Some(value) = opt_value { 433 if !(0f64..=1.0).contains(&value) { 434 return Err(de::Error::custom(format!("{} is outside range 0-1", value))); 435 } 436 }; 437 Ok(opt_value) 438 } 439 440 fn deserialize_to_tangential_pressure<'de, D>(deserializer: D) -> Result<Option<f64>, D::Error> 441 where 442 D: Deserializer<'de>, 443 { 444 let opt_value = deserialize_to_option_f64(deserializer)?; 445 if let Some(value) = opt_value { 446 if !(-1.0..=1.0).contains(&value) { 447 return Err(de::Error::custom(format!( 448 "{} is outside range -1-1", 449 value 450 ))); 451 } 452 }; 453 Ok(opt_value) 454 } 455 456 fn deserialize_to_tilt<'de, D>(deserializer: D) -> Result<Option<i64>, D::Error> 457 where 458 D: Deserializer<'de>, 459 { 460 let opt_value = deserialize_to_option_i64(deserializer)?; 461 if let Some(value) = opt_value { 462 if !(-90..=90).contains(&value) { 463 return Err(de::Error::custom(format!( 464 "{} is outside range -90-90", 465 value 466 ))); 467 } 468 }; 469 Ok(opt_value) 470 } 471 472 fn deserialize_to_twist<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error> 473 where 474 D: Deserializer<'de>, 475 { 476 let opt_value = deserialize_to_option_u64(deserializer)?; 477 if let Some(value) = opt_value { 478 if !(0..=359).contains(&value) { 479 return Err(de::Error::custom(format!( 480 "{} is outside range 0-359", 481 value 482 ))); 483 } 484 }; 485 Ok(opt_value) 486 } 487 488 fn deserialize_to_altitude_angle<'de, D>(deserializer: D) -> Result<Option<f64>, D::Error> 489 where 490 D: Deserializer<'de>, 491 { 492 let opt_value = deserialize_to_option_f64(deserializer)?; 493 if let Some(value) = opt_value { 494 if !(0f64..=f64::consts::FRAC_PI_2).contains(&value) { 495 return Err(de::Error::custom(format!( 496 "{} is outside range 0-PI/2", 497 value 498 ))); 499 } 500 }; 501 Ok(opt_value) 502 } 503 504 fn deserialize_to_azimuth_angle<'de, D>(deserializer: D) -> Result<Option<f64>, D::Error> 505 where 506 D: Deserializer<'de>, 507 { 508 let opt_value = deserialize_to_option_f64(deserializer)?; 509 if let Some(value) = opt_value { 510 if !(0f64..=f64::consts::TAU).contains(&value) { 511 return Err(de::Error::custom(format!( 512 "{} is outside range 0-2*PI", 513 value 514 ))); 515 } 516 }; 517 Ok(opt_value) 518 } 519 520 #[cfg(test)] 521 mod test { 522 use super::*; 523 use crate::test::{assert_de, assert_ser_de}; 524 use serde_json::{self, json, Value}; 525 526 #[test] 527 fn test_json_action_sequence_null() { 528 let json = json!({ 529 "id": "some_key", 530 "type": "none", 531 "actions": [{ 532 "type": "pause", 533 "duration": 1, 534 }] 535 }); 536 let seq = ActionSequence { 537 id: "some_key".into(), 538 actions: ActionsType::Null { 539 actions: vec![NullActionItem::General(GeneralAction::Pause(PauseAction { 540 duration: Some(1), 541 }))], 542 }, 543 }; 544 545 assert_ser_de(&seq, json); 546 } 547 548 #[test] 549 fn test_json_action_sequence_key() { 550 let json = json!({ 551 "id": "some_key", 552 "type": "key", 553 "actions": [ 554 {"type": "keyDown", "value": "f"}, 555 ], 556 }); 557 let seq = ActionSequence { 558 id: "some_key".into(), 559 actions: ActionsType::Key { 560 actions: vec![KeyActionItem::Key(KeyAction::Down(KeyDownAction { 561 value: String::from("f"), 562 }))], 563 }, 564 }; 565 566 assert_ser_de(&seq, json); 567 } 568 569 #[test] 570 fn test_json_action_sequence_pointer() { 571 let json = json!({ 572 "id": "some_pointer", 573 "type": "pointer", 574 "parameters": { 575 "pointerType": "mouse" 576 }, 577 "actions": [ 578 {"type": "pointerDown", "button": 0}, 579 {"type": "pointerMove", "origin": "pointer", "x": 10.5, "y": 20.5}, 580 {"type": "pointerUp", "button": 0}, 581 ] 582 }); 583 let seq = ActionSequence { 584 id: "some_pointer".into(), 585 actions: ActionsType::Pointer { 586 parameters: PointerActionParameters { 587 pointer_type: PointerType::Mouse, 588 }, 589 actions: vec![ 590 PointerActionItem::Pointer(PointerAction::Down(PointerDownAction { 591 button: 0, 592 ..Default::default() 593 })), 594 PointerActionItem::Pointer(PointerAction::Move(PointerMoveAction { 595 origin: PointerOrigin::Pointer, 596 duration: None, 597 x: 10.5, 598 y: 20.5, 599 ..Default::default() 600 })), 601 PointerActionItem::Pointer(PointerAction::Up(PointerUpAction { 602 button: 0, 603 ..Default::default() 604 })), 605 ], 606 }, 607 }; 608 609 assert_ser_de(&seq, json); 610 } 611 612 #[test] 613 fn test_json_action_sequence_id_missing() { 614 let json = json!({ 615 "type": "key", 616 "actions": [], 617 }); 618 assert!(serde_json::from_value::<ActionSequence>(json).is_err()); 619 } 620 621 #[test] 622 fn test_json_action_sequence_id_null() { 623 let json = json!({ 624 "id": null, 625 "type": "key", 626 "actions": [], 627 }); 628 assert!(serde_json::from_value::<ActionSequence>(json).is_err()); 629 } 630 631 #[test] 632 fn test_json_action_sequence_actions_missing() { 633 assert!(serde_json::from_value::<ActionSequence>(json!({"id": "3"})).is_err()); 634 } 635 636 #[test] 637 fn test_json_action_sequence_actions_null() { 638 let json = json!({ 639 "id": "3", 640 "actions": null, 641 }); 642 assert!(serde_json::from_value::<ActionSequence>(json).is_err()); 643 } 644 645 #[test] 646 fn test_json_action_sequence_actions_invalid_type() { 647 let json = json!({ 648 "id": "3", 649 "actions": "foo", 650 }); 651 assert!(serde_json::from_value::<ActionSequence>(json).is_err()); 652 } 653 654 #[test] 655 fn test_json_actions_type_null() { 656 let json = json!({ 657 "type": "none", 658 "actions": [{ 659 "type": "pause", 660 "duration": 1, 661 }], 662 }); 663 let null = ActionsType::Null { 664 actions: vec![NullActionItem::General(GeneralAction::Pause(PauseAction { 665 duration: Some(1), 666 }))], 667 }; 668 669 assert_ser_de(&null, json); 670 } 671 672 #[test] 673 fn test_json_actions_type_key() { 674 let json = json!({ 675 "type": "key", 676 "actions": [{ 677 "type": "keyDown", 678 "value": "f", 679 }], 680 }); 681 let key = ActionsType::Key { 682 actions: vec![KeyActionItem::Key(KeyAction::Down(KeyDownAction { 683 value: String::from("f"), 684 }))], 685 }; 686 687 assert_ser_de(&key, json); 688 } 689 690 #[test] 691 fn test_json_actions_type_pointer() { 692 let json = json!({ 693 "type": "pointer", 694 "parameters": {"pointerType": "mouse"}, 695 "actions": [ 696 {"type": "pointerDown", "button": 1}, 697 ]}); 698 let pointer = ActionsType::Pointer { 699 parameters: PointerActionParameters { 700 pointer_type: PointerType::Mouse, 701 }, 702 actions: vec![PointerActionItem::Pointer(PointerAction::Down( 703 PointerDownAction { 704 button: 1, 705 ..Default::default() 706 }, 707 ))], 708 }; 709 710 assert_ser_de(&pointer, json); 711 } 712 713 #[test] 714 fn test_json_actions_type_pointer_with_parameters_missing() { 715 let json = json!({ 716 "type": "pointer", 717 "actions": [ 718 {"type": "pointerDown", "button": 1}, 719 ]}); 720 let pointer = ActionsType::Pointer { 721 parameters: PointerActionParameters { 722 pointer_type: PointerType::Mouse, 723 }, 724 actions: vec![PointerActionItem::Pointer(PointerAction::Down( 725 PointerDownAction { 726 button: 1, 727 ..Default::default() 728 }, 729 ))], 730 }; 731 732 assert_de(&pointer, json); 733 } 734 735 #[test] 736 fn test_json_actions_type_pointer_with_parameters_invalid_type() { 737 let json = json!({ 738 "type": "pointer", 739 "parameters": null, 740 "actions": [ 741 {"type":"pointerDown", "button": 1}, 742 ]}); 743 assert!(serde_json::from_value::<ActionsType>(json).is_err()); 744 } 745 746 #[test] 747 fn test_json_actions_type_invalid() { 748 let json = json!({"actions": [{"foo": "bar"}]}); 749 assert!(serde_json::from_value::<ActionsType>(json).is_err()); 750 } 751 752 #[test] 753 fn test_json_null_action_item_general() { 754 let pause = 755 NullActionItem::General(GeneralAction::Pause(PauseAction { duration: Some(1) })); 756 assert_ser_de(&pause, json!({"type": "pause", "duration": 1})); 757 } 758 759 #[test] 760 fn test_json_null_action_item_invalid_type() { 761 assert!(serde_json::from_value::<NullActionItem>(json!({"type": "invalid"})).is_err()); 762 } 763 764 #[test] 765 fn test_json_general_action_pause() { 766 let pause = GeneralAction::Pause(PauseAction { duration: Some(1) }); 767 assert_ser_de(&pause, json!({"type": "pause", "duration": 1})); 768 } 769 770 #[test] 771 fn test_json_general_action_pause_with_duration_missing() { 772 let pause = GeneralAction::Pause(PauseAction { duration: None }); 773 assert_ser_de(&pause, json!({"type": "pause"})); 774 } 775 776 #[test] 777 fn test_json_general_action_pause_with_duration_null() { 778 let json = json!({"type": "pause", "duration": null}); 779 assert!(serde_json::from_value::<GeneralAction>(json).is_err()); 780 } 781 782 #[test] 783 fn test_json_general_action_pause_with_duration_invalid_type() { 784 let json = json!({"type": "pause", "duration":" foo"}); 785 assert!(serde_json::from_value::<GeneralAction>(json).is_err()); 786 } 787 788 #[test] 789 fn test_json_general_action_pause_with_duration_negative() { 790 let json = json!({"type": "pause", "duration": -30}); 791 assert!(serde_json::from_value::<GeneralAction>(json).is_err()); 792 } 793 794 #[test] 795 fn test_json_key_action_item_general() { 796 let pause = KeyActionItem::General(GeneralAction::Pause(PauseAction { duration: Some(1) })); 797 assert_ser_de(&pause, json!({"type": "pause", "duration": 1})); 798 } 799 800 #[test] 801 fn test_json_key_action_item_key() { 802 let key_down = KeyActionItem::Key(KeyAction::Down(KeyDownAction { 803 value: String::from("f"), 804 })); 805 assert_ser_de(&key_down, json!({"type": "keyDown", "value": "f"})); 806 } 807 808 #[test] 809 fn test_json_key_action_item_invalid_type() { 810 assert!(serde_json::from_value::<KeyActionItem>(json!({"type": "invalid"})).is_err()); 811 } 812 813 #[test] 814 fn test_json_key_action_missing_subtype() { 815 assert!(serde_json::from_value::<KeyAction>(json!({"value": "f"})).is_err()); 816 } 817 818 #[test] 819 fn test_json_key_action_wrong_subtype() { 820 let json = json!({"type": "pause", "value": "f"}); 821 assert!(serde_json::from_value::<KeyAction>(json).is_err()); 822 } 823 824 #[test] 825 fn test_json_key_action_down() { 826 let key_down = KeyAction::Down(KeyDownAction { 827 value: "f".to_string(), 828 }); 829 assert_ser_de(&key_down, json!({"type": "keyDown", "value": "f"})); 830 } 831 832 #[test] 833 fn test_json_key_action_down_with_value_unicode() { 834 let key_down = KeyAction::Down(KeyDownAction { 835 value: "Ã ".to_string(), 836 }); 837 assert_ser_de(&key_down, json!({"type": "keyDown", "value": "Ã "})); 838 } 839 840 #[test] 841 fn test_json_key_action_down_with_value_unicode_encoded() { 842 let key_down = KeyAction::Down(KeyDownAction { 843 value: "Ã ".to_string(), 844 }); 845 assert_de(&key_down, json!({"type": "keyDown", "value": "\u{00E0}"})); 846 } 847 848 #[test] 849 fn test_json_key_action_down_with_value_missing() { 850 assert!(serde_json::from_value::<KeyAction>(json!({"type": "keyDown"})).is_err()); 851 } 852 853 #[test] 854 fn test_json_key_action_down_with_value_null() { 855 let json = json!({"type": "keyDown", "value": null}); 856 assert!(serde_json::from_value::<KeyAction>(json).is_err()); 857 } 858 859 #[test] 860 fn test_json_key_action_down_with_value_invalid_type() { 861 let json = json!({"type": "keyDown", "value": ["f", "o", "o"]}); 862 assert!(serde_json::from_value::<KeyAction>(json).is_err()); 863 } 864 865 #[test] 866 fn test_json_key_action_down_with_multiple_code_points() { 867 let json = json!({"type": "keyDown", "value": "fo"}); 868 assert!(serde_json::from_value::<KeyAction>(json).is_err()); 869 } 870 871 #[test] 872 fn test_json_key_action_up() { 873 let key_up = KeyAction::Up(KeyUpAction { 874 value: "f".to_string(), 875 }); 876 assert_ser_de(&key_up, json!({"type": "keyUp", "value": "f"})); 877 } 878 879 #[test] 880 fn test_json_key_action_up_with_value_unicode() { 881 let key_up = KeyAction::Up(KeyUpAction { 882 value: "Ã ".to_string(), 883 }); 884 assert_ser_de(&key_up, json!({"type":"keyUp", "value": "Ã "})); 885 } 886 887 #[test] 888 fn test_json_key_action_up_with_value_unicode_encoded() { 889 let key_up = KeyAction::Up(KeyUpAction { 890 value: "Ã ".to_string(), 891 }); 892 assert_de(&key_up, json!({"type": "keyUp", "value": "\u{00E0}"})); 893 } 894 895 #[test] 896 fn test_json_key_action_up_with_value_missing() { 897 assert!(serde_json::from_value::<KeyAction>(json!({"type": "keyUp"})).is_err()); 898 } 899 900 #[test] 901 fn test_json_key_action_up_with_value_null() { 902 let json = json!({"type": "keyUp", "value": null}); 903 assert!(serde_json::from_value::<KeyAction>(json).is_err()); 904 } 905 906 #[test] 907 fn test_json_key_action_up_with_value_invalid_type() { 908 let json = json!({"type": "keyUp", "value": ["f","o","o"]}); 909 assert!(serde_json::from_value::<KeyAction>(json).is_err()); 910 } 911 912 #[test] 913 fn test_json_key_action_up_with_multiple_code_points() { 914 let json = json!({"type": "keyUp", "value": "fo"}); 915 assert!(serde_json::from_value::<KeyAction>(json).is_err()); 916 } 917 918 #[test] 919 fn test_json_pointer_action_item_general() { 920 let pause = 921 PointerActionItem::General(GeneralAction::Pause(PauseAction { duration: Some(1) })); 922 assert_ser_de(&pause, json!({"type": "pause", "duration": 1})); 923 } 924 925 #[test] 926 fn test_json_pointer_action_item_pointer() { 927 let cancel = PointerActionItem::Pointer(PointerAction::Cancel); 928 assert_ser_de(&cancel, json!({"type": "pointerCancel"})); 929 } 930 931 #[test] 932 fn test_json_pointer_action_item_invalid() { 933 assert!(serde_json::from_value::<PointerActionItem>(json!({"type": "invalid"})).is_err()); 934 } 935 936 #[test] 937 fn test_json_pointer_action_parameters_mouse() { 938 let mouse = PointerActionParameters { 939 pointer_type: PointerType::Mouse, 940 }; 941 assert_ser_de(&mouse, json!({"pointerType": "mouse"})); 942 } 943 944 #[test] 945 fn test_json_pointer_action_parameters_pen() { 946 let pen = PointerActionParameters { 947 pointer_type: PointerType::Pen, 948 }; 949 assert_ser_de(&pen, json!({"pointerType": "pen"})); 950 } 951 952 #[test] 953 fn test_json_pointer_action_parameters_touch() { 954 let touch = PointerActionParameters { 955 pointer_type: PointerType::Touch, 956 }; 957 assert_ser_de(&touch, json!({"pointerType": "touch"})); 958 } 959 960 #[test] 961 fn test_json_pointer_action_item_invalid_type() { 962 let json = json!({"type": "pointerInvalid"}); 963 assert!(serde_json::from_value::<PointerActionItem>(json).is_err()); 964 } 965 966 #[test] 967 fn test_json_pointer_action_missing_subtype() { 968 assert!(serde_json::from_value::<PointerAction>(json!({"button": 1})).is_err()); 969 } 970 971 #[test] 972 fn test_json_pointer_action_invalid_subtype() { 973 let json = json!({"type": "invalid", "button": 1}); 974 assert!(serde_json::from_value::<PointerAction>(json).is_err()); 975 } 976 977 #[test] 978 fn test_json_pointer_action_cancel() { 979 assert_ser_de(&PointerAction::Cancel, json!({"type": "pointerCancel"})); 980 } 981 982 #[test] 983 fn test_json_pointer_action_down() { 984 let pointer_down = PointerAction::Down(PointerDownAction { 985 button: 1, 986 ..Default::default() 987 }); 988 assert_ser_de(&pointer_down, json!({"type": "pointerDown", "button": 1})); 989 } 990 991 #[test] 992 fn test_json_pointer_action_down_with_button_missing() { 993 let json = json!({"type": "pointerDown"}); 994 assert!(serde_json::from_value::<PointerAction>(json).is_err()); 995 } 996 997 #[test] 998 fn test_json_pointer_action_down_with_button_null() { 999 let json = json!({ 1000 "type": "pointerDown", 1001 "button": null, 1002 }); 1003 assert!(serde_json::from_value::<PointerAction>(json).is_err()); 1004 } 1005 1006 #[test] 1007 fn test_json_pointer_action_down_with_button_invalid_type() { 1008 let json = json!({ 1009 "type": "pointerDown", 1010 "button": "foo", 1011 }); 1012 assert!(serde_json::from_value::<PointerAction>(json).is_err()); 1013 } 1014 1015 #[test] 1016 fn test_json_pointer_action_down_with_button_negative() { 1017 let json = json!({ 1018 "type": "pointerDown", 1019 "button": -30, 1020 }); 1021 assert!(serde_json::from_value::<PointerAction>(json).is_err()); 1022 } 1023 1024 #[test] 1025 fn test_json_pointer_action_move() { 1026 let json = json!({ 1027 "type": "pointerMove", 1028 "duration": 100, 1029 "origin": "viewport", 1030 "x": 5.5, 1031 "y": 10.5, 1032 }); 1033 let pointer_move = PointerAction::Move(PointerMoveAction { 1034 duration: Some(100), 1035 origin: PointerOrigin::Viewport, 1036 x: 5.5, 1037 y: 10.5, 1038 ..Default::default() 1039 }); 1040 1041 assert_ser_de(&pointer_move, json); 1042 } 1043 1044 #[test] 1045 fn test_json_pointer_action_move_missing_subtype() { 1046 let json = json!({ 1047 "duration": 100, 1048 "origin": "viewport", 1049 "x": 5.5, 1050 "y": 10.5, 1051 }); 1052 assert!(serde_json::from_value::<PointerAction>(json).is_err()); 1053 } 1054 1055 #[test] 1056 fn test_json_pointer_action_move_wrong_subtype() { 1057 let json = json!({ 1058 "type": "pointerUp", 1059 "duration": 100, 1060 "origin": "viewport", 1061 "x": 5.5, 1062 "y": 10.5, 1063 }); 1064 assert!(serde_json::from_value::<PointerAction>(json).is_err()); 1065 } 1066 1067 #[test] 1068 fn test_json_pointer_action_move_with_duration_missing() { 1069 let json = json!({ 1070 "type": "pointerMove", 1071 "origin": "viewport", 1072 "x": 5.5, 1073 "y": 10.5, 1074 }); 1075 let pointer_move = PointerAction::Move(PointerMoveAction { 1076 duration: None, 1077 origin: PointerOrigin::Viewport, 1078 x: 5.5, 1079 y: 10.5, 1080 ..Default::default() 1081 }); 1082 1083 assert_ser_de(&pointer_move, json); 1084 } 1085 1086 #[test] 1087 fn test_json_pointer_action_move_with_duration_null() { 1088 let json = json!({ 1089 "type": "pointerMove", 1090 "duration": null, 1091 "origin": "viewport", 1092 "x": 5.5, 1093 "y": 10.5, 1094 }); 1095 assert!(serde_json::from_value::<PointerAction>(json).is_err()); 1096 } 1097 1098 #[test] 1099 fn test_json_pointer_action_move_with_duration_invalid_type() { 1100 let json = json!({ 1101 "type": "pointerMove", 1102 "duration": "invalid", 1103 "origin": "viewport", 1104 "x": 5.5, 1105 "y": 10.5, 1106 }); 1107 assert!(serde_json::from_value::<PointerAction>(json).is_err()); 1108 } 1109 1110 #[test] 1111 fn test_json_pointer_action_move_with_duration_negative() { 1112 let json = json!({ 1113 "type": "pointerMove", 1114 "duration": -30, 1115 "origin": "viewport", 1116 "x": 5.5, 1117 "y": 10.5, 1118 }); 1119 assert!(serde_json::from_value::<PointerAction>(json).is_err()); 1120 } 1121 1122 #[test] 1123 fn test_json_pointer_action_move_with_origin_missing() { 1124 let json = json!({ 1125 "type": "pointerMove", 1126 "duration": 100, 1127 "x": 5.5, 1128 "y": 10.5, 1129 }); 1130 let pointer_move = PointerAction::Move(PointerMoveAction { 1131 duration: Some(100), 1132 origin: PointerOrigin::Viewport, 1133 x: 5.5, 1134 y: 10.5, 1135 ..Default::default() 1136 }); 1137 1138 assert_de(&pointer_move, json); 1139 } 1140 1141 #[test] 1142 fn test_json_pointer_action_move_with_origin_webelement() { 1143 let json = json!({ 1144 "type": "pointerMove", 1145 "duration": 100, 1146 "origin": {ELEMENT_KEY: "elem"}, 1147 "x": 5.5, 1148 "y": 10.5, 1149 }); 1150 let pointer_move = PointerAction::Move(PointerMoveAction { 1151 duration: Some(100), 1152 origin: PointerOrigin::Element(WebElement("elem".into())), 1153 x: 5.5, 1154 y: 10.5, 1155 ..Default::default() 1156 }); 1157 1158 assert_ser_de(&pointer_move, json); 1159 } 1160 1161 #[test] 1162 fn test_json_pointer_action_move_with_origin_webelement_and_legacy_element() { 1163 let json = json!({ 1164 "type": "pointerMove", 1165 "duration": 100, 1166 "origin": {ELEMENT_KEY: "elem"}, 1167 "x": 5.5, 1168 "y": 10.5, 1169 }); 1170 let pointer_move = PointerAction::Move(PointerMoveAction { 1171 duration: Some(100), 1172 origin: PointerOrigin::Element(WebElement("elem".into())), 1173 x: 5.5, 1174 y: 10.5, 1175 ..Default::default() 1176 }); 1177 1178 assert_de(&pointer_move, json); 1179 } 1180 1181 #[test] 1182 fn test_json_pointer_action_move_with_origin_only_legacy_element() { 1183 let json = json!({ 1184 "type": "pointerMove", 1185 "duration": 100, 1186 "origin": {ELEMENT_KEY: "elem"}, 1187 "x": 5, 1188 "y": 10, 1189 }); 1190 assert!(serde_json::from_value::<PointerOrigin>(json).is_err()); 1191 } 1192 1193 #[test] 1194 fn test_json_pointer_action_move_with_x_null() { 1195 let json = json!({ 1196 "type": "pointerMove", 1197 "duration": 100, 1198 "origin": "viewport", 1199 "x": null, 1200 "y": 10, 1201 }); 1202 assert!(serde_json::from_value::<PointerAction>(json).is_err()); 1203 } 1204 1205 #[test] 1206 fn test_json_pointer_action_move_with_x_invalid_type() { 1207 let json = json!({ 1208 "type": "pointerMove", 1209 "duration": 100, 1210 "origin": "viewport", 1211 "x": "invalid", 1212 "y": 10, 1213 }); 1214 assert!(serde_json::from_value::<PointerAction>(json).is_err()); 1215 } 1216 1217 #[test] 1218 fn test_json_pointer_action_move_with_y_null() { 1219 let json = json!({ 1220 "type": "pointerMove", 1221 "duration": 100, 1222 "origin": "viewport", 1223 "x": 5, 1224 "y": null, 1225 }); 1226 assert!(serde_json::from_value::<PointerAction>(json).is_err()); 1227 } 1228 1229 #[test] 1230 fn test_json_pointer_action_move_with_y_invalid_type() { 1231 let json = json!({ 1232 "type": "pointerMove", 1233 "duration": 100, 1234 "origin": "viewport", 1235 "x": 5, 1236 "y": "invalid", 1237 }); 1238 assert!(serde_json::from_value::<PointerAction>(json).is_err()); 1239 } 1240 1241 #[test] 1242 fn test_json_pointer_action_up() { 1243 let pointer_up = PointerAction::Up(PointerUpAction { 1244 button: 1, 1245 ..Default::default() 1246 }); 1247 assert_ser_de(&pointer_up, json!({"type": "pointerUp", "button": 1})); 1248 } 1249 1250 #[test] 1251 fn test_json_pointer_action_up_with_button_missing() { 1252 assert!(serde_json::from_value::<PointerAction>(json!({"type": "pointerUp"})).is_err()); 1253 } 1254 1255 #[test] 1256 fn test_json_pointer_action_up_with_button_null() { 1257 let json = json!({ 1258 "type": "pointerUp", 1259 "button": null, 1260 }); 1261 assert!(serde_json::from_value::<PointerAction>(json).is_err()); 1262 } 1263 1264 #[test] 1265 fn test_json_pointer_action_up_with_button_invalid_type() { 1266 let json = json!({ 1267 "type": "pointerUp", 1268 "button": "foo", 1269 }); 1270 assert!(serde_json::from_value::<PointerAction>(json).is_err()); 1271 } 1272 1273 #[test] 1274 fn test_json_pointer_action_up_with_button_negative() { 1275 let json = json!({ 1276 "type": "pointerUp", 1277 "button": -30, 1278 }); 1279 assert!(serde_json::from_value::<PointerAction>(json).is_err()); 1280 } 1281 1282 #[test] 1283 fn test_json_pointer_origin_pointer() { 1284 assert_ser_de(&PointerOrigin::Pointer, json!("pointer")); 1285 } 1286 1287 #[test] 1288 fn test_json_pointer_origin_viewport() { 1289 assert_ser_de(&PointerOrigin::Viewport, json!("viewport")); 1290 } 1291 1292 #[test] 1293 fn test_json_pointer_origin_web_element() { 1294 let element = PointerOrigin::Element(WebElement("elem".into())); 1295 assert_ser_de(&element, json!({ELEMENT_KEY: "elem"})); 1296 } 1297 1298 #[test] 1299 fn test_json_pointer_origin_invalid_type() { 1300 assert!(serde_json::from_value::<PointerOrigin>(json!("invalid")).is_err()); 1301 } 1302 1303 #[test] 1304 fn test_json_pointer_type_mouse() { 1305 assert_ser_de(&PointerType::Mouse, json!("mouse")); 1306 } 1307 1308 #[test] 1309 fn test_json_pointer_type_pen() { 1310 assert_ser_de(&PointerType::Pen, json!("pen")); 1311 } 1312 1313 #[test] 1314 fn test_json_pointer_type_touch() { 1315 assert_ser_de(&PointerType::Touch, json!("touch")); 1316 } 1317 1318 #[test] 1319 fn test_json_pointer_type_invalid_type() { 1320 assert!(serde_json::from_value::<PointerType>(json!("invalid")).is_err()); 1321 } 1322 1323 #[test] 1324 fn test_pointer_properties() { 1325 // Ideally these would be seperate tests, but it was too much boilerplate to write 1326 // and adding a macro seemed like overkill. 1327 for actionType in ["pointerUp", "pointerDown", "pointerMove"] { 1328 for (prop_name, value, is_valid) in [ 1329 ("pressure", Value::from(0), true), 1330 ("pressure", Value::from(0.5), true), 1331 ("pressure", Value::from(1), true), 1332 ("pressure", Value::from(1.1), false), 1333 ("pressure", Value::from(-0.1), false), 1334 ("tangentialPressure", Value::from(-1), true), 1335 ("tangentialPressure", Value::from(0), true), 1336 ("tangentialPressure", Value::from(1.0), true), 1337 ("tangentialPressure", Value::from(-1.1), false), 1338 ("tangentialPressure", Value::from(1.1), false), 1339 ("tiltX", Value::from(-90), true), 1340 ("tiltX", Value::from(0), true), 1341 ("tiltX", Value::from(45), true), 1342 ("tiltX", Value::from(90), true), 1343 ("tiltX", Value::from(0.5), false), 1344 ("tiltX", Value::from(-91), false), 1345 ("tiltX", Value::from(91), false), 1346 ("tiltY", Value::from(-90), true), 1347 ("tiltY", Value::from(0), true), 1348 ("tiltY", Value::from(45), true), 1349 ("tiltY", Value::from(90), true), 1350 ("tiltY", Value::from(0.5), false), 1351 ("tiltY", Value::from(-91), false), 1352 ("tiltY", Value::from(91), false), 1353 ("twist", Value::from(0), true), 1354 ("twist", Value::from(180), true), 1355 ("twist", Value::from(359), true), 1356 ("twist", Value::from(360), false), 1357 ("twist", Value::from(-1), false), 1358 ("twist", Value::from(23.5), false), 1359 ("altitudeAngle", Value::from(0), true), 1360 ("altitudeAngle", Value::from(f64::consts::FRAC_PI_4), true), 1361 ("altitudeAngle", Value::from(f64::consts::FRAC_PI_2), true), 1362 ( 1363 "altitudeAngle", 1364 Value::from(f64::consts::FRAC_PI_2 + 0.1), 1365 false, 1366 ), 1367 ("altitudeAngle", Value::from(-f64::consts::FRAC_PI_4), false), 1368 ("azimuthAngle", Value::from(0), true), 1369 ("azimuthAngle", Value::from(f64::consts::PI), true), 1370 ("azimuthAngle", Value::from(f64::consts::TAU), true), 1371 ("azimuthAngle", Value::from(f64::consts::TAU + 0.01), false), 1372 ("azimuthAngle", Value::from(-f64::consts::FRAC_PI_4), false), 1373 ] { 1374 let mut json = serde_json::Map::new(); 1375 json.insert("type".into(), actionType.into()); 1376 if actionType != "pointerMove" { 1377 json.insert("button".into(), Value::from(0)); 1378 } else { 1379 json.insert("x".into(), Value::from(0)); 1380 json.insert("y".into(), Value::from(0)); 1381 } 1382 json.insert(prop_name.into(), value); 1383 println!("{:?}", json); 1384 let deserialized = serde_json::from_value::<PointerAction>(json.into()); 1385 if is_valid { 1386 assert!(deserialized.is_ok()); 1387 } else { 1388 assert!(deserialized.is_err()); 1389 } 1390 } 1391 } 1392 } 1393 }