playwright_rs/protocol/
drop_options.rs1use crate::protocol::FilePayload;
6use crate::protocol::click::Position;
7
8#[derive(Debug, Clone, Default)]
36#[non_exhaustive]
37pub struct DropOptions {
38 pub files: Vec<FilePayload>,
40 pub data: Vec<(String, String)>,
42 pub position: Option<Position>,
44 pub timeout: Option<f64>,
46}
47
48impl DropOptions {
49 pub fn builder() -> DropOptionsBuilder {
51 DropOptionsBuilder::default()
52 }
53
54 pub(crate) fn to_json(&self) -> serde_json::Value {
56 use base64::{Engine as _, engine::general_purpose};
57
58 let mut json = serde_json::json!({});
59
60 if !self.files.is_empty() {
61 let payloads: Vec<serde_json::Value> = self
62 .files
63 .iter()
64 .map(|f| {
65 serde_json::json!({
66 "name": f.name,
67 "mimeType": f.mime_type,
68 "buffer": general_purpose::STANDARD.encode(&f.buffer),
69 })
70 })
71 .collect();
72 json["payloads"] = serde_json::Value::Array(payloads);
73 }
74
75 if !self.data.is_empty() {
76 let data: Vec<serde_json::Value> = self
77 .data
78 .iter()
79 .map(|(mime, value)| serde_json::json!({ "mimeType": mime, "value": value }))
80 .collect();
81 json["data"] = serde_json::Value::Array(data);
82 }
83
84 if let Some(position) = &self.position {
85 json["position"] =
86 serde_json::to_value(position).expect("serialization of position cannot fail");
87 }
88
89 if let Some(timeout) = self.timeout {
91 json["timeout"] = serde_json::json!(timeout);
92 } else {
93 json["timeout"] = serde_json::json!(crate::DEFAULT_TIMEOUT_MS);
94 }
95
96 json
97 }
98}
99
100#[derive(Debug, Clone, Default)]
104pub struct DropOptionsBuilder {
105 files: Vec<FilePayload>,
106 data: Vec<(String, String)>,
107 position: Option<Position>,
108 timeout: Option<f64>,
109}
110
111impl DropOptionsBuilder {
112 pub fn file(mut self, file: FilePayload) -> Self {
114 self.files.push(file);
115 self
116 }
117
118 pub fn files(mut self, files: Vec<FilePayload>) -> Self {
120 self.files = files;
121 self
122 }
123
124 pub fn data(mut self, mime_type: impl Into<String>, value: impl Into<String>) -> Self {
126 self.data.push((mime_type.into(), value.into()));
127 self
128 }
129
130 pub fn position(mut self, position: Position) -> Self {
132 self.position = Some(position);
133 self
134 }
135
136 pub fn timeout(mut self, timeout: f64) -> Self {
138 self.timeout = Some(timeout);
139 self
140 }
141
142 pub fn build(self) -> DropOptions {
144 DropOptions {
145 files: self.files,
146 data: self.data,
147 position: self.position,
148 timeout: self.timeout,
149 }
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156
157 #[test]
158 fn test_drop_options_default() {
159 let json = DropOptions::builder().build().to_json();
160 assert!(json["timeout"].is_number());
161 assert!(json.get("payloads").is_none());
162 assert!(json.get("data").is_none());
163 assert!(json.get("position").is_none());
164 }
165
166 #[test]
167 fn test_drop_options_file_payload() {
168 let file = FilePayload::new("note.txt", "text/plain", b"hi".to_vec());
169 let json = DropOptions::builder().file(file).build().to_json();
170 assert_eq!(json["payloads"][0]["name"], "note.txt");
171 assert_eq!(json["payloads"][0]["mimeType"], "text/plain");
172 assert_eq!(json["payloads"][0]["buffer"], "aGk="); }
174
175 #[test]
176 fn test_drop_options_data() {
177 let json = DropOptions::builder()
178 .data("text/uri-list", "https://example.com")
179 .build()
180 .to_json();
181 assert_eq!(json["data"][0]["mimeType"], "text/uri-list");
182 assert_eq!(json["data"][0]["value"], "https://example.com");
183 }
184
185 #[test]
186 fn test_drop_options_position_and_timeout() {
187 let json = DropOptions::builder()
188 .position(Position { x: 10.0, y: 20.0 })
189 .timeout(5000.0)
190 .build()
191 .to_json();
192 assert_eq!(json["position"]["x"], 10.0);
193 assert_eq!(json["position"]["y"], 20.0);
194 assert_eq!(json["timeout"], 5000.0);
195 }
196}