/ tests / e2e / src / actor.rs
actor.rs
  1  use playwright_rs::{expect, expect_page, Page};
  2  use std::time::Duration;
  3  
  4  use crate::locators::Locator;
  5  
  6  pub type Result = std::result::Result<(), Box<dyn std::error::Error>>;
  7  
  8  pub trait Task {
  9      async fn perform(self, page: &Page) -> Result;
 10  }
 11  
 12  pub struct Actor {
 13      page: Page,
 14  }
 15  
 16  impl Actor {
 17      pub fn new(page: Page) -> Self {
 18          Self { page }
 19      }
 20  
 21      pub async fn attempts_to(&self, task: impl Task) -> Result {
 22          task.perform(&self.page).await
 23      }
 24  
 25      pub fn expect(&self, locator: Locator) -> PendingExpectation<'_> {
 26          PendingExpectation {
 27              page: &self.page,
 28              locator,
 29              negate: false,
 30              timeout: None,
 31          }
 32      }
 33  
 34      pub fn expect_page(&self) -> playwright_rs::PageExpectation {
 35          expect_page(&self.page)
 36      }
 37  
 38      pub async fn locate(&self, locator: Locator) -> playwright_rs::Locator {
 39          locator.resolve(&self.page).await
 40      }
 41  
 42      pub fn page(&self) -> &Page {
 43          &self.page
 44      }
 45  }
 46  
 47  pub struct PendingExpectation<'a> {
 48      page: &'a Page,
 49      locator: Locator,
 50      negate: bool,
 51      timeout: Option<Duration>,
 52  }
 53  
 54  macro_rules! expect_method {
 55      ($name:ident) => {
 56          pub async fn $name(self) -> Result {
 57              let (el, negate, timeout) = self.resolve().await;
 58              let mut e = expect(el);
 59              if negate { e = e.not(); }
 60              if let Some(t) = timeout { e = e.with_timeout(t); }
 61              e.$name().await?;
 62              Ok(())
 63          }
 64      };
 65      ($name:ident, $arg:ident: $ty:ty) => {
 66          pub async fn $name(self, $arg: $ty) -> Result {
 67              let (el, negate, timeout) = self.resolve().await;
 68              let mut e = expect(el);
 69              if negate { e = e.not(); }
 70              if let Some(t) = timeout { e = e.with_timeout(t); }
 71              e.$name($arg).await?;
 72              Ok(())
 73          }
 74      };
 75  }
 76  
 77  impl PendingExpectation<'_> {
 78      pub fn not(mut self) -> Self {
 79          self.negate = true;
 80          self
 81      }
 82  
 83      pub fn with_timeout(mut self, timeout: Duration) -> Self {
 84          self.timeout = Some(timeout);
 85          self
 86      }
 87  
 88      async fn resolve(self) -> (playwright_rs::Locator, bool, Option<Duration>) {
 89          let el = self.locator.resolve(self.page).await;
 90          (el, self.negate, self.timeout)
 91      }
 92  
 93      expect_method!(to_be_visible);
 94      expect_method!(to_be_hidden);
 95      expect_method!(to_be_enabled);
 96      expect_method!(to_be_disabled);
 97      expect_method!(to_be_checked);
 98      expect_method!(to_be_unchecked);
 99      expect_method!(to_be_editable);
100      expect_method!(to_be_focused);
101      expect_method!(to_have_text, expected: &str);
102      expect_method!(to_have_text_regex, pattern: &str);
103      expect_method!(to_contain_text, expected: &str);
104      expect_method!(to_contain_text_regex, pattern: &str);
105      expect_method!(to_have_value, expected: &str);
106      expect_method!(to_have_value_regex, pattern: &str);
107  
108      pub async fn to_have_screenshot(
109          self,
110          baseline_path: impl AsRef<std::path::Path>,
111          options: Option<playwright_rs::ScreenshotAssertionOptions>,
112      ) -> Result {
113          let (el, negate, timeout) = self.resolve().await;
114          let mut e = expect(el);
115          if negate { e = e.not(); }
116          if let Some(t) = timeout { e = e.with_timeout(t); }
117          e.to_have_screenshot(baseline_path, options).await?;
118          Ok(())
119      }
120  }