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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
use crate::app::SemanticApp;
use crate::selector::{ElementRef, ElementSet, Selector};
use crate::semantics::Role;
/// Chainable query builder bound to a mounted app session.
#[derive(Debug)]
pub struct Query<'a> {
pub(crate) app: &'a mut SemanticApp,
pub(crate) selector: Selector,
}
impl Query<'_> {
/// Restricts the query to nodes with the given accessibility role.
#[must_use]
pub fn role(mut self, role: Role) -> Self {
self.selector = self.selector.role(role);
self
}
/// Restricts the query to nodes with the given automation identifier.
#[must_use]
pub fn identifier(mut self, identifier: impl Into<String>) -> Self {
self.selector = self.selector.identifier(identifier);
self
}
/// Restricts the query to nodes with exactly matching labels.
#[must_use]
pub fn label(mut self, label: impl Into<String>) -> Self {
self.selector = self.selector.label(label);
self
}
/// Restricts the query to nodes whose labels contain the provided text.
#[must_use]
pub fn label_contains(mut self, label: impl Into<String>) -> Self {
self.selector = self.selector.label_contains(label);
self
}
/// Restricts the query to descendants of an element.
#[must_use]
pub fn within(mut self, handle: &ElementRef) -> Self {
self.selector = self.selector.within(handle.clone());
self
}
/// Restricts the query to direct children of an element.
#[must_use]
pub fn children_of(mut self, handle: &ElementRef) -> Self {
self.selector = self.selector.children_of(handle.clone());
self
}
/// Restricts the query to nodes with the requested enabled state.
#[must_use]
pub fn enabled(mut self, enabled: bool) -> Self {
self.selector = self.selector.enabled(enabled);
self
}
/// Restricts the query to nodes with the requested selected state.
#[must_use]
pub fn selected(mut self, selected: bool) -> Self {
self.selector = self.selector.selected(selected);
self
}
/// Restricts the query to nodes with the requested checked state.
#[must_use]
pub fn checked(mut self, checked: bool) -> Self {
self.selector = self.selector.checked(checked);
self
}
/// Restricts the query to nodes with an indeterminate checked state.
#[must_use]
pub fn mixed(mut self) -> Self {
self.selector = self.selector.mixed();
self
}
/// Restricts the query to nodes with the requested expanded state.
#[must_use]
pub fn expanded(mut self, expanded: bool) -> Self {
self.selector = self.selector.expanded(expanded);
self
}
/// Restricts the query to nodes with the requested busy state.
#[must_use]
pub fn busy(mut self, busy: bool) -> Self {
self.selector = self.selector.busy(busy);
self
}
/// Restricts the query to nodes with exactly matching values.
#[must_use]
pub fn value(mut self, value: impl Into<String>) -> Self {
self.selector = self.selector.value(value);
self
}
/// Restricts the query to nodes whose values contain the provided text.
#[must_use]
pub fn value_contains(mut self, value: impl Into<String>) -> Self {
self.selector = self.selector.value_contains(value);
self
}
/// Includes or excludes hidden nodes.
#[must_use]
pub fn hidden(mut self, hidden: bool) -> Self {
self.selector = self.selector.hidden(hidden);
self
}
/// Resolves all matching elements.
#[must_use]
pub fn all(self) -> ElementSet {
self.app.resolve_elements(&self.selector)
}
/// Resolves zero or one matching element.
///
/// # Panics
///
/// Panics if the selector resolves more than one element.
#[must_use]
pub fn optional(self) -> Option<ElementRef> {
let all = self.app.resolve_elements(&self.selector);
if all.is_empty() {
return None;
}
assert!(
all.len() <= 1,
"waterui-testing selector {} resolved {} nodes, expected at most 1; candidates: {}",
self.selector.describe(),
all.len(),
all.debug_summary(3)
);
Some(all[0].clone())
}
/// Resolves exactly one matching element.
#[must_use]
pub fn single(self) -> ElementRef {
self.app.resolve_single(&self.selector)
}
/// Returns whether at least one matching element exists.
#[must_use]
pub fn exists(self) -> bool {
!self.all().is_empty()
}
/// Asserts that at least one matching element exists.
pub fn assert_exists(self) {
self.app.assert_exists(&self.selector);
}
/// Asserts that no matching element exists.
pub fn assert_not_exists(self) {
self.app.assert_not_exists(&self.selector);
}
/// Asserts that the matching element owns `WaterUI` UI focus.
pub fn assert_ui_focus(self) {
self.app.assert_ui_focus(&self.selector);
}
/// Waits until at least one matching element exists.
#[must_use]
pub fn wait_for_existence(self, timeout: std::time::Duration) -> bool {
self.app.wait_for_existence(&self.selector, timeout)
}
/// Waits until no matching element exists.
#[must_use]
pub fn wait_for_nonexistence(self, timeout: std::time::Duration) -> bool {
self.app.wait_for_nonexistence(&self.selector, timeout)
}
/// Waits until one matching element has the expected value.
#[must_use]
pub fn wait_for_value_eq(self, value: impl Into<String>, timeout: std::time::Duration) -> bool {
self.app.wait_for_value_eq(&self.selector, value, timeout)
}
/// Performs a tap on the matching element.
///
/// # Panics
///
/// Panics if the element does not handle the click action.
pub fn tap(self) {
let element = self.app.resolve_single(&self.selector);
self.app.tap_node(element.id());
}
/// Requests accessibility focus on the matching element.
///
/// # Panics
///
/// Panics if the element does not handle the focus action.
pub fn focus(self) {
let element = self.app.resolve_single(&self.selector);
self.app.focus_node(element.id());
}
/// Sets text on the matching editable element.
///
/// # Panics
///
/// Panics if the element does not handle the set-value action.
pub fn set_text(self, value: impl Into<String>) {
let element = self.app.resolve_single(&self.selector);
self.app.set_text_node(element.id(), value);
}
/// Performs an increment action on the matching element.
///
/// # Panics
///
/// Panics if the element does not handle the increment action.
pub fn increment(self) {
let element = self.app.resolve_single(&self.selector);
self.app.increment_node(element.id());
}
/// Performs a decrement action on the matching element.
///
/// # Panics
///
/// Panics if the element does not handle the decrement action.
pub fn decrement(self) {
let element = self.app.resolve_single(&self.selector);
self.app.decrement_node(element.id());
}
/// Performs a scroll-down action on the matching element.
///
/// # Panics
///
/// Panics if the element does not handle the scroll-down action.
pub fn scroll_down(self) {
let element = self.app.resolve_single(&self.selector);
self.app.scroll_down_node(element.id());
}
/// Moves hover to the matching element center.
pub fn hover(self) {
let element = self.app.resolve_single(&self.selector);
element.hover(self.app);
}
/// Moves hover to a normalized point inside the matching element.
pub fn hover_at(self, normalized_x: f32, normalized_y: f32) {
let element = self.app.resolve_single(&self.selector);
element.hover_at(self.app, normalized_x, normalized_y);
}
/// Performs a tap at a normalized point inside the matching element.
pub fn tap_at(self, normalized_x: f32, normalized_y: f32) {
let element = self.app.resolve_single(&self.selector);
element.tap_at(self.app, normalized_x, normalized_y);
}
/// Drags from the matching element center by a delta.
pub fn drag_by(self, dx: f32, dy: f32) {
let element = self.app.resolve_single(&self.selector);
element.drag_by(self.app, dx, dy);
}
/// Drags from the matching element center by a delta with step/timing control.
pub fn drag_by_with(self, dx: f32, dy: f32, options: crate::app::DragOptions) {
let element = self.app.resolve_single(&self.selector);
element.drag_by_with(self.app, dx, dy, options);
}
/// Drags between normalized points inside the matching element.
pub fn drag_between(self, from_x: f32, from_y: f32, to_x: f32, to_y: f32) {
let element = self.app.resolve_single(&self.selector);
element.drag_between(self.app, from_x, from_y, to_x, to_y);
}
/// Applies a magnification gesture to the matching element.
pub fn magnify(self, factor: f32) {
let element = self.app.resolve_single(&self.selector);
element.magnify(self.app, factor);
}
}