1use ferridriver::locator::Locator;
4use ferridriver::options::{FilterOptions, LocatorLike};
5use rquickjs::JsLifetime;
6use rquickjs::class::Trace;
7use rquickjs::function::Opt;
8
9use crate::bindings::convert::FerriResultExt;
10
11pub(crate) struct ParsedLocatorOptions {
17 pub has_text: Option<String>,
18 pub has_not_text: Option<String>,
19 pub has: Option<LocatorLike>,
20 pub has_not: Option<LocatorLike>,
21 pub visible: Option<bool>,
22}
23
24fn get_string<'js>(obj: &rquickjs::Object<'js>, key: &str) -> rquickjs::Result<Option<String>> {
26 let v: rquickjs::Value<'js> = obj.get(key)?;
27 if v.is_undefined() || v.is_null() {
28 return Ok(None);
29 }
30 match v.as_string() {
31 Some(s) => Ok(Some(s.to_string()?)),
32 None => Err(rquickjs::Error::new_from_js_message(
33 "filter options",
34 "field",
35 format!("{key}: expected string"),
36 )),
37 }
38}
39
40fn get_locator_like<'js>(
45 ctx: &rquickjs::Ctx<'js>,
46 obj: &rquickjs::Object<'js>,
47 key: &str,
48) -> rquickjs::Result<Option<LocatorLike>> {
49 let v: rquickjs::Value<'js> = obj.get(key)?;
50 if v.is_undefined() || v.is_null() {
51 return Ok(None);
52 }
53 if let Ok(class) = rquickjs::Class::<LocatorJs>::from_value(&v) {
57 let inner = class.borrow();
58 return Ok(Some(LocatorLike::Locator(inner.inner.clone())));
59 }
60 let _ = ctx;
63 if let Some(obj) = v.as_object() {
64 if let Some(sel) = get_string(obj, "selector")? {
65 return Ok(Some(LocatorLike::Selector(sel)));
66 }
67 }
68 Err(rquickjs::Error::new_from_js_message(
69 "filter options",
70 "field",
71 format!("{key}: expected Locator instance or {{ selector: string }}"),
72 ))
73}
74
75fn get_bool<'js>(obj: &rquickjs::Object<'js>, key: &str) -> rquickjs::Result<Option<bool>> {
76 let v: rquickjs::Value<'js> = obj.get(key)?;
77 if v.is_undefined() || v.is_null() {
78 return Ok(None);
79 }
80 v.as_bool()
81 .map(Some)
82 .ok_or_else(|| rquickjs::Error::new_from_js_message("filter options", "field", format!("{key}: expected boolean")))
83}
84
85pub(crate) fn parse_locator_options_public<'js>(
86 ctx: &rquickjs::Ctx<'js>,
87 value: Opt<rquickjs::Value<'js>>,
88 allow_visible: bool,
89) -> rquickjs::Result<ParsedLocatorOptions> {
90 let Some(val) = value.0 else {
91 return Ok(ParsedLocatorOptions {
92 has_text: None,
93 has_not_text: None,
94 has: None,
95 has_not: None,
96 visible: None,
97 });
98 };
99 if val.is_undefined() || val.is_null() {
100 return Ok(ParsedLocatorOptions {
101 has_text: None,
102 has_not_text: None,
103 has: None,
104 has_not: None,
105 visible: None,
106 });
107 }
108 let obj = val
109 .as_object()
110 .ok_or_else(|| rquickjs::Error::new_from_js_message("locator options", "", "expected an options object"))?;
111 Ok(ParsedLocatorOptions {
112 has_text: get_string(obj, "hasText")?,
113 has_not_text: get_string(obj, "hasNotText")?,
114 has: get_locator_like(ctx, obj, "has")?,
115 has_not: get_locator_like(ctx, obj, "hasNot")?,
116 visible: if allow_visible { get_bool(obj, "visible")? } else { None },
117 })
118}
119
120pub(crate) fn is_empty_filter(opts: &FilterOptions) -> bool {
124 opts.has_text.is_none()
125 && opts.has_not_text.is_none()
126 && opts.has.is_none()
127 && opts.has_not.is_none()
128 && opts.visible.is_none()
129}
130
131#[derive(JsLifetime, Trace)]
132#[rquickjs::class(rename = "Locator")]
133pub struct LocatorJs {
134 #[qjs(skip_trace)]
135 inner: Locator,
136}
137
138impl LocatorJs {
139 #[must_use]
140 pub fn new(inner: Locator) -> Self {
141 Self { inner }
142 }
143
144 #[must_use]
148 pub fn inner_ref(&self) -> &Locator {
149 &self.inner
150 }
151}
152
153#[rquickjs::methods]
154impl LocatorJs {
155 #[qjs(rename = "locator")]
166 pub fn locator<'js>(
167 &self,
168 ctx: rquickjs::Ctx<'js>,
169 selector_or_locator: rquickjs::Value<'js>,
170 options: Opt<rquickjs::Value<'js>>,
171 ) -> rquickjs::Result<LocatorJs> {
172 let like: ferridriver::options::LocatorLike = if let Some(s) = selector_or_locator.as_string() {
176 ferridriver::options::LocatorLike::Selector(s.to_string()?)
177 } else if let Ok(class) = rquickjs::Class::<LocatorJs>::from_value(&selector_or_locator) {
178 ferridriver::options::LocatorLike::Locator(class.borrow().inner.clone())
179 } else if let Some(obj) = selector_or_locator.as_object() {
180 match get_string(obj, "selector")? {
181 Some(sel) => ferridriver::options::LocatorLike::Selector(sel),
182 None => {
183 return Err(rquickjs::Error::new_from_js_message(
184 "Locator",
185 "locator",
186 "expected a selector string or Locator instance",
187 ));
188 },
189 }
190 } else {
191 return Err(rquickjs::Error::new_from_js_message(
192 "Locator",
193 "locator",
194 "expected a selector string or Locator instance",
195 ));
196 };
197
198 let opts = parse_locator_options_public(&ctx, options, false)?;
203 let filter_opts = ferridriver::options::FilterOptions {
204 has_text: opts.has_text,
205 has_not_text: opts.has_not_text,
206 has: opts.has,
207 has_not: opts.has_not,
208 visible: opts.visible,
209 };
210 let filter = if is_empty_filter(&filter_opts) {
211 None
212 } else {
213 Some(filter_opts)
214 };
215 Ok(LocatorJs::new(self.inner.locator(like, filter)))
216 }
217
218 #[qjs(rename = "filter")]
222 pub fn filter<'js>(
223 &self,
224 ctx: rquickjs::Ctx<'js>,
225 options: Opt<rquickjs::Value<'js>>,
226 ) -> rquickjs::Result<LocatorJs> {
227 let parsed = parse_locator_options_public(&ctx, options, true)?;
228 let opts = FilterOptions {
229 has_text: parsed.has_text,
230 has_not_text: parsed.has_not_text,
231 has: parsed.has,
232 has_not: parsed.has_not,
233 visible: parsed.visible,
234 };
235 Ok(LocatorJs::new(self.inner.filter(&opts)))
236 }
237
238 #[qjs(rename = "and")]
243 pub fn and<'js>(&self, ctx: rquickjs::Ctx<'js>, other: rquickjs::Value<'js>) -> rquickjs::Result<LocatorJs> {
244 let _ = ctx;
245 let class = rquickjs::Class::<LocatorJs>::from_value(&other)
246 .map_err(|_| rquickjs::Error::new_from_js_message("Locator", "and", "expected a Locator instance"))?;
247 Ok(LocatorJs::new(self.inner.and(&class.borrow().inner)))
248 }
249
250 #[qjs(rename = "or")]
253 pub fn or<'js>(&self, ctx: rquickjs::Ctx<'js>, other: rquickjs::Value<'js>) -> rquickjs::Result<LocatorJs> {
254 let _ = ctx;
255 let class = rquickjs::Class::<LocatorJs>::from_value(&other)
256 .map_err(|_| rquickjs::Error::new_from_js_message("Locator", "or", "expected a Locator instance"))?;
257 Ok(LocatorJs::new(self.inner.or(&class.borrow().inner)))
258 }
259
260 #[qjs(rename = "elementHandle")]
263 pub async fn element_handle(&self) -> rquickjs::Result<crate::bindings::element_handle::ElementHandleJs> {
264 let inner = self.inner.element_handle().await.into_js()?;
265 Ok(crate::bindings::element_handle::ElementHandleJs::new(inner))
266 }
267
268 #[qjs(rename = "elementHandles")]
270 pub async fn element_handles(&self) -> rquickjs::Result<Vec<crate::bindings::element_handle::ElementHandleJs>> {
271 let inner = self.inner.element_handles().await.into_js()?;
272 Ok(
273 inner
274 .into_iter()
275 .map(crate::bindings::element_handle::ElementHandleJs::new)
276 .collect(),
277 )
278 }
279
280 #[qjs(rename = "getByRole")]
281 pub fn get_by_role(
282 &self,
283 role: String,
284 options: rquickjs::function::Opt<rquickjs::Value<'_>>,
285 ) -> rquickjs::Result<LocatorJs> {
286 let opts = crate::bindings::page::parse_role_options(options)?;
287 Ok(LocatorJs::new(self.inner.get_by_role(&role, &opts)))
288 }
289
290 #[qjs(rename = "getByText")]
291 pub fn get_by_text(
292 &self,
293 text: rquickjs::Value<'_>,
294 options: rquickjs::function::Opt<rquickjs::Value<'_>>,
295 ) -> rquickjs::Result<LocatorJs> {
296 let t = crate::bindings::page::string_or_regex_from_js(text)?;
297 let opts = crate::bindings::page::parse_text_options(options);
298 Ok(LocatorJs::new(self.inner.get_by_text(&t, &opts)))
299 }
300
301 #[qjs(rename = "getByLabel")]
302 pub fn get_by_label(
303 &self,
304 text: rquickjs::Value<'_>,
305 options: rquickjs::function::Opt<rquickjs::Value<'_>>,
306 ) -> rquickjs::Result<LocatorJs> {
307 let t = crate::bindings::page::string_or_regex_from_js(text)?;
308 let opts = crate::bindings::page::parse_text_options(options);
309 Ok(LocatorJs::new(self.inner.get_by_label(&t, &opts)))
310 }
311
312 #[qjs(rename = "getByPlaceholder")]
313 pub fn get_by_placeholder(
314 &self,
315 text: rquickjs::Value<'_>,
316 options: rquickjs::function::Opt<rquickjs::Value<'_>>,
317 ) -> rquickjs::Result<LocatorJs> {
318 let t = crate::bindings::page::string_or_regex_from_js(text)?;
319 let opts = crate::bindings::page::parse_text_options(options);
320 Ok(LocatorJs::new(self.inner.get_by_placeholder(&t, &opts)))
321 }
322
323 #[qjs(rename = "getByAltText")]
324 pub fn get_by_alt_text(
325 &self,
326 text: rquickjs::Value<'_>,
327 options: rquickjs::function::Opt<rquickjs::Value<'_>>,
328 ) -> rquickjs::Result<LocatorJs> {
329 let t = crate::bindings::page::string_or_regex_from_js(text)?;
330 let opts = crate::bindings::page::parse_text_options(options);
331 Ok(LocatorJs::new(self.inner.get_by_alt_text(&t, &opts)))
332 }
333
334 #[qjs(rename = "getByTitle")]
335 pub fn get_by_title(
336 &self,
337 text: rquickjs::Value<'_>,
338 options: rquickjs::function::Opt<rquickjs::Value<'_>>,
339 ) -> rquickjs::Result<LocatorJs> {
340 let t = crate::bindings::page::string_or_regex_from_js(text)?;
341 let opts = crate::bindings::page::parse_text_options(options);
342 Ok(LocatorJs::new(self.inner.get_by_title(&t, &opts)))
343 }
344
345 #[qjs(rename = "getByTestId")]
346 pub fn get_by_test_id(&self, test_id: rquickjs::Value<'_>) -> rquickjs::Result<LocatorJs> {
347 let t = crate::bindings::page::string_or_regex_from_js(test_id)?;
348 Ok(LocatorJs::new(self.inner.get_by_test_id(&t)))
349 }
350
351 #[qjs(rename = "contentFrame")]
353 pub fn content_frame(&self) -> crate::bindings::frame_locator::FrameLocatorJs {
354 crate::bindings::frame_locator::FrameLocatorJs::new(self.inner.content_frame())
355 }
356
357 #[qjs(rename = "frameLocator")]
359 pub fn frame_locator(&self, selector: String) -> crate::bindings::frame_locator::FrameLocatorJs {
360 crate::bindings::frame_locator::FrameLocatorJs::new(self.inner.frame_locator(&selector))
361 }
362
363 #[qjs(rename = "page")]
367 pub fn page(&self, ctx: rquickjs::Ctx<'_>) -> crate::bindings::page::PageJs {
368 crate::bindings::page::pagejs_for_ctx(&ctx, self.inner.page().clone())
369 }
370
371 #[qjs(rename = "first")]
372 pub fn first(&self) -> LocatorJs {
373 LocatorJs::new(self.inner.first())
374 }
375
376 #[qjs(rename = "last")]
377 pub fn last(&self) -> LocatorJs {
378 LocatorJs::new(self.inner.last())
379 }
380
381 #[qjs(rename = "nth")]
382 pub fn nth(&self, index: i32) -> LocatorJs {
383 LocatorJs::new(self.inner.nth(index))
384 }
385
386 #[qjs(rename = "click")]
389 pub async fn click<'js>(
390 &self,
391 ctx: rquickjs::Ctx<'js>,
392 options: rquickjs::function::Opt<rquickjs::Value<'js>>,
393 ) -> rquickjs::Result<()> {
394 let opts = crate::bindings::convert::parse_click_options(&ctx, options)?;
395 self.inner.click(opts).await.into_js()
396 }
397
398 #[qjs(rename = "dblclick")]
399 pub async fn dblclick<'js>(
400 &self,
401 ctx: rquickjs::Ctx<'js>,
402 options: rquickjs::function::Opt<rquickjs::Value<'js>>,
403 ) -> rquickjs::Result<()> {
404 let opts = crate::bindings::convert::parse_dblclick_options(&ctx, options)?;
405 self.inner.dblclick(opts).await.into_js()
406 }
407
408 #[qjs(rename = "fill")]
409 pub async fn fill<'js>(
410 &self,
411 ctx: rquickjs::Ctx<'js>,
412 value: String,
413 options: rquickjs::function::Opt<rquickjs::Value<'js>>,
414 ) -> rquickjs::Result<()> {
415 let opts = crate::bindings::convert::parse_fill_options(&ctx, options)?;
416 self.inner.fill(&value, opts).await.into_js()
417 }
418
419 #[qjs(rename = "clear")]
420 pub async fn clear(&self) -> rquickjs::Result<()> {
421 self.inner.clear().await.into_js()
422 }
423
424 #[qjs(rename = "type")]
425 pub async fn type_<'js>(
426 &self,
427 ctx: rquickjs::Ctx<'js>,
428 text: String,
429 options: rquickjs::function::Opt<rquickjs::Value<'js>>,
430 ) -> rquickjs::Result<()> {
431 let opts = crate::bindings::convert::parse_type_options(&ctx, options)?;
432 self.inner.r#type(&text, opts).await.into_js()
433 }
434
435 #[qjs(rename = "pressSequentially")]
436 pub async fn press_sequentially<'js>(
437 &self,
438 ctx: rquickjs::Ctx<'js>,
439 text: String,
440 options: rquickjs::function::Opt<rquickjs::Value<'js>>,
441 ) -> rquickjs::Result<()> {
442 let opts = crate::bindings::convert::parse_type_options(&ctx, options)?;
443 self.inner.press_sequentially(&text, opts).await.into_js()
444 }
445
446 #[qjs(rename = "press")]
447 pub async fn press<'js>(
448 &self,
449 ctx: rquickjs::Ctx<'js>,
450 key: String,
451 options: rquickjs::function::Opt<rquickjs::Value<'js>>,
452 ) -> rquickjs::Result<()> {
453 let opts = crate::bindings::convert::parse_press_options(&ctx, options)?;
454 self.inner.press(&key, opts).await.into_js()
455 }
456
457 #[qjs(rename = "hover")]
458 pub async fn hover<'js>(
459 &self,
460 ctx: rquickjs::Ctx<'js>,
461 options: rquickjs::function::Opt<rquickjs::Value<'js>>,
462 ) -> rquickjs::Result<()> {
463 let opts = crate::bindings::convert::parse_hover_options(&ctx, options)?;
464 self.inner.hover(opts).await.into_js()
465 }
466
467 #[qjs(rename = "tap")]
468 pub async fn tap<'js>(
469 &self,
470 ctx: rquickjs::Ctx<'js>,
471 options: rquickjs::function::Opt<rquickjs::Value<'js>>,
472 ) -> rquickjs::Result<()> {
473 let opts = crate::bindings::convert::parse_tap_options(&ctx, options)?;
474 self.inner.tap(opts).await.into_js()
475 }
476
477 #[qjs(rename = "focus")]
478 pub async fn focus(&self) -> rquickjs::Result<()> {
479 self.inner.focus().await.into_js()
480 }
481
482 #[qjs(rename = "blur")]
483 pub async fn blur(&self) -> rquickjs::Result<()> {
484 self.inner.blur().await.into_js()
485 }
486
487 #[qjs(rename = "check")]
488 pub async fn check<'js>(
489 &self,
490 ctx: rquickjs::Ctx<'js>,
491 options: rquickjs::function::Opt<rquickjs::Value<'js>>,
492 ) -> rquickjs::Result<()> {
493 let opts = crate::bindings::convert::parse_check_options(&ctx, options)?;
494 self.inner.check(opts).await.into_js()
495 }
496
497 #[qjs(rename = "uncheck")]
498 pub async fn uncheck<'js>(
499 &self,
500 ctx: rquickjs::Ctx<'js>,
501 options: rquickjs::function::Opt<rquickjs::Value<'js>>,
502 ) -> rquickjs::Result<()> {
503 let opts = crate::bindings::convert::parse_check_options(&ctx, options)?;
504 self.inner.uncheck(opts).await.into_js()
505 }
506
507 #[qjs(rename = "setChecked")]
508 pub async fn set_checked<'js>(
509 &self,
510 ctx: rquickjs::Ctx<'js>,
511 checked: bool,
512 options: rquickjs::function::Opt<rquickjs::Value<'js>>,
513 ) -> rquickjs::Result<()> {
514 let opts = crate::bindings::convert::parse_check_options(&ctx, options)?;
515 self.inner.set_checked(checked, opts).await.into_js()
516 }
517
518 #[qjs(rename = "selectOption")]
519 pub async fn select_option<'js>(
520 &self,
521 ctx: rquickjs::Ctx<'js>,
522 values: rquickjs::Value<'js>,
523 options: rquickjs::function::Opt<rquickjs::Value<'js>>,
524 ) -> rquickjs::Result<Vec<String>> {
525 let values = crate::bindings::convert::parse_select_option_values(&ctx, values)?;
526 let opts = crate::bindings::convert::parse_select_option_options(&ctx, options)?;
527 self.inner.select_option(values, opts).await.into_js()
528 }
529
530 #[qjs(rename = "setInputFiles")]
534 pub async fn set_input_files<'js>(
535 &self,
536 ctx: rquickjs::Ctx<'js>,
537 files: rquickjs::Value<'js>,
538 options: rquickjs::function::Opt<rquickjs::Value<'js>>,
539 ) -> rquickjs::Result<()> {
540 let files = crate::bindings::convert::parse_input_files(&ctx, files)?;
541 let opts = crate::bindings::convert::parse_set_input_files_options(&ctx, options)?;
542 self.inner.set_input_files(files, opts).await.into_js()
543 }
544
545 #[qjs(rename = "scrollIntoViewIfNeeded")]
546 pub async fn scroll_into_view_if_needed(&self) -> rquickjs::Result<()> {
547 self.inner.scroll_into_view_if_needed().await.into_js()
548 }
549
550 #[qjs(rename = "waitFor")]
554 pub async fn wait_for<'js>(
555 &self,
556 ctx: rquickjs::Ctx<'js>,
557 options: rquickjs::function::Opt<rquickjs::Value<'js>>,
558 ) -> rquickjs::Result<()> {
559 #[derive(serde::Deserialize, Default)]
560 #[serde(rename_all = "camelCase", default)]
561 struct JsWaitOpts {
562 state: Option<String>,
563 timeout: Option<u64>,
564 }
565 let parsed: JsWaitOpts = match options.0 {
566 Some(v) if !v.is_undefined() && !v.is_null() => crate::bindings::convert::serde_from_js(&ctx, v)?,
567 _ => JsWaitOpts::default(),
568 };
569 self
570 .inner
571 .wait_for(ferridriver::options::WaitOptions {
572 state: parsed.state,
573 timeout: parsed.timeout,
574 })
575 .await
576 .into_js()
577 }
578
579 #[qjs(rename = "dispatchEvent")]
582 pub async fn dispatch_event<'js>(
583 &self,
584 ctx: rquickjs::Ctx<'js>,
585 event_type: String,
586 event_init: rquickjs::function::Opt<rquickjs::Value<'js>>,
587 options: rquickjs::function::Opt<rquickjs::Value<'js>>,
588 ) -> rquickjs::Result<()> {
589 let init_json = match event_init.0 {
590 Some(v) if !v.is_undefined() && !v.is_null() => {
591 Some(crate::bindings::convert::serde_from_js::<serde_json::Value>(&ctx, v)?)
592 },
593 _ => None,
594 };
595 let opts = crate::bindings::convert::parse_dispatch_event_options(&ctx, options)?;
596 self.inner.dispatch_event(&event_type, init_json, opts).await.into_js()
597 }
598
599 #[qjs(rename = "count")]
602 pub async fn count(&self) -> rquickjs::Result<i32> {
603 self
604 .inner
605 .count()
606 .await
607 .into_js()
608 .map(|c| i32::try_from(c).unwrap_or(i32::MAX))
609 }
610
611 #[qjs(rename = "screenshot")]
614 pub async fn screenshot(&self) -> rquickjs::Result<Vec<u8>> {
615 self.inner.screenshot().await.into_js()
616 }
617
618 #[qjs(rename = "textContent")]
619 pub async fn text_content(&self) -> rquickjs::Result<Option<String>> {
620 self.inner.text_content().await.into_js()
621 }
622
623 #[qjs(rename = "innerText")]
624 pub async fn inner_text(&self) -> rquickjs::Result<String> {
625 self.inner.inner_text().await.into_js()
626 }
627
628 #[qjs(rename = "innerHTML")]
629 pub async fn inner_html(&self) -> rquickjs::Result<String> {
630 self.inner.inner_html().await.into_js()
631 }
632
633 #[qjs(rename = "inputValue")]
634 pub async fn input_value(&self) -> rquickjs::Result<String> {
635 self.inner.input_value().await.into_js()
636 }
637
638 #[qjs(rename = "ariaSnapshot")]
641 pub async fn aria_snapshot<'js>(
642 &self,
643 ctx: rquickjs::Ctx<'js>,
644 options: rquickjs::function::Opt<rquickjs::Value<'js>>,
645 ) -> rquickjs::Result<String> {
646 let core_opts = match options.0 {
647 Some(v) if !v.is_undefined() && !v.is_null() => {
648 #[derive(serde::Deserialize, Default)]
649 #[serde(rename_all = "camelCase", default)]
650 struct JsAria {
651 mode: Option<String>,
652 depth: Option<i32>,
653 timeout: Option<u64>,
654 }
655 let p: JsAria = crate::bindings::convert::serde_from_js(&ctx, v)?;
656 ferridriver::options::AriaSnapshotOptions {
657 mode: Some(ferridriver::options::AriaSnapshotMode::from_opt_str(p.mode.as_deref())),
658 depth: p.depth,
659 timeout: p.timeout,
660 }
661 },
662 _ => ferridriver::options::AriaSnapshotOptions::default(),
663 };
664 self.inner.aria_snapshot(core_opts).await.into_js()
665 }
666
667 #[qjs(rename = "getAttribute")]
668 pub async fn get_attribute(&self, name: String) -> rquickjs::Result<Option<String>> {
669 self.inner.get_attribute(&name).await.into_js()
670 }
671
672 #[qjs(rename = "isVisible")]
673 pub async fn is_visible(&self) -> rquickjs::Result<bool> {
674 self.inner.is_visible().await.into_js()
675 }
676
677 #[qjs(rename = "isHidden")]
678 pub async fn is_hidden(&self) -> rquickjs::Result<bool> {
679 self.inner.is_hidden().await.into_js()
680 }
681
682 #[qjs(rename = "isEnabled")]
683 pub async fn is_enabled(&self) -> rquickjs::Result<bool> {
684 self.inner.is_enabled().await.into_js()
685 }
686
687 #[qjs(rename = "isDisabled")]
688 pub async fn is_disabled(&self) -> rquickjs::Result<bool> {
689 self.inner.is_disabled().await.into_js()
690 }
691
692 #[qjs(rename = "isChecked")]
693 pub async fn is_checked(&self) -> rquickjs::Result<bool> {
694 self.inner.is_checked().await.into_js()
695 }
696
697 #[qjs(rename = "isEditable")]
698 pub async fn is_editable(&self) -> rquickjs::Result<bool> {
699 self.inner.is_editable().await.into_js()
700 }
701
702 #[qjs(rename = "isAttached")]
703 pub async fn is_attached(&self) -> rquickjs::Result<bool> {
704 self.inner.is_attached().await.into_js()
705 }
706
707 #[qjs(rename = "dragTo")]
718 pub async fn drag_to<'js>(
719 &self,
720 ctx: rquickjs::Ctx<'js>,
721 target: rquickjs::Class<'js, LocatorJs>,
722 options: Opt<rquickjs::Value<'js>>,
723 ) -> rquickjs::Result<()> {
724 let target_inner = target.borrow().inner.clone();
725 let opts = crate::bindings::page::parse_drag_options(&ctx, options)?;
726 self.inner.drag_to(&target_inner, opts).await.into_js()
727 }
728
729 #[qjs(rename = "allTextContents")]
732 pub async fn all_text_contents(&self) -> rquickjs::Result<Vec<String>> {
733 self.inner.all_text_contents().await.into_js()
734 }
735
736 #[qjs(rename = "allInnerTexts")]
737 pub async fn all_inner_texts(&self) -> rquickjs::Result<Vec<String>> {
738 self.inner.all_inner_texts().await.into_js()
739 }
740
741 #[qjs(rename = "evaluate")]
745 pub async fn evaluate<'js>(
746 &self,
747 ctx: rquickjs::Ctx<'js>,
748 page_function: rquickjs::Value<'js>,
749 arg: rquickjs::function::Opt<rquickjs::Value<'js>>,
750 ) -> rquickjs::Result<rquickjs::Value<'js>> {
751 let (source, is_fn) = crate::bindings::convert::extract_page_function(&ctx, page_function)?;
752 let serialized = crate::bindings::convert::quickjs_arg_to_serialized(&ctx, arg.0)?;
753 let result = self.inner.evaluate(&source, serialized, is_fn, None).await.into_js()?;
754 crate::bindings::convert::serialized_value_to_quickjs(&ctx, &result)
755 }
756
757 #[qjs(rename = "evaluateHandle")]
759 pub async fn evaluate_handle<'js>(
760 &self,
761 ctx: rquickjs::Ctx<'js>,
762 page_function: rquickjs::Value<'js>,
763 arg: rquickjs::function::Opt<rquickjs::Value<'js>>,
764 ) -> rquickjs::Result<crate::bindings::js_handle::JSHandleJs> {
765 let (source, is_fn) = crate::bindings::convert::extract_page_function(&ctx, page_function)?;
766 let serialized = crate::bindings::convert::quickjs_arg_to_serialized(&ctx, arg.0)?;
767 let handle = self
768 .inner
769 .evaluate_handle(&source, serialized, is_fn, None)
770 .await
771 .into_js()?;
772 Ok(crate::bindings::js_handle::JSHandleJs::new(handle))
773 }
774
775 #[qjs(rename = "evaluateAll")]
777 pub async fn evaluate_all<'js>(
778 &self,
779 ctx: rquickjs::Ctx<'js>,
780 page_function: rquickjs::Value<'js>,
781 arg: rquickjs::function::Opt<rquickjs::Value<'js>>,
782 ) -> rquickjs::Result<rquickjs::Value<'js>> {
783 let (source, is_fn) = crate::bindings::convert::extract_page_function(&ctx, page_function)?;
784 let serialized = crate::bindings::convert::quickjs_arg_to_serialized(&ctx, arg.0)?;
785 let result = self.inner.evaluate_all(&source, serialized, is_fn).await.into_js()?;
786 crate::bindings::convert::serialized_value_to_quickjs(&ctx, &result)
787 }
788}