use ferridriver::Frame;
use rquickjs::JsLifetime;
use rquickjs::class::Trace;
use crate::bindings::convert::{
FerriResultExt, extract_page_function, quickjs_arg_to_serialized, serialized_value_to_quickjs,
};
use crate::bindings::locator::LocatorJs;
#[derive(JsLifetime, Trace)]
#[rquickjs::class(rename = "Frame")]
pub struct FrameJs {
#[qjs(skip_trace)]
inner: Frame,
}
impl FrameJs {
#[must_use]
pub(crate) fn new(inner: Frame) -> Self {
Self { inner }
}
}
#[rquickjs::methods]
impl FrameJs {
#[qjs(rename = "name")]
pub fn name(&self) -> String {
self.inner.name()
}
#[qjs(rename = "url")]
pub fn url(&self) -> String {
self.inner.url()
}
#[qjs(rename = "isMainFrame")]
pub fn is_main_frame(&self) -> bool {
self.inner.is_main_frame()
}
#[qjs(rename = "parentFrame")]
pub fn parent_frame(&self) -> Option<FrameJs> {
self.inner.parent_frame().map(FrameJs::new)
}
#[qjs(rename = "childFrames")]
pub fn child_frames(&self) -> Vec<FrameJs> {
self.inner.child_frames().into_iter().map(FrameJs::new).collect()
}
#[qjs(rename = "isDetached")]
pub fn is_detached(&self) -> bool {
self.inner.is_detached()
}
#[qjs(rename = "evaluate")]
pub async fn evaluate<'js>(
&self,
ctx: rquickjs::Ctx<'js>,
page_function: rquickjs::Value<'js>,
arg: rquickjs::function::Opt<rquickjs::Value<'js>>,
) -> rquickjs::Result<rquickjs::Value<'js>> {
let (source, is_fn) = extract_page_function(&ctx, page_function)?;
let serialized = quickjs_arg_to_serialized(&ctx, arg.0)?;
let result = self.inner.evaluate(&source, serialized, is_fn).await.into_js()?;
serialized_value_to_quickjs(&ctx, &result)
}
#[qjs(rename = "evaluateHandle")]
pub async fn evaluate_handle<'js>(
&self,
ctx: rquickjs::Ctx<'js>,
page_function: rquickjs::Value<'js>,
arg: rquickjs::function::Opt<rquickjs::Value<'js>>,
) -> rquickjs::Result<crate::bindings::js_handle::JSHandleJs> {
let (source, is_fn) = extract_page_function(&ctx, page_function)?;
let serialized = quickjs_arg_to_serialized(&ctx, arg.0)?;
let handle = self.inner.evaluate_handle(&source, serialized, is_fn).await.into_js()?;
Ok(crate::bindings::js_handle::JSHandleJs::new(handle))
}
#[qjs(rename = "title")]
pub async fn title(&self) -> rquickjs::Result<String> {
self.inner.title().await.into_js()
}
#[qjs(rename = "content")]
pub async fn content(&self) -> rquickjs::Result<String> {
self.inner.content().await.into_js()
}
#[qjs(rename = "waitForLoadState")]
pub async fn wait_for_load_state(&self) -> rquickjs::Result<()> {
self.inner.wait_for_load_state().await.into_js()
}
#[qjs(rename = "waitForSelector")]
pub async fn wait_for_selector<'js>(
&self,
ctx: rquickjs::Ctx<'js>,
selector: String,
options: rquickjs::function::Opt<rquickjs::Value<'js>>,
) -> rquickjs::Result<Option<crate::bindings::element_handle::ElementHandleJs>> {
let opts = crate::bindings::page::parse_wait_options(&ctx, options)?;
let handle = self.inner.wait_for_selector(&selector, opts).await.into_js()?;
Ok(handle.map(crate::bindings::element_handle::ElementHandleJs::new))
}
#[qjs(rename = "locator")]
pub fn locator(&self, selector: String) -> LocatorJs {
LocatorJs::new(self.inner.locator(&selector, None))
}
#[qjs(rename = "getByRole")]
pub fn get_by_role(
&self,
role: String,
options: rquickjs::function::Opt<rquickjs::Value<'_>>,
) -> rquickjs::Result<LocatorJs> {
let opts = crate::bindings::page::parse_role_options(options)?;
Ok(LocatorJs::new(self.inner.get_by_role(&role, &opts)))
}
#[qjs(rename = "getByText")]
pub fn get_by_text(
&self,
text: rquickjs::Value<'_>,
options: rquickjs::function::Opt<rquickjs::Value<'_>>,
) -> rquickjs::Result<LocatorJs> {
let t = crate::bindings::page::string_or_regex_from_js(text)?;
let opts = crate::bindings::page::parse_text_options(options);
Ok(LocatorJs::new(self.inner.get_by_text(&t, &opts)))
}
#[qjs(rename = "getByLabel")]
pub fn get_by_label(
&self,
text: rquickjs::Value<'_>,
options: rquickjs::function::Opt<rquickjs::Value<'_>>,
) -> rquickjs::Result<LocatorJs> {
let t = crate::bindings::page::string_or_regex_from_js(text)?;
let opts = crate::bindings::page::parse_text_options(options);
Ok(LocatorJs::new(self.inner.get_by_label(&t, &opts)))
}
#[qjs(rename = "getByPlaceholder")]
pub fn get_by_placeholder(
&self,
text: rquickjs::Value<'_>,
options: rquickjs::function::Opt<rquickjs::Value<'_>>,
) -> rquickjs::Result<LocatorJs> {
let t = crate::bindings::page::string_or_regex_from_js(text)?;
let opts = crate::bindings::page::parse_text_options(options);
Ok(LocatorJs::new(self.inner.get_by_placeholder(&t, &opts)))
}
#[qjs(rename = "getByAltText")]
pub fn get_by_alt_text(
&self,
text: rquickjs::Value<'_>,
options: rquickjs::function::Opt<rquickjs::Value<'_>>,
) -> rquickjs::Result<LocatorJs> {
let t = crate::bindings::page::string_or_regex_from_js(text)?;
let opts = crate::bindings::page::parse_text_options(options);
Ok(LocatorJs::new(self.inner.get_by_alt_text(&t, &opts)))
}
#[qjs(rename = "getByTitle")]
pub fn get_by_title(
&self,
text: rquickjs::Value<'_>,
options: rquickjs::function::Opt<rquickjs::Value<'_>>,
) -> rquickjs::Result<LocatorJs> {
let t = crate::bindings::page::string_or_regex_from_js(text)?;
let opts = crate::bindings::page::parse_text_options(options);
Ok(LocatorJs::new(self.inner.get_by_title(&t, &opts)))
}
#[qjs(rename = "getByTestId")]
pub fn get_by_test_id(&self, test_id: rquickjs::Value<'_>) -> rquickjs::Result<LocatorJs> {
let t = crate::bindings::page::string_or_regex_from_js(test_id)?;
Ok(LocatorJs::new(self.inner.get_by_test_id(&t)))
}
#[qjs(rename = "frameLocator")]
pub fn frame_locator(&self, selector: String) -> crate::bindings::frame_locator::FrameLocatorJs {
crate::bindings::frame_locator::FrameLocatorJs::new(self.inner.frame_locator(&selector))
}
#[qjs(rename = "page")]
pub fn page(&self, ctx: rquickjs::Ctx<'_>) -> crate::bindings::page::PageJs {
crate::bindings::page::pagejs_for_ctx(&ctx, self.inner.page_arc().clone())
}
#[qjs(rename = "click")]
pub async fn click<'js>(
&self,
ctx: rquickjs::Ctx<'js>,
selector: String,
options: rquickjs::function::Opt<rquickjs::Value<'js>>,
) -> rquickjs::Result<()> {
let opts = crate::bindings::convert::parse_click_options(&ctx, options)?;
self.inner.click(&selector, opts).await.into_js()
}
#[qjs(rename = "dblclick")]
pub async fn dblclick<'js>(
&self,
ctx: rquickjs::Ctx<'js>,
selector: String,
options: rquickjs::function::Opt<rquickjs::Value<'js>>,
) -> rquickjs::Result<()> {
let opts = crate::bindings::convert::parse_dblclick_options(&ctx, options)?;
self.inner.dblclick(&selector, opts).await.into_js()
}
#[qjs(rename = "hover")]
pub async fn hover<'js>(
&self,
ctx: rquickjs::Ctx<'js>,
selector: String,
options: rquickjs::function::Opt<rquickjs::Value<'js>>,
) -> rquickjs::Result<()> {
let opts = crate::bindings::convert::parse_hover_options(&ctx, options)?;
self.inner.hover(&selector, opts).await.into_js()
}
#[qjs(rename = "tap")]
pub async fn tap<'js>(
&self,
ctx: rquickjs::Ctx<'js>,
selector: String,
options: rquickjs::function::Opt<rquickjs::Value<'js>>,
) -> rquickjs::Result<()> {
let opts = crate::bindings::convert::parse_tap_options(&ctx, options)?;
self.inner.tap(&selector, opts).await.into_js()
}
#[qjs(rename = "focus")]
pub async fn focus(&self, selector: String) -> rquickjs::Result<()> {
self.inner.focus(&selector).await.into_js()
}
#[qjs(rename = "fill")]
pub async fn fill<'js>(
&self,
ctx: rquickjs::Ctx<'js>,
selector: String,
value: String,
options: rquickjs::function::Opt<rquickjs::Value<'js>>,
) -> rquickjs::Result<()> {
let opts = crate::bindings::convert::parse_fill_options(&ctx, options)?;
self.inner.fill(&selector, &value, opts).await.into_js()
}
#[qjs(rename = "type")]
pub async fn type_text<'js>(
&self,
ctx: rquickjs::Ctx<'js>,
selector: String,
text: String,
options: rquickjs::function::Opt<rquickjs::Value<'js>>,
) -> rquickjs::Result<()> {
let opts = crate::bindings::convert::parse_type_options(&ctx, options)?;
self.inner.r#type(&selector, &text, opts).await.into_js()
}
#[qjs(rename = "press")]
pub async fn press<'js>(
&self,
ctx: rquickjs::Ctx<'js>,
selector: String,
key: String,
options: rquickjs::function::Opt<rquickjs::Value<'js>>,
) -> rquickjs::Result<()> {
let opts = crate::bindings::convert::parse_press_options(&ctx, options)?;
self.inner.press(&selector, &key, opts).await.into_js()
}
#[qjs(rename = "check")]
pub async fn check<'js>(
&self,
ctx: rquickjs::Ctx<'js>,
selector: String,
options: rquickjs::function::Opt<rquickjs::Value<'js>>,
) -> rquickjs::Result<()> {
let opts = crate::bindings::convert::parse_check_options(&ctx, options)?;
self.inner.check(&selector, opts).await.into_js()
}
#[qjs(rename = "uncheck")]
pub async fn uncheck<'js>(
&self,
ctx: rquickjs::Ctx<'js>,
selector: String,
options: rquickjs::function::Opt<rquickjs::Value<'js>>,
) -> rquickjs::Result<()> {
let opts = crate::bindings::convert::parse_check_options(&ctx, options)?;
self.inner.uncheck(&selector, opts).await.into_js()
}
#[qjs(rename = "setChecked")]
pub async fn set_checked<'js>(
&self,
ctx: rquickjs::Ctx<'js>,
selector: String,
checked: bool,
options: rquickjs::function::Opt<rquickjs::Value<'js>>,
) -> rquickjs::Result<()> {
let opts = crate::bindings::convert::parse_check_options(&ctx, options)?;
self.inner.set_checked(&selector, checked, opts).await.into_js()
}
#[qjs(rename = "selectOption")]
pub async fn select_option<'js>(
&self,
ctx: rquickjs::Ctx<'js>,
selector: String,
values: rquickjs::Value<'js>,
options: rquickjs::function::Opt<rquickjs::Value<'js>>,
) -> rquickjs::Result<Vec<String>> {
let values = crate::bindings::convert::parse_select_option_values(&ctx, values)?;
let opts = crate::bindings::convert::parse_select_option_options(&ctx, options)?;
self.inner.select_option(&selector, values, opts).await.into_js()
}
#[qjs(rename = "setInputFiles")]
pub async fn set_input_files<'js>(
&self,
ctx: rquickjs::Ctx<'js>,
selector: String,
files: rquickjs::Value<'js>,
options: rquickjs::function::Opt<rquickjs::Value<'js>>,
) -> rquickjs::Result<()> {
let files = crate::bindings::convert::parse_input_files(&ctx, files)?;
let opts = crate::bindings::convert::parse_set_input_files_options(&ctx, options)?;
self.inner.set_input_files(&selector, files, opts).await.into_js()
}
#[qjs(rename = "dragAndDrop")]
pub async fn drag_and_drop(&self, source: String, target: String) -> rquickjs::Result<()> {
self.inner.drag_and_drop(&source, &target, None).await.into_js()
}
#[qjs(rename = "dispatchEvent")]
pub async fn dispatch_event<'js>(
&self,
ctx: rquickjs::Ctx<'js>,
selector: String,
event_type: String,
event_init: rquickjs::function::Opt<rquickjs::Value<'js>>,
options: rquickjs::function::Opt<rquickjs::Value<'js>>,
) -> rquickjs::Result<()> {
let init_json = match event_init.0 {
Some(v) if !v.is_undefined() && !v.is_null() => {
Some(crate::bindings::convert::serde_from_js::<serde_json::Value>(&ctx, v)?)
},
_ => None,
};
let opts = crate::bindings::convert::parse_dispatch_event_options(&ctx, options)?;
self
.inner
.dispatch_event(&selector, &event_type, init_json, opts)
.await
.into_js()
}
#[qjs(rename = "textContent")]
pub async fn text_content(&self, selector: String) -> rquickjs::Result<Option<String>> {
self.inner.text_content(&selector).await.into_js()
}
#[qjs(rename = "innerText")]
pub async fn inner_text(&self, selector: String) -> rquickjs::Result<String> {
self.inner.inner_text(&selector).await.into_js()
}
#[qjs(rename = "innerHTML")]
pub async fn inner_html(&self, selector: String) -> rquickjs::Result<String> {
self.inner.inner_html(&selector).await.into_js()
}
#[qjs(rename = "getAttribute")]
pub async fn get_attribute(&self, selector: String, name: String) -> rquickjs::Result<Option<String>> {
self.inner.get_attribute(&selector, &name).await.into_js()
}
#[qjs(rename = "inputValue")]
pub async fn input_value(&self, selector: String) -> rquickjs::Result<String> {
self.inner.input_value(&selector).await.into_js()
}
#[qjs(rename = "isVisible")]
pub async fn is_visible(&self, selector: String) -> rquickjs::Result<bool> {
self.inner.is_visible(&selector).await.into_js()
}
#[qjs(rename = "isHidden")]
pub async fn is_hidden(&self, selector: String) -> rquickjs::Result<bool> {
self.inner.is_hidden(&selector).await.into_js()
}
#[qjs(rename = "isEnabled")]
pub async fn is_enabled(&self, selector: String) -> rquickjs::Result<bool> {
self.inner.is_enabled(&selector).await.into_js()
}
#[qjs(rename = "isDisabled")]
pub async fn is_disabled(&self, selector: String) -> rquickjs::Result<bool> {
self.inner.is_disabled(&selector).await.into_js()
}
#[qjs(rename = "isEditable")]
pub async fn is_editable(&self, selector: String) -> rquickjs::Result<bool> {
self.inner.is_editable(&selector).await.into_js()
}
#[qjs(rename = "isChecked")]
pub async fn is_checked(&self, selector: String) -> rquickjs::Result<bool> {
self.inner.is_checked(&selector).await.into_js()
}
}