1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
//! ARIA snapshot implementation for Locator.
use super::aria::{aria_snapshot_js, AriaSnapshot};
use super::Locator;
use crate::error::LocatorError;
use viewpoint_js::js;
impl Locator<'_> {
/// Get an ARIA accessibility snapshot of this element.
///
/// The snapshot captures the accessible tree structure as it would be
/// exposed to assistive technologies. This is useful for accessibility testing.
///
/// # Example
///
/// ```no_run
/// use viewpoint_core::Page;
///
/// # async fn example(page: &Page) -> Result<(), viewpoint_core::CoreError> {
/// let snapshot = page.locator("form").aria_snapshot().await?;
/// println!("{}", snapshot); // YAML-like output
/// # Ok(())
/// # }
/// ```
///
/// # Errors
///
/// Returns an error if the element is not found or snapshot capture fails.
pub async fn aria_snapshot(&self) -> Result<AriaSnapshot, LocatorError> {
if self.page.is_closed() {
return Err(LocatorError::PageClosed);
}
// Get the element and evaluate ARIA snapshot
// Note: to_js_expression() returns code that evaluates to NodeList/array,
// so we need to get the first element from it
let js_selector = self.selector.to_js_expression();
let snapshot_fn = aria_snapshot_js();
let js_code = js! {
(function() {
const elements = @{js_selector};
const element = elements && elements[0] ? elements[0] : elements;
if (!element) {
return { error: "Element not found" };
}
const getSnapshot = @{snapshot_fn};
return getSnapshot(element);
})()
};
let result: viewpoint_cdp::protocol::runtime::EvaluateResult = self
.page
.connection()
.send_command(
"Runtime.evaluate",
Some(viewpoint_cdp::protocol::runtime::EvaluateParams {
expression: js_code,
object_group: None,
include_command_line_api: None,
silent: Some(true),
context_id: None,
return_by_value: Some(true),
await_promise: Some(false),
}),
Some(self.page.session_id()),
)
.await?;
if let Some(exception) = result.exception_details {
return Err(LocatorError::EvaluationError(exception.text));
}
let value = result.result.value.ok_or_else(|| {
LocatorError::EvaluationError("No result from aria snapshot".to_string())
})?;
// Check for error
if let Some(error) = value.get("error").and_then(|e| e.as_str()) {
return Err(LocatorError::NotFound(error.to_string()));
}
// Parse the snapshot
let snapshot: AriaSnapshot = serde_json::from_value(value).map_err(|e| {
LocatorError::EvaluationError(format!("Failed to parse aria snapshot: {e}"))
})?;
Ok(snapshot)
}
}