use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "strategy", content = "value")]
pub enum By {
#[serde(rename = "css")]
Css(String),
#[serde(rename = "xpath")]
XPath(String),
#[serde(rename = "text")]
Text(String),
#[serde(rename = "partialText")]
PartialText(String),
#[serde(rename = "id")]
Id(String),
#[serde(rename = "tag")]
Tag(String),
#[serde(rename = "name")]
Name(String),
#[serde(rename = "class")]
Class(String),
#[serde(rename = "linkText")]
LinkText(String),
#[serde(rename = "partialLinkText")]
PartialLinkText(String),
}
impl By {
#[inline]
pub fn css(selector: impl Into<String>) -> Self {
Self::Css(selector.into())
}
#[inline]
pub fn xpath(expr: impl Into<String>) -> Self {
Self::XPath(expr.into())
}
#[inline]
pub fn text(text: impl Into<String>) -> Self {
Self::Text(text.into())
}
#[inline]
pub fn partial_text(text: impl Into<String>) -> Self {
Self::PartialText(text.into())
}
#[inline]
pub fn id(id: impl Into<String>) -> Self {
Self::Id(id.into())
}
#[inline]
pub fn tag(tag: impl Into<String>) -> Self {
Self::Tag(tag.into())
}
#[inline]
pub fn name(name: impl Into<String>) -> Self {
Self::Name(name.into())
}
#[inline]
pub fn class(class: impl Into<String>) -> Self {
Self::Class(class.into())
}
#[inline]
pub fn link_text(text: impl Into<String>) -> Self {
Self::LinkText(text.into())
}
#[inline]
pub fn partial_link_text(text: impl Into<String>) -> Self {
Self::PartialLinkText(text.into())
}
#[must_use]
pub fn strategy(&self) -> &'static str {
match self {
Self::Css(_) => "css",
Self::XPath(_) => "xpath",
Self::Text(_) => "text",
Self::PartialText(_) => "partialText",
Self::Id(_) => "id",
Self::Tag(_) => "tag",
Self::Name(_) => "name",
Self::Class(_) => "class",
Self::LinkText(_) => "linkText",
Self::PartialLinkText(_) => "partialLinkText",
}
}
#[must_use]
pub fn value(&self) -> &str {
match self {
Self::Css(v)
| Self::XPath(v)
| Self::Text(v)
| Self::PartialText(v)
| Self::Id(v)
| Self::Tag(v)
| Self::Name(v)
| Self::Class(v)
| Self::LinkText(v)
| Self::PartialLinkText(v) => v,
}
}
}
impl From<&str> for By {
fn from(s: &str) -> Self {
Self::Css(s.to_string())
}
}
impl From<String> for By {
fn from(s: String) -> Self {
Self::Css(s)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_by_css() {
let by = By::Css("#login".to_string());
assert_eq!(by.strategy(), "css");
assert_eq!(by.value(), "#login");
}
#[test]
fn test_by_id() {
let by = By::Id("username".to_string());
assert_eq!(by.strategy(), "id");
assert_eq!(by.value(), "username");
}
#[test]
fn test_by_xpath() {
let by = By::XPath("//button".to_string());
assert_eq!(by.strategy(), "xpath");
assert_eq!(by.value(), "//button");
}
#[test]
fn test_by_text() {
let by = By::Text("Submit".to_string());
assert_eq!(by.strategy(), "text");
assert_eq!(by.value(), "Submit");
}
#[test]
fn test_from_str() {
let by: By = "#login".into();
assert!(matches!(by, By::Css(_)));
}
#[test]
fn test_builder_methods() {
assert!(matches!(By::css("#id"), By::Css(_)));
assert!(matches!(By::xpath("//div"), By::XPath(_)));
assert!(matches!(By::text("hello"), By::Text(_)));
assert!(matches!(By::id("myid"), By::Id(_)));
}
}