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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
//! Headless rendering and accessibility-first test utilities for `WaterUI`.
//!
//! `waterui-testing` runs inside ordinary `cargo test` targets. [`ui`] builds a
//! test session; theme and render mode are orthogonal: [`UiBuilder::theme`]
//! swaps the theme package (the plain Hydrolysis test theme by default) and
//! [`UiBuilder::mount`] / [`UiBuilder::mount_offscreen`] pick between the fast
//! semantic runtime and the GPU-backed offscreen runtime.
//!
//! # `cargo test` Integration
//!
//! ```ignore
//! fn login_view() -> impl waterui::View {
//! waterui::text("Login").body()
//! }
//!
//! #[waterui::test(login_view, theme = hydrolysis_m3::install)]
//! fn login_smoke(app: &mut waterui_testing::SemanticApp) {
//! app.query()
//! .role(waterui_testing::Role::LABEL)
//! .label("Login")
//! .assert_exists();
//! }
//! ```
//!
//! For tests that own `Binding`s the view closes over, omit the view path and
//! take the configured [`UiBuilder`] by value (the manual-mount form):
//!
//! ```ignore
//! #[waterui::test(theme = hydrolysis_m3::install)]
//! fn stepper_updates(ui: waterui_testing::UiBuilder) {
//! let value = waterui::Binding::i32(2);
//! let value_for_view = value.clone();
//! let mut app = ui.mount(move || stepper("Limited", &value_for_view));
//! app.query().label("Limited").increment();
//! assert_eq!(value.get(), 3);
//! }
//! ```
//!
//! The `#[waterui::test(...)]` macro expands to a regular `#[test]`, so these
//! tests run under the normal Rust test harness and on GitHub Actions without a
//! custom runner.
//!
//! # Interactions, waits, and time
//!
//! Interactions (`tap`, `set_text`, `increment`, ...) return `()` and panic
//! when the runtime reports the accessibility action unhandled — a plain call
//! is the assertion. After every interaction the session settles to real
//! quiescence (no queued input, no spawned work, no scheduled animations or
//! patches) instead of sleeping. The animation clock is virtual: each pump
//! advances it exactly one frame, so transition sampling is deterministic;
//! [`OffscreenApp::pump_for`] lands on an exact phase of a transition, and
//! waits (`wait_for_existence`, [`SemanticApp::wait_for`]) pump hot while work
//! is scheduled and only touch wall-clock time for work outside the runtime.
//!
//! Use semantic queries to resolve an [`ElementRef`], then drive interactions
//! through that handle or use it to scope later queries with [`Query::within`].
//! Views tagged with `.a11y_id("login.submit")` resolve via
//! `Selector::identifier` / `Query::identifier`.
//!
//! # Snapshot Artifacts
//!
//! ```ignore
//! use waterui::Environment;
//! use waterui::ViewExt as _;
//! use waterui::graphics::color::Srgb;
//! use waterui_testing::TestHost;
//!
//! let host = TestHost::new(Environment::new(), 320, 180);
//! let captured = host.capture_snapshot(
//! waterui::text("Preview")
//! .body()
//! .foreground(Srgb::WHITE)
//! .background(Srgb::BLACK),
//! "docs/visual",
//! "text-preview",
//! "00_initial",
//! );
//! assert!(captured.path().is_file());
//! ```
//!
//! When `WATERUI_TEST_ARTIFACTS_DIR` is set, snapshots are written beneath that
//! directory using `WaterUI`'s canonical `<suite>/<case>/<stage>.png` layout. The
//! repository's GitHub workflows already upload and summarize those snapshot images.
pub
pub
pub use Role as AccessKitRole;
pub use ;
pub use ;
pub use FrameTiming;
pub use drain_parked_local_work;
pub use ;
pub use ;
pub use ;
pub use Query;
pub use ;
pub use ;
pub use ;
pub use ;
/// Internal async bridge used by `#[waterui::test(...)]` expansion.