pub(crate) use crate::imp::element_handle::Opt;
use crate::imp::{
core::*,
element_handle::ElementHandle,
js_handle::JsHandle,
page::Page,
prelude::*,
response::Response,
utils::{DocumentLoadState, File, KeyboardModifier, MouseButton, Position}
};
use std::{collections::HashSet, iter::FromIterator};
#[derive(Debug)]
pub(crate) struct Frame {
channel: ChannelOwner,
parent_frame: Option<Weak<Frame>>,
var: Mutex<Variable>,
tx: Mutex<Option<broadcast::Sender<Evt>>>
}
#[derive(Debug)]
struct Variable {
url: String,
name: String,
page: Option<Weak<Page>>,
child_frames: Vec<Weak<Frame>>,
load_states: HashSet<DocumentLoadState>
}
macro_rules! is_checked {
($f: ident, $m: literal) => {
pub(crate) async fn $f(&self, selector: &str, timeout: Option<f64>) -> ArcResult<bool> {
#[skip_serializing_none]
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct Args<'a> {
selector: &'a str,
timeout: Option<f64>
}
let args = Args { selector, timeout };
let v = send_message!(self, $m, args);
let b = first(&v)
.ok_or(Error::InvalidParams)?
.as_bool()
.ok_or(Error::InvalidParams)?;
Ok(b)
}
};
}
macro_rules! eval_handle {
($name:ident, $variant:ident, $t:ty) => {
pub(crate) async fn $name<T>(&self, expression: &str, arg: Option<T>) -> ArcResult<Weak<$t>>
where
T: Serialize
{
let handle = match self.evaluate_handle(expression, arg).await? {
Handle::$variant(handle) => handle,
_ => return Err(Error::ObjectNotFound.into())
};
Ok(handle)
}
};
}
impl Frame {
pub(crate) fn try_new(ctx: &Context, channel: ChannelOwner) -> Result<Self, Error> {
let Initializer {
name,
url,
parent_frame,
load_states
} = serde_json::from_value(channel.initializer.clone())?;
let parent_frame =
match parent_frame.map(|OnlyGuid { guid }| get_object!(ctx, &guid, Frame)) {
Some(Err(e)) => return Err(e),
Some(Ok(x)) => Some(x),
None => None
};
let var = Mutex::new(Variable {
url,
name,
page: None,
child_frames: Vec::new(),
load_states: HashSet::from_iter(load_states)
});
Ok(Self {
channel,
parent_frame,
var,
tx: Mutex::default()
})
}
pub(crate) fn hook_created(&self, this: Weak<Frame>) -> Result<(), Error> {
if let Some(parent) = &self.parent_frame {
upgrade(parent)?.add_child_frames(this);
}
Ok(())
}
pub(crate) async fn goto(&self, args: GotoArgs<'_, '_>) -> ArcResult<Option<Weak<Response>>> {
let v = send_message!(self, "goto", args);
let guid = match as_only_guid(&v) {
Some(g) => g,
None => return Ok(None)
};
let r = get_object!(self.context()?.lock().unwrap(), guid, Response)?;
Ok(Some(r))
}
pub(crate) async fn click(&self, args: ClickArgs<'_>) -> ArcResult<()> {
let _ = send_message!(self, "click", args);
Ok(())
}
pub(crate) async fn dblclick(&self, args: ClickArgs<'_>) -> ArcResult<()> {
let _ = send_message!(self, "dblclick", args);
Ok(())
}
pub(crate) async fn tap(&self, args: TapArgs<'_>) -> ArcResult<()> {
let _ = send_message!(self, "tap", args);
Ok(())
}
pub(crate) async fn fill(&self, args: FillArgs<'_, '_>) -> ArcResult<()> {
let _ = send_message!(self, "fill", args);
Ok(())
}
pub(crate) async fn focus(&self, selector: &str, timeout: Option<f64>) -> ArcResult<()> {
let args = SelectorTimeout { selector, timeout };
let _ = send_message!(self, "focus", args);
Ok(())
}
pub(crate) async fn text_content(
&self,
selector: &str,
timeout: Option<f64>
) -> ArcResult<Option<String>> {
let args = SelectorTimeout { selector, timeout };
let v = send_message!(self, "textContent", args);
let s = maybe_only_str(&v)?;
Ok(s.map(Into::into))
}
pub(crate) async fn inner_text(
&self,
selector: &str,
timeout: Option<f64>
) -> ArcResult<String> {
let args = SelectorTimeout { selector, timeout };
let v = send_message!(self, "innerText", args);
let s = only_str(&v)?;
Ok(s.into())
}
pub(crate) async fn inner_html(
&self,
selector: &str,
timeout: Option<f64>
) -> ArcResult<String> {
let args = SelectorTimeout { selector, timeout };
let v = send_message!(self, "innerHTML", args);
let s = only_str(&v)?;
Ok(s.into())
}
pub(crate) async fn get_attribute(
&self,
selector: &str,
name: &str,
timeout: Option<f64>
) -> ArcResult<Option<String>> {
#[skip_serializing_none]
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct Args<'a, 'b> {
selector: &'a str,
name: &'b str,
timeout: Option<f64>
}
let args = Args {
selector,
name,
timeout
};
let v = send_message!(self, "getAttribute", args);
let s = maybe_only_str(&v)?;
Ok(s.map(Into::into))
}
pub(crate) async fn query_selector(
&self,
selector: &str
) -> ArcResult<Option<Weak<ElementHandle>>> {
let mut args = HashMap::new();
args.insert("selector", selector);
let v = send_message!(self, "querySelector", args);
let guid = match as_only_guid(&v) {
Some(g) => g,
None => return Ok(None)
};
let e = get_object!(self.context()?.lock().unwrap(), guid, ElementHandle)?;
Ok(Some(e))
}
pub(crate) async fn query_selector_all(
&self,
selector: &str
) -> ArcResult<Vec<Weak<ElementHandle>>> {
let mut args = HashMap::new();
args.insert("selector", selector);
let v = send_message!(self, "querySelectorAll", args);
let first = first(&v).ok_or(Error::InvalidParams)?;
let elements: Vec<OnlyGuid> =
serde_json::from_value((*first).clone()).map_err(Error::Serde)?;
let es = elements
.into_iter()
.map(|OnlyGuid { guid }| {
get_object!(self.context()?.lock().unwrap(), &guid, ElementHandle)
})
.collect::<Result<Vec<_>, Error>>()?;
Ok(es)
}
pub(crate) async fn frame_element(&self) -> ArcResult<Weak<ElementHandle>> {
let v = send_message!(self, "frameElement", Map::new());
let guid = only_guid(&v)?;
let e = get_object!(self.context()?.lock().unwrap(), guid, ElementHandle)?;
Ok(e)
}
pub(crate) async fn wait_for_selector(
&self,
args: WaitForSelectorArgs<'_>
) -> ArcResult<Option<Weak<ElementHandle>>> {
let v = send_message!(self, "waitForSelector", args);
let guid = match as_only_guid(&v) {
Some(g) => g,
None => return Ok(None)
};
let e = get_object!(self.context()?.lock().unwrap(), guid, ElementHandle)?;
Ok(Some(e))
}
pub(crate) async fn title(&self) -> ArcResult<String> {
let v = send_message!(self, "title", Map::new());
let s = only_str(&v)?;
Ok(s.to_owned())
}
pub(crate) async fn r#type(&self, args: TypeArgs<'_, '_>) -> ArcResult<()> {
let _ = send_message!(self, "type", args);
Ok(())
}
pub(crate) async fn press(&self, args: PressArgs<'_, '_>) -> ArcResult<()> {
let _ = send_message!(self, "press", args);
Ok(())
}
pub(crate) async fn hover(&self, args: HoverArgs<'_>) -> ArcResult<()> {
let _ = send_message!(self, "hover", args);
Ok(())
}
is_checked!(is_checked, "isChecked");
is_checked!(is_disabled, "isDisabled");
is_checked!(is_editable, "isEditable");
is_checked!(is_enabled, "isEnabled");
is_checked!(is_hidden, "isHidden");
is_checked!(is_visible, "isVisible");
pub(crate) async fn content(&self) -> ArcResult<String> {
let v = send_message!(self, "content", Map::new());
let s = only_str(&v)?;
Ok(s.into())
}
pub(crate) async fn set_content(&self, args: SetContentArgs<'_>) -> ArcResult<()> {
let _ = send_message!(self, "setContent", args);
Ok(())
}
pub(crate) async fn check(&self, args: CheckArgs<'_>) -> ArcResult<()> {
let _ = send_message!(self, "check", args);
Ok(())
}
pub(crate) async fn uncheck(&self, args: CheckArgs<'_>) -> ArcResult<()> {
let _ = send_message!(self, "uncheck", args);
Ok(())
}
pub(crate) async fn add_script_tag(
&self,
args: AddScriptTagArgs<'_, '_, '_>
) -> ArcResult<Weak<ElementHandle>> {
let v = send_message!(self, "addScriptTag", args);
let guid = only_guid(&v)?;
let e = get_object!(self.context()?.lock().unwrap(), guid, ElementHandle)?;
Ok(e)
}
pub(crate) async fn add_style_tag(
&self,
content: &str,
url: Option<&str>
) -> ArcResult<Weak<ElementHandle>> {
let mut args = HashMap::new();
args.insert("content", content);
if let Some(url) = url {
args.insert("url", url);
}
let v = send_message!(self, "addStyleTag", args);
let guid = only_guid(&v)?;
let e = get_object!(self.context()?.lock().unwrap(), guid, ElementHandle)?;
Ok(e)
}
pub(crate) async fn eval<U>(&self, expression: &str) -> ArcResult<U>
where
U: DeserializeOwned
{
self.evaluate::<(), U>(expression, None).await
}
pub(crate) async fn evaluate<T, U>(&self, expression: &str, arg: Option<T>) -> ArcResult<U>
where
T: Serialize,
U: DeserializeOwned
{
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct Args<'a> {
expression: &'a str,
arg: Value
}
let arg = ser::to_value(&arg).map_err(Error::SerializationPwJson)?;
let args = Args { expression, arg };
let v = send_message!(self, "evaluateExpression", args);
let first = first(&v).ok_or(Error::ObjectNotFound)?;
Ok(de::from_value(first).map_err(Error::DeserializationPwJson)?)
}
async fn evaluate_handle<T>(&self, expression: &str, arg: Option<T>) -> ArcResult<Handle>
where
T: Serialize
{
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct Args<'a> {
expression: &'a str,
arg: Value
}
let arg = ser::to_value(&arg).map_err(Error::SerializationPwJson)?;
let args = Args { expression, arg };
let v = send_message!(self, "evaluateExpressionHandle", args);
let guid = only_guid(&v)?;
let e = get_object!(self.context()?.lock().unwrap(), guid, ElementHandle)
.ok()
.map(Handle::Element);
let j = get_object!(self.context()?.lock().unwrap(), guid, JsHandle)
.ok()
.map(Handle::Js);
let h = e.or(j).ok_or(Error::ObjectNotFound)?;
Ok(h)
}
eval_handle! {evaluate_element_handle, Element, ElementHandle}
eval_handle! {evaluate_js_handle, Js, JsHandle}
pub(crate) async fn evaluate_on_selector<T, U>(
&self,
selector: &str,
expression: &str,
arg: Option<T>
) -> ArcResult<U>
where
T: Serialize,
U: DeserializeOwned
{
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct Args<'a, 'b> {
selector: &'a str,
expression: &'b str,
arg: Value
}
let arg = ser::to_value(&arg).map_err(Error::SerializationPwJson)?;
let args = Args {
selector,
expression,
arg
};
let v = send_message!(self, "evalOnSelector", args);
let first = first(&v).ok_or(Error::ObjectNotFound)?;
Ok(de::from_value(first).map_err(Error::DeserializationPwJson)?)
}
pub(crate) async fn evaluate_on_selector_all<T, U>(
&self,
selector: &str,
expression: &str,
arg: Option<T>
) -> ArcResult<U>
where
T: Serialize,
U: DeserializeOwned
{
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct Args<'a, 'b> {
selector: &'a str,
expression: &'b str,
arg: Value
}
let arg = ser::to_value(&arg).map_err(Error::SerializationPwJson)?;
let args = Args {
selector,
expression,
arg
};
let v = send_message!(self, "evalOnSelectorAll", args);
let first = first(&v).ok_or(Error::ObjectNotFound)?;
Ok(de::from_value(first).map_err(Error::DeserializationPwJson)?)
}
pub(crate) async fn dispatch_event<T>(
&self,
selector: &str,
r#type: &str,
event_init: Option<T>
) -> ArcResult<()>
where
T: Serialize
{
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct Args<'a, 'b> {
selector: &'a str,
r#type: &'b str,
event_init: Value
}
let event_init = ser::to_value(&event_init).map_err(Error::SerializationPwJson)?;
let args = Args {
selector,
r#type,
event_init
};
let _ = send_message!(self, "dispatchEvent", args);
Ok(())
}
pub(crate) async fn select_option(&self, args: SelectOptionArgs<'_>) -> ArcResult<Vec<String>> {
let v = send_message!(self, "selectOption", args);
let first = first(&v).ok_or(Error::InvalidParams)?;
let ss = first
.as_array()
.ok_or(Error::InvalidParams)?
.iter()
.filter_map(|v| v.as_str())
.map(ToOwned::to_owned)
.collect();
Ok(ss)
}
pub(crate) async fn set_input_files(&self, args: SetInputFilesArgs<'_>) -> ArcResult<()> {
let _ = send_message!(self, "setInputFiles", args);
Ok(())
}
pub(crate) async fn wait_for_function(
&self,
args: WaitForFunctionArgs<'_>
) -> ArcResult<Weak<JsHandle>> {
let v = send_message!(self, "waitForFunction", args);
let guid = only_guid(&v)?;
let h = get_object!(self.context()?.lock().unwrap(), guid, JsHandle)?;
Ok(h)
}
}
impl Frame {
pub(crate) fn url(&self) -> String { self.var.lock().unwrap().url.clone() }
pub(crate) fn name(&self) -> String { self.var.lock().unwrap().name.clone() }
pub(crate) fn page(&self) -> Option<Weak<Page>> { self.var.lock().unwrap().page.clone() }
pub(crate) fn set_page(&self, page: Weak<Page>) { self.var.lock().unwrap().page = Some(page); }
pub(crate) fn parent_frame(&self) -> Option<Weak<Frame>> { self.parent_frame.clone() }
pub(crate) fn child_frames(&self) -> Vec<Weak<Frame>> {
self.var.lock().unwrap().child_frames.clone()
}
pub(crate) fn add_child_frames(&self, child: Weak<Frame>) {
self.var.lock().unwrap().child_frames.push(child);
}
fn on_navigated(&self, ctx: &Context, params: Map<String, Value>) -> Result<(), Error> {
let var = &mut self.var.lock().unwrap();
let payload: FrameNavigatedEvent = serde_json::from_value(params.into())?;
{
var.name = payload.name.clone();
var.url = payload.url.clone();
}
self.emit_event(Evt::Navigated(payload));
if let Some(page) = var.page.as_ref().and_then(|p| p.upgrade()) {
let this = get_object!(ctx, self.guid(), Frame)?;
page.on_frame_navigated(this);
}
Ok(())
}
fn on_load_state(&self, params: Map<String, Value>) -> Result<(), Error> {
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
enum Op {
Add(DocumentLoadState),
Remove(DocumentLoadState)
}
let op: Op = serde_json::from_value(params.into())?;
let load_states = &mut self.var.lock().unwrap().load_states;
match op {
Op::Add(x) => {
load_states.insert(x);
self.emit_event(Evt::LoadState(x));
}
Op::Remove(x) => {
load_states.remove(&x);
}
}
Ok(())
}
}
impl RemoteObject for Frame {
fn channel(&self) -> &ChannelOwner { &self.channel }
fn channel_mut(&mut self) -> &mut ChannelOwner { &mut self.channel }
fn handle_event(
&self,
ctx: &Context,
method: Str<Method>,
params: Map<String, Value>
) -> Result<(), Error> {
match method.as_str() {
"navigated" => self.on_navigated(ctx, params)?,
"loadstate" => self.on_load_state(params)?,
_ => {}
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub(crate) enum Evt {
LoadState(DocumentLoadState),
Navigated(FrameNavigatedEvent)
}
impl EventEmitter for Frame {
type Event = Evt;
fn tx(&self) -> Option<broadcast::Sender<Self::Event>> { self.tx.lock().unwrap().clone() }
fn set_tx(&self, tx: broadcast::Sender<Self::Event>) { *self.tx.lock().unwrap() = Some(tx); }
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum EventType {
LoadState,
Navigated
}
impl IsEvent for Evt {
type EventType = EventType;
fn event_type(&self) -> Self::EventType {
match self {
Evt::LoadState(_) => EventType::LoadState,
Evt::Navigated(_) => EventType::Navigated
}
}
}
enum Handle {
Js(Weak<JsHandle>),
Element(Weak<ElementHandle>)
}
#[skip_serializing_none]
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct GotoArgs<'a, 'b> {
url: &'a str,
pub(crate) timeout: Option<f64>,
pub(crate) wait_until: Option<DocumentLoadState>,
pub(crate) referer: Option<&'b str>
}
impl<'a> GotoArgs<'a, '_> {
pub(crate) fn new(url: &'a str) -> Self {
Self {
url,
timeout: None,
wait_until: None,
referer: None
}
}
}
#[skip_serializing_none]
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct ClickArgs<'a> {
selector: &'a str,
pub(crate) modifiers: Option<Vec<KeyboardModifier>>,
pub(crate) position: Option<Position>,
pub(crate) delay: Option<f64>,
pub(crate) button: Option<MouseButton>,
pub(crate) click_count: Option<i32>,
pub(crate) timeout: Option<f64>,
pub(crate) force: Option<bool>,
pub(crate) no_wait_after: Option<bool>,
pub(crate) trial: Option<bool>
}
impl<'a> ClickArgs<'a> {
pub(crate) fn new(selector: &'a str) -> Self {
Self {
selector,
modifiers: None,
position: None,
delay: None,
button: None,
click_count: None,
timeout: None,
force: None,
no_wait_after: None,
trial: None
}
}
}
#[skip_serializing_none]
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct WaitForSelectorArgs<'a> {
selector: &'a str,
pub(crate) timeout: Option<f64>,
pub(crate) state: Option<FrameState>
}
impl<'a> WaitForSelectorArgs<'a> {
pub(crate) fn new(selector: &'a str) -> Self {
Self {
selector,
timeout: None,
state: None
}
}
}
#[derive(Serialize)]
#[serde(rename_all = "lowercase")]
pub enum FrameState {
Attached,
Detached,
Hidden,
Visible
}
macro_rules! type_args {
($t:ident, $f:ident) => {
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct $t<'a, 'b> {
selector: &'a str,
$f: &'b str,
pub(crate) delay: Option<f64>,
pub(crate) timeout: Option<f64>,
pub(crate) no_wait_after: Option<bool>
}
impl<'a, 'b> $t<'a, 'b> {
pub(crate) fn new(selector: &'a str, $f: &'b str) -> Self {
Self {
selector,
$f,
delay: None,
timeout: None,
no_wait_after: None
}
}
}
};
}
type_args! {TypeArgs, text}
type_args! {PressArgs, key}
#[skip_serializing_none]
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct HoverArgs<'a> {
selector: &'a str,
pub(crate) modifiers: Option<Vec<KeyboardModifier>>,
pub(crate) position: Option<Position>,
pub(crate) timeout: Option<f64>,
pub(crate) force: Option<bool>,
pub(crate) trial: Option<bool>
}
impl<'a> HoverArgs<'a> {
pub(crate) fn new(selector: &'a str) -> Self {
Self {
selector,
modifiers: None,
position: None,
timeout: None,
force: None,
trial: None
}
}
}
#[skip_serializing_none]
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct SetContentArgs<'a> {
html: &'a str,
pub(crate) timeout: Option<f64>,
pub(crate) wait_until: Option<DocumentLoadState>
}
impl<'a> SetContentArgs<'a> {
pub(crate) fn new(html: &'a str) -> Self {
Self {
html,
timeout: None,
wait_until: None
}
}
}
#[skip_serializing_none]
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct TapArgs<'a> {
selector: &'a str,
pub(crate) modifiers: Option<Vec<KeyboardModifier>>,
pub(crate) position: Option<Position>,
pub(crate) timeout: Option<f64>,
pub(crate) force: Option<bool>,
pub(crate) no_wait_after: Option<bool>,
pub(crate) trial: Option<bool>
}
impl<'a> TapArgs<'a> {
pub(crate) fn new(selector: &'a str) -> Self {
Self {
selector,
modifiers: None,
position: None,
timeout: None,
force: None,
no_wait_after: None,
trial: None
}
}
}
#[skip_serializing_none]
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct FillArgs<'a, 'b> {
selector: &'a str,
value: &'b str,
pub(crate) timeout: Option<f64>,
pub(crate) no_wait_after: Option<bool>
}
impl<'a, 'b> FillArgs<'a, 'b> {
pub(crate) fn new(selector: &'a str, value: &'b str) -> Self {
Self {
selector,
value,
timeout: None,
no_wait_after: None
}
}
}
#[skip_serializing_none]
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct SelectorTimeout<'a> {
selector: &'a str,
timeout: Option<f64>
}
#[skip_serializing_none]
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct CheckArgs<'a> {
selector: &'a str,
pub(crate) position: Option<Position>,
pub(crate) timeout: Option<f64>,
pub(crate) force: Option<bool>,
pub(crate) no_wait_after: Option<bool>,
pub(crate) trial: Option<bool>
}
impl<'a> CheckArgs<'a> {
pub(crate) fn new(selector: &'a str) -> Self {
Self {
selector,
position: None,
timeout: None,
force: None,
no_wait_after: None,
trial: None
}
}
}
#[skip_serializing_none]
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct AddScriptTagArgs<'a, 'b, 'c> {
content: &'a str,
pub(crate) url: Option<&'b str>,
pub(crate) r#type: Option<&'c str>
}
impl<'a, 'b, 'c> AddScriptTagArgs<'a, 'b, 'c> {
pub(crate) fn new(content: &'a str) -> Self {
Self {
content,
url: None,
r#type: None
}
}
}
#[skip_serializing_none]
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct SelectOptionArgs<'a> {
selector: &'a str,
pub(crate) options: Option<Vec<Opt>>,
pub(crate) elements: Option<Vec<OnlyGuid>>,
pub(crate) timeout: Option<f64>,
pub(crate) no_wait_after: Option<bool>
}
impl<'a> SelectOptionArgs<'a> {
pub(crate) fn new(selector: &'a str) -> Self {
Self {
selector,
options: None,
elements: None,
timeout: None,
no_wait_after: None
}
}
}
#[skip_serializing_none]
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct SetInputFilesArgs<'a> {
selector: &'a str,
pub(crate) files: Vec<File>,
pub(crate) timeout: Option<f64>,
pub(crate) no_wait_after: Option<bool>
}
impl<'a> SetInputFilesArgs<'a> {
pub(crate) fn new(selector: &'a str) -> Self {
Self {
selector,
files: Vec::new(),
timeout: None,
no_wait_after: None
}
}
}
#[skip_serializing_none]
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct WaitForFunctionArgs<'a> {
expression: &'a str,
pub(crate) timeout: Option<f64>,
pub(crate) polling: Option<Polling>,
pub(crate) arg: Option<Value>
}
pub enum Polling {
RequestAnimationFrame,
Millis(u32)
}
impl Serialize for Polling {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer
{
match self {
Self::Millis(x) => x.serialize(serializer),
Self::RequestAnimationFrame => "raf".serialize(serializer)
}
}
}
impl<'a> WaitForFunctionArgs<'a> {
pub(crate) fn new(expression: &'a str) -> Self {
Self {
expression,
timeout: None,
polling: None,
arg: None
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct Initializer {
name: String,
url: String,
parent_frame: Option<OnlyGuid>,
load_states: Vec<DocumentLoadState>
}
#[derive(Debug, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct FrameNavigatedEvent {
url: String,
name: String,
new_document: Option<Document>,
error: Option<String>
}
#[derive(Debug, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Document {
#[serde(default)]
request: Value
}
#[cfg(test)]
mod tests {
use super::*;
use crate::imp::{
browser::{Browser, *},
browser_context::BrowserContext,
browser_type::*,
page::Page,
playwright::Playwright
};
crate::runtime_test!(eval_handle, {
let driver = Driver::install().unwrap();
let conn = Connection::run(&driver.executable()).unwrap();
let pw = Playwright::wait_initial_object(&conn).await.unwrap();
let pw: Arc<Playwright> = pw.upgrade().unwrap();
let chromium: Arc<BrowserType> = pw.chromium().upgrade().unwrap();
let browser: Weak<Browser> = chromium.launch(LaunchArgs::default()).await.unwrap();
let browser: Arc<Browser> = browser.upgrade().unwrap();
let browser_context: Weak<BrowserContext> = browser
.new_context(NewContextArgs::default())
.await
.unwrap();
let browser_context: Arc<BrowserContext> = browser_context.upgrade().unwrap();
let page: Weak<Page> = browser_context.new_page().await.unwrap();
let page: Arc<Page> = page.upgrade().unwrap();
let frame: Weak<Frame> = page.main_frame();
let frame: Arc<Frame> = frame.upgrade().unwrap();
let _handle: Weak<JsHandle> = frame
.evaluate_js_handle::<()>("() => location.href", None)
.await
.unwrap();
let _handle: Weak<ElementHandle> = frame
.evaluate_element_handle::<()>("() => document.body", None)
.await
.unwrap();
});
#[test]
fn serialize_enum() {
let s = serde_json::to_string(&Polling::Millis(3)).unwrap();
assert_eq!(s, "3");
let s = serde_json::to_string(&Polling::RequestAnimationFrame).unwrap();
assert_eq!(s, r#""raf""#);
}
}