Add Trait for supporting other WebDriver-compatible commands (CDP, Selenium, Appium, etc)
stevepryde opened this issue · comments
Most (perhaps all) WebDriver commands simply consist of an endpoint, method, optional body, and JSON response, so this could be abstracted behind a trait. This would then allow other compatible commands to be supported in future, either as part of fantoccini
(potentially CDP) or as part of downstream crates (thirtyfour
, and potentially an appium crate later if anyone is interested).
The trait would look something like this:
pub trait WebDriverCompatibleCommand {
fn endpoint(&self, session_id: Option<String>) -> Result<url::Url, url::ParseError>;
fn method_and_body(&self) -> (http::Method, Option<serde_json::Value>);
}
That should be enough I think.
Since the WebDriverCommand
enum would then become a subset, I'd recommend implementing the trait for it, and then changing the Cmd::WebDriver(..)
variant to WebDriver(Box<dyn WebDriverCompatibleCommand>)
instead of WebDriver(Wcmd)
.
The other part that is required is to make Client::issue()
completely public, or alternatively a
pub fn issue_cmd(cmd: Box<dyn WebDriverCompatibleCmd>) -> Result<serde_json::Value, error::CmdError>
to restrict it to just this particular subset of commands.
I think this is the last remaining change required to fully support the changeover for #145 :)
It also opens the door to add support for CDP, either natively in fantoccini
or in a separate crate.
Note that actually adding support for any additional commands is not a requirement for resolving this issue.
I'm in favor of landing something like this 👍
@jonhoo Do you have a preference between making Client::issue()
public vs adding a new pub fn issue_cmd(cmd: Box<dyn WebDriverCompatibleCommand>)
for just the trait?
I think I prefer the second one just because I don't think we need/want to expose all of the other session::Cmd
variants externally
I'd prefer the latter too, yeah. Although I wonder if it should be generic rather than taking Box<dyn>
. What do you think?
I'm happy to go either way but I lean slightly towards dynamic dispatch here.
My reasoning is as follows:
- any performance implication is unlikely to matter much in an application so heavily bound to network requests (even if the webdriver server is running on the local machine).
- generics would likely increase compile time
These are probably really minor factors though.
There is a slight ergonomics cost in having to do Box::new(cmd)
but most "end users" would only interact with this via fantoccini
or another crate that calls Client::issue_cmd()
, and even in that crate it would likely be wrapped. So I think this aspect is ok.
If there are other factors I've missed let me know