@gtkx/testing 0.21.0 → 1.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +137 -34
- package/dist/act.d.ts +19 -0
- package/dist/act.d.ts.map +1 -0
- package/dist/act.js +56 -0
- package/dist/act.js.map +1 -0
- package/dist/bound-queries.d.ts +33 -0
- package/dist/bound-queries.d.ts.map +1 -0
- package/dist/bound-queries.js +2 -0
- package/dist/bound-queries.js.map +1 -0
- package/dist/build-queries.d.ts +16 -0
- package/dist/build-queries.d.ts.map +1 -0
- package/dist/build-queries.js +115 -0
- package/dist/build-queries.js.map +1 -0
- package/dist/cleanup-registry.d.ts +5 -0
- package/dist/cleanup-registry.d.ts.map +1 -0
- package/dist/cleanup-registry.js +21 -0
- package/dist/cleanup-registry.js.map +1 -0
- package/dist/config.d.ts +20 -52
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +17 -46
- package/dist/config.js.map +1 -1
- package/dist/editable.d.ts +8 -0
- package/dist/editable.d.ts.map +1 -0
- package/dist/editable.js +26 -0
- package/dist/editable.js.map +1 -0
- package/dist/errors.d.ts +30 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +135 -0
- package/dist/errors.js.map +1 -0
- package/dist/fire-event.d.ts +8 -25
- package/dist/fire-event.d.ts.map +1 -1
- package/dist/fire-event.js +11 -30
- package/dist/fire-event.js.map +1 -1
- package/dist/frame-sync.d.ts +4 -0
- package/dist/frame-sync.d.ts.map +1 -0
- package/dist/frame-sync.js +37 -0
- package/dist/frame-sync.js.map +1 -0
- package/dist/index.d.ts +17 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -7
- package/dist/index.js.map +1 -1
- package/dist/matchers.d.ts +59 -0
- package/dist/matchers.d.ts.map +1 -0
- package/dist/matchers.js +117 -0
- package/dist/matchers.js.map +1 -0
- package/dist/pretty-widget.d.ts +24 -26
- package/dist/pretty-widget.d.ts.map +1 -1
- package/dist/pretty-widget.js +111 -117
- package/dist/pretty-widget.js.map +1 -1
- package/dist/queries.d.ts +190 -180
- package/dist/queries.d.ts.map +1 -1
- package/dist/queries.js +291 -320
- package/dist/queries.js.map +1 -1
- package/dist/register-test-hooks.d.ts +2 -0
- package/dist/register-test-hooks.d.ts.map +1 -0
- package/dist/register-test-hooks.js +16 -0
- package/dist/register-test-hooks.js.map +1 -0
- package/dist/render-hook.d.ts +15 -35
- package/dist/render-hook.d.ts.map +1 -1
- package/dist/render-hook.js +9 -45
- package/dist/render-hook.js.map +1 -1
- package/dist/render.d.ts +13 -42
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +138 -121
- package/dist/render.js.map +1 -1
- package/dist/role-helpers.d.ts +19 -53
- package/dist/role-helpers.d.ts.map +1 -1
- package/dist/role-helpers.js +48 -63
- package/dist/role-helpers.js.map +1 -1
- package/dist/screen.d.ts +7 -63
- package/dist/screen.d.ts.map +1 -1
- package/dist/screen.js +24 -110
- package/dist/screen.js.map +1 -1
- package/dist/screenshot.d.ts +21 -23
- package/dist/screenshot.d.ts.map +1 -1
- package/dist/screenshot.js +98 -50
- package/dist/screenshot.js.map +1 -1
- package/dist/suggestions.d.ts +27 -0
- package/dist/suggestions.d.ts.map +1 -0
- package/dist/suggestions.js +61 -0
- package/dist/suggestions.js.map +1 -0
- package/dist/traversal.d.ts +12 -10
- package/dist/traversal.d.ts.map +1 -1
- package/dist/traversal.js +36 -15
- package/dist/traversal.js.map +1 -1
- package/dist/types.d.ts +115 -169
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/user-event/adjustment.d.ts +10 -0
- package/dist/user-event/adjustment.d.ts.map +1 -0
- package/dist/user-event/adjustment.js +35 -0
- package/dist/user-event/adjustment.js.map +1 -0
- package/dist/user-event/click.d.ts +8 -0
- package/dist/user-event/click.d.ts.map +1 -0
- package/dist/user-event/click.js +73 -0
- package/dist/user-event/click.js.map +1 -0
- package/dist/user-event/controller.d.ts +8 -0
- package/dist/user-event/controller.d.ts.map +1 -0
- package/dist/user-event/controller.js +31 -0
- package/dist/user-event/controller.js.map +1 -0
- package/dist/user-event/dispatch.d.ts +7 -0
- package/dist/user-event/dispatch.d.ts.map +1 -0
- package/dist/user-event/dispatch.js +11 -0
- package/dist/user-event/dispatch.js.map +1 -0
- package/dist/user-event/event-wrapper.d.ts +4 -0
- package/dist/user-event/event-wrapper.d.ts.map +1 -0
- package/dist/user-event/event-wrapper.js +59 -0
- package/dist/user-event/event-wrapper.js.map +1 -0
- package/dist/user-event/gesture.d.ts +35 -0
- package/dist/user-event/gesture.d.ts.map +1 -0
- package/dist/user-event/gesture.js +138 -0
- package/dist/user-event/gesture.js.map +1 -0
- package/dist/user-event/index.d.ts +51 -0
- package/dist/user-event/index.d.ts.map +1 -0
- package/dist/user-event/index.js +42 -0
- package/dist/user-event/index.js.map +1 -0
- package/dist/user-event/keyboard.d.ts +10 -0
- package/dist/user-event/keyboard.d.ts.map +1 -0
- package/dist/user-event/keyboard.js +204 -0
- package/dist/user-event/keyboard.js.map +1 -0
- package/dist/user-event/pointer.d.ts +10 -0
- package/dist/user-event/pointer.d.ts.map +1 -0
- package/dist/user-event/pointer.js +30 -0
- package/dist/user-event/pointer.js.map +1 -0
- package/dist/user-event/selection.d.ts +5 -0
- package/dist/user-event/selection.d.ts.map +1 -0
- package/dist/user-event/selection.js +105 -0
- package/dist/user-event/selection.js.map +1 -0
- package/dist/user-event/state.d.ts +7 -0
- package/dist/user-event/state.d.ts.map +1 -0
- package/dist/user-event/state.js +3 -0
- package/dist/user-event/state.js.map +1 -0
- package/dist/user-event/text.d.ts +18 -0
- package/dist/user-event/text.d.ts.map +1 -0
- package/dist/user-event/text.js +113 -0
- package/dist/user-event/text.js.map +1 -0
- package/dist/wait-for.d.ts +16 -36
- package/dist/wait-for.d.ts.map +1 -1
- package/dist/wait-for.js +74 -70
- package/dist/wait-for.js.map +1 -1
- package/dist/widget-accessible-properties.d.ts +34 -0
- package/dist/widget-accessible-properties.d.ts.map +1 -0
- package/dist/widget-accessible-properties.js +260 -0
- package/dist/widget-accessible-properties.js.map +1 -0
- package/dist/within.d.ts +10 -26
- package/dist/within.d.ts.map +1 -1
- package/dist/within.js +16 -25
- package/dist/within.js.map +1 -1
- package/package.json +23 -12
- package/src/act.ts +77 -0
- package/src/bound-queries.ts +37 -0
- package/src/build-queries.ts +226 -0
- package/src/cleanup-registry.ts +27 -0
- package/src/config.ts +35 -62
- package/src/editable.ts +37 -0
- package/src/errors.ts +191 -0
- package/src/fire-event.ts +13 -38
- package/src/frame-sync.ts +51 -0
- package/src/index.ts +58 -15
- package/src/matchers.ts +251 -0
- package/src/pretty-widget.ts +163 -130
- package/src/queries.ts +485 -396
- package/src/register-test-hooks.ts +19 -0
- package/src/render-hook.tsx +38 -45
- package/src/render.tsx +192 -155
- package/src/role-helpers.ts +65 -72
- package/src/screen.ts +26 -114
- package/src/screenshot.ts +128 -56
- package/src/suggestions.ts +106 -0
- package/src/traversal.ts +56 -22
- package/src/types.ts +144 -172
- package/src/user-event/adjustment.ts +62 -0
- package/src/user-event/click.ts +99 -0
- package/src/user-event/controller.ts +58 -0
- package/src/user-event/dispatch.ts +25 -0
- package/src/user-event/event-wrapper.ts +80 -0
- package/src/user-event/gesture.ts +239 -0
- package/src/user-event/index.ts +81 -0
- package/src/user-event/keyboard.ts +290 -0
- package/src/user-event/pointer.ts +46 -0
- package/src/user-event/selection.ts +159 -0
- package/src/user-event/state.ts +8 -0
- package/src/user-event/text.ts +172 -0
- package/src/wait-for.ts +117 -78
- package/src/widget-accessible-properties.ts +388 -0
- package/src/within.ts +29 -27
- package/dist/bind-queries.d.ts +0 -14
- package/dist/bind-queries.d.ts.map +0 -1
- package/dist/bind-queries.js +0 -29
- package/dist/bind-queries.js.map +0 -1
- package/dist/error-builder.d.ts +0 -28
- package/dist/error-builder.d.ts.map +0 -1
- package/dist/error-builder.js +0 -81
- package/dist/error-builder.js.map +0 -1
- package/dist/timing.d.ts +0 -18
- package/dist/timing.d.ts.map +0 -1
- package/dist/timing.js +0 -18
- package/dist/timing.js.map +0 -1
- package/dist/user-event.d.ts +0 -138
- package/dist/user-event.d.ts.map +0 -1
- package/dist/user-event.js +0 -411
- package/dist/user-event.js.map +0 -1
- package/dist/widget-text.d.ts +0 -69
- package/dist/widget-text.d.ts.map +0 -1
- package/dist/widget-text.js +0 -177
- package/dist/widget-text.js.map +0 -1
- package/dist/widget.d.ts +0 -3
- package/dist/widget.d.ts.map +0 -1
- package/dist/widget.js +0 -13
- package/dist/widget.js.map +0 -1
- package/src/bind-queries.ts +0 -52
- package/src/error-builder.ts +0 -102
- package/src/timing.ts +0 -17
- package/src/user-event.ts +0 -492
- package/src/widget-text.ts +0 -202
- package/src/widget.ts +0 -15
package/src/queries.ts
CHANGED
|
@@ -1,52 +1,312 @@
|
|
|
1
|
-
import * as Gtk from "@gtkx/
|
|
2
|
-
import {
|
|
1
|
+
import * as Gtk from "@gtkx/gi/gtk";
|
|
2
|
+
import type { ByRoleOptions, ByRoleValue, Matcher, MatcherOptions, NormalizerFn, NormalizerOptions } from "./types.js";
|
|
3
|
+
import { buildQueries, type BuiltQueries, type QueryAllBy } from "./build-queries.js";
|
|
4
|
+
import { multipleFoundError, notFoundError } from "./errors.js";
|
|
3
5
|
import { type Container, findAll, traverse } from "./traversal.js";
|
|
4
|
-
import type { ByRoleOptions, TextMatch, TextMatchOptions } from "./types.js";
|
|
5
|
-
import { waitFor } from "./wait-for.js";
|
|
6
6
|
import {
|
|
7
7
|
getWidgetAccessibleName,
|
|
8
|
+
getWidgetBusyState,
|
|
8
9
|
getWidgetCheckedState,
|
|
10
|
+
getWidgetDescription,
|
|
11
|
+
getWidgetDisplayValue,
|
|
9
12
|
getWidgetExpandedState,
|
|
13
|
+
getWidgetLabelledByText,
|
|
14
|
+
getWidgetLabelText,
|
|
15
|
+
getWidgetLevel,
|
|
10
16
|
getWidgetName,
|
|
17
|
+
getWidgetOwnLabel,
|
|
18
|
+
getWidgetPlaceholderText,
|
|
11
19
|
getWidgetPressedState,
|
|
12
20
|
getWidgetSelectedState,
|
|
13
|
-
|
|
14
|
-
|
|
21
|
+
getWidgetValue,
|
|
22
|
+
isInaccessible,
|
|
23
|
+
} from "./widget-accessible-properties.js";
|
|
24
|
+
|
|
25
|
+
type QueryFamilyReturns = {
|
|
26
|
+
queryBy: Gtk.Widget | null;
|
|
27
|
+
queryAllBy: Gtk.Widget[];
|
|
28
|
+
getBy: Gtk.Widget;
|
|
29
|
+
getAllBy: Gtk.Widget[];
|
|
30
|
+
findBy: Promise<Gtk.Widget>;
|
|
31
|
+
findAllBy: Promise<Gtk.Widget[]>;
|
|
32
|
+
};
|
|
15
33
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
34
|
+
type NamedFamily<Suffix extends string, Args extends unknown[]> = {
|
|
35
|
+
[K in keyof QueryFamilyReturns as `${K & string}${Suffix}`]: (
|
|
36
|
+
container: Container,
|
|
37
|
+
...args: Args
|
|
38
|
+
) => QueryFamilyReturns[K];
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
type BuiltinQueries = NamedFamily<"Role", [role: Gtk.AccessibleRole, options?: ByRoleOptions]> &
|
|
42
|
+
NamedFamily<"LabelText", [text: Matcher, options?: MatcherOptions]> &
|
|
43
|
+
NamedFamily<"Text", [text: Matcher, options?: MatcherOptions]> &
|
|
44
|
+
NamedFamily<"Name", [name: Matcher, options?: MatcherOptions]> &
|
|
45
|
+
NamedFamily<"PlaceholderText", [text: Matcher, options?: MatcherOptions]> &
|
|
46
|
+
NamedFamily<"DisplayValue", [value: Matcher, options?: MatcherOptions]>;
|
|
47
|
+
|
|
48
|
+
const roleQueries = nameQueryFamily(
|
|
49
|
+
"Role",
|
|
50
|
+
queryAllByRole,
|
|
51
|
+
buildQueries<[role: Gtk.AccessibleRole, options?: ByRoleOptions]>(
|
|
52
|
+
"Role",
|
|
53
|
+
queryAllByRole,
|
|
54
|
+
(container, matches, role, options) =>
|
|
55
|
+
multipleFoundError(container, { queryType: "role", role, options }, matches),
|
|
56
|
+
(container, role, options) => notFoundError(container, { queryType: "role", role, options }),
|
|
57
|
+
),
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const labelTextQueries = nameQueryFamily(
|
|
61
|
+
"LabelText",
|
|
62
|
+
queryAllByLabelText,
|
|
63
|
+
buildQueries<[text: Matcher, options?: MatcherOptions]>(
|
|
64
|
+
"LabelText",
|
|
65
|
+
queryAllByLabelText,
|
|
66
|
+
(container, matches, text) => multipleFoundError(container, { queryType: "labelText", text }, matches),
|
|
67
|
+
(container, text) => notFoundError(container, { queryType: "labelText", text }),
|
|
68
|
+
),
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const textQueries = nameQueryFamily(
|
|
72
|
+
"Text",
|
|
73
|
+
queryAllByText,
|
|
74
|
+
buildQueries<[text: Matcher, options?: MatcherOptions]>(
|
|
75
|
+
"Text",
|
|
76
|
+
queryAllByText,
|
|
77
|
+
(container, matches, text) => multipleFoundError(container, { queryType: "text", text }, matches),
|
|
78
|
+
(container, text) => notFoundError(container, { queryType: "text", text }),
|
|
79
|
+
),
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const nameQueries = nameQueryFamily(
|
|
83
|
+
"Name",
|
|
84
|
+
queryAllByName,
|
|
85
|
+
buildQueries<[name: Matcher, options?: MatcherOptions]>(
|
|
86
|
+
"Name",
|
|
87
|
+
queryAllByName,
|
|
88
|
+
(container, matches, name) => multipleFoundError(container, { queryType: "name", name }, matches),
|
|
89
|
+
(container, name) => notFoundError(container, { queryType: "name", name }),
|
|
90
|
+
),
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
const placeholderTextQueries = nameQueryFamily(
|
|
94
|
+
"PlaceholderText",
|
|
95
|
+
queryAllByPlaceholderText,
|
|
96
|
+
buildQueries<[text: Matcher, options?: MatcherOptions]>(
|
|
97
|
+
"PlaceholderText",
|
|
98
|
+
queryAllByPlaceholderText,
|
|
99
|
+
(container, matches, text) => multipleFoundError(container, { queryType: "placeholderText", text }, matches),
|
|
100
|
+
(container, text) => notFoundError(container, { queryType: "placeholderText", text }),
|
|
101
|
+
),
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const displayValueQueries = nameQueryFamily(
|
|
105
|
+
"DisplayValue",
|
|
106
|
+
queryAllByDisplayValue,
|
|
107
|
+
buildQueries<[value: Matcher, options?: MatcherOptions]>(
|
|
108
|
+
"DisplayValue",
|
|
109
|
+
queryAllByDisplayValue,
|
|
110
|
+
(container, matches, value) => multipleFoundError(container, { queryType: "displayValue", value }, matches),
|
|
111
|
+
(container, value) => notFoundError(container, { queryType: "displayValue", value }),
|
|
112
|
+
),
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
const builtinQueries: BuiltinQueries = {
|
|
116
|
+
...roleQueries,
|
|
117
|
+
...labelTextQueries,
|
|
118
|
+
...textQueries,
|
|
119
|
+
...nameQueries,
|
|
120
|
+
...placeholderTextQueries,
|
|
121
|
+
...displayValueQueries,
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Returns the single widget with a matching accessible role and options, or null when none match.
|
|
126
|
+
* Throws when more than one matches.
|
|
127
|
+
*/
|
|
128
|
+
const queryByRole: BuiltinQueries["queryByRole"] = roleQueries.queryByRole;
|
|
129
|
+
/** Returns every widget with a matching accessible role and options. Throws when none match. */
|
|
130
|
+
const getAllByRole: BuiltinQueries["getAllByRole"] = roleQueries.getAllByRole;
|
|
131
|
+
/**
|
|
132
|
+
* Returns the single widget with a matching accessible role and options.
|
|
133
|
+
* Throws when none or more than one matches.
|
|
134
|
+
*/
|
|
135
|
+
const getByRole: BuiltinQueries["getByRole"] = roleQueries.getByRole;
|
|
136
|
+
/**
|
|
137
|
+
* Waits for and returns every widget with a matching accessible role and options, retrying until at
|
|
138
|
+
* least one appears or the timeout elapses.
|
|
139
|
+
*/
|
|
140
|
+
const findAllByRole: BuiltinQueries["findAllByRole"] = roleQueries.findAllByRole;
|
|
141
|
+
/**
|
|
142
|
+
* Waits for and returns the single widget with a matching accessible role and options, retrying
|
|
143
|
+
* until it appears or the timeout elapses. Rejects when none or more than one matches.
|
|
144
|
+
*/
|
|
145
|
+
const findByRole: BuiltinQueries["findByRole"] = roleQueries.findByRole;
|
|
146
|
+
/**
|
|
147
|
+
* Returns the single widget with matching associated label text, or null when none match.
|
|
148
|
+
* Throws when more than one matches.
|
|
149
|
+
*/
|
|
150
|
+
const queryByLabelText: BuiltinQueries["queryByLabelText"] = labelTextQueries.queryByLabelText;
|
|
151
|
+
/** Returns every widget with matching associated label text. Throws when none match. */
|
|
152
|
+
const getAllByLabelText: BuiltinQueries["getAllByLabelText"] = labelTextQueries.getAllByLabelText;
|
|
153
|
+
/** Returns the single widget with matching associated label text. Throws when none or more than one matches. */
|
|
154
|
+
const getByLabelText: BuiltinQueries["getByLabelText"] = labelTextQueries.getByLabelText;
|
|
155
|
+
/**
|
|
156
|
+
* Waits for and returns every widget with matching associated label text, retrying until at least
|
|
157
|
+
* one appears or the timeout elapses.
|
|
158
|
+
*/
|
|
159
|
+
const findAllByLabelText: BuiltinQueries["findAllByLabelText"] = labelTextQueries.findAllByLabelText;
|
|
160
|
+
/**
|
|
161
|
+
* Waits for and returns the single widget with matching associated label text, retrying until it
|
|
162
|
+
* appears or the timeout elapses. Rejects when none or more than one matches.
|
|
163
|
+
*/
|
|
164
|
+
const findByLabelText: BuiltinQueries["findByLabelText"] = labelTextQueries.findByLabelText;
|
|
165
|
+
/**
|
|
166
|
+
* Returns the single widget with matching rendered text content, or null when none match.
|
|
167
|
+
* Throws when more than one matches.
|
|
168
|
+
*/
|
|
169
|
+
const queryByText: BuiltinQueries["queryByText"] = textQueries.queryByText;
|
|
170
|
+
/** Returns every widget with matching rendered text content. Throws when none match. */
|
|
171
|
+
const getAllByText: BuiltinQueries["getAllByText"] = textQueries.getAllByText;
|
|
172
|
+
/** Returns the single widget with matching rendered text content. Throws when none or more than one matches. */
|
|
173
|
+
const getByText: BuiltinQueries["getByText"] = textQueries.getByText;
|
|
174
|
+
/**
|
|
175
|
+
* Waits for and returns every widget with matching rendered text content, retrying until at least
|
|
176
|
+
* one appears or the timeout elapses.
|
|
177
|
+
*/
|
|
178
|
+
const findAllByText: BuiltinQueries["findAllByText"] = textQueries.findAllByText;
|
|
179
|
+
/**
|
|
180
|
+
* Waits for and returns the single widget with matching rendered text content, retrying until it
|
|
181
|
+
* appears or the timeout elapses. Rejects when none or more than one matches.
|
|
182
|
+
*/
|
|
183
|
+
const findByText: BuiltinQueries["findByText"] = textQueries.findByText;
|
|
184
|
+
/**
|
|
185
|
+
* Returns the single widget with a matching widget name, or null when none match.
|
|
186
|
+
* Throws when more than one matches.
|
|
187
|
+
*/
|
|
188
|
+
const queryByName: BuiltinQueries["queryByName"] = nameQueries.queryByName;
|
|
189
|
+
/** Returns every widget with a matching widget name. Throws when none match. */
|
|
190
|
+
const getAllByName: BuiltinQueries["getAllByName"] = nameQueries.getAllByName;
|
|
191
|
+
/** Returns the single widget with a matching widget name. Throws when none or more than one matches. */
|
|
192
|
+
const getByName: BuiltinQueries["getByName"] = nameQueries.getByName;
|
|
193
|
+
/**
|
|
194
|
+
* Waits for and returns every widget with a matching widget name, retrying until at least one
|
|
195
|
+
* appears or the timeout elapses.
|
|
196
|
+
*/
|
|
197
|
+
const findAllByName: BuiltinQueries["findAllByName"] = nameQueries.findAllByName;
|
|
198
|
+
/**
|
|
199
|
+
* Waits for and returns the single widget with a matching widget name, retrying until it appears or
|
|
200
|
+
* the timeout elapses. Rejects when none or more than one matches.
|
|
201
|
+
*/
|
|
202
|
+
const findByName: BuiltinQueries["findByName"] = nameQueries.findByName;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Returns the single widget with matching placeholder text, or null when none match.
|
|
206
|
+
* Throws when more than one matches.
|
|
207
|
+
*/
|
|
208
|
+
const queryByPlaceholderText: BuiltinQueries["queryByPlaceholderText"] =
|
|
209
|
+
placeholderTextQueries.queryByPlaceholderText;
|
|
210
|
+
|
|
211
|
+
/** Returns every widget with matching placeholder text. Throws when none match. */
|
|
212
|
+
const getAllByPlaceholderText: BuiltinQueries["getAllByPlaceholderText"] =
|
|
213
|
+
placeholderTextQueries.getAllByPlaceholderText;
|
|
20
214
|
|
|
21
|
-
|
|
22
|
-
|
|
215
|
+
/** Returns the single widget with matching placeholder text. Throws when none or more than one matches. */
|
|
216
|
+
const getByPlaceholderText: BuiltinQueries["getByPlaceholderText"] = placeholderTextQueries.getByPlaceholderText;
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Waits for and returns every widget with matching placeholder text, retrying until at least one
|
|
220
|
+
* appears or the timeout elapses.
|
|
221
|
+
*/
|
|
222
|
+
const findAllByPlaceholderText: BuiltinQueries["findAllByPlaceholderText"] =
|
|
223
|
+
placeholderTextQueries.findAllByPlaceholderText;
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Waits for and returns the single widget with matching placeholder text, retrying until it appears
|
|
227
|
+
* or the timeout elapses. Rejects when none or more than one matches.
|
|
228
|
+
*/
|
|
229
|
+
const findByPlaceholderText: BuiltinQueries["findByPlaceholderText"] =
|
|
230
|
+
placeholderTextQueries.findByPlaceholderText;
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Returns the single widget with a matching display value, or null when none match.
|
|
234
|
+
* Throws when more than one matches.
|
|
235
|
+
*/
|
|
236
|
+
const queryByDisplayValue: BuiltinQueries["queryByDisplayValue"] = displayValueQueries.queryByDisplayValue;
|
|
237
|
+
/** Returns every widget with a matching display value. Throws when none match. */
|
|
238
|
+
const getAllByDisplayValue: BuiltinQueries["getAllByDisplayValue"] = displayValueQueries.getAllByDisplayValue;
|
|
239
|
+
/** Returns the single widget with a matching display value. Throws when none or more than one matches. */
|
|
240
|
+
const getByDisplayValue: BuiltinQueries["getByDisplayValue"] = displayValueQueries.getByDisplayValue;
|
|
241
|
+
/**
|
|
242
|
+
* Waits for and returns every widget with a matching display value, retrying until at least one
|
|
243
|
+
* appears or the timeout elapses.
|
|
244
|
+
*/
|
|
245
|
+
const findAllByDisplayValue: BuiltinQueries["findAllByDisplayValue"] = displayValueQueries.findAllByDisplayValue;
|
|
246
|
+
/**
|
|
247
|
+
* Waits for and returns the single widget with a matching display value, retrying until it appears
|
|
248
|
+
* or the timeout elapses. Rejects when none or more than one matches.
|
|
249
|
+
*/
|
|
250
|
+
const findByDisplayValue: BuiltinQueries["findByDisplayValue"] = displayValueQueries.findByDisplayValue;
|
|
23
251
|
|
|
252
|
+
/**
|
|
253
|
+
* Builds the default text normalizer, which optionally trims surrounding whitespace and collapses
|
|
254
|
+
* runs of whitespace into single spaces.
|
|
255
|
+
* @param options Toggles for trimming and whitespace collapsing.
|
|
256
|
+
* @returns A function that normalizes a string for comparison against a matcher.
|
|
257
|
+
*/
|
|
258
|
+
const getDefaultNormalizer = ({
|
|
259
|
+
trim = true,
|
|
260
|
+
collapseWhitespace = true,
|
|
261
|
+
}: NormalizerOptions = {}): NormalizerFn => {
|
|
24
262
|
return (text: string): string => {
|
|
25
263
|
let result = text;
|
|
264
|
+
|
|
26
265
|
if (trim) {
|
|
27
266
|
result = result.trim();
|
|
28
267
|
}
|
|
29
268
|
|
|
30
269
|
if (collapseWhitespace) {
|
|
31
|
-
result = result.
|
|
270
|
+
result = result.replaceAll(/\s+/g, " ");
|
|
32
271
|
}
|
|
33
272
|
|
|
34
273
|
return result;
|
|
35
274
|
};
|
|
36
275
|
};
|
|
37
276
|
|
|
38
|
-
const
|
|
277
|
+
const buildNormalizer = (options?: MatcherOptions): NormalizerFn => {
|
|
278
|
+
const { normalizer, trim, collapseWhitespace } = options ?? {};
|
|
279
|
+
|
|
280
|
+
if (!normalizer) {
|
|
281
|
+
return getDefaultNormalizer({ trim, collapseWhitespace });
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (trim !== undefined || collapseWhitespace !== undefined) {
|
|
285
|
+
throw new Error(
|
|
286
|
+
"trim and collapseWhitespace are not supported with a normalizer. " +
|
|
287
|
+
"If you want to use the default trim and collapseWhitespace logic in your normalizer, " +
|
|
288
|
+
"use \"getDefaultNormalizer({ trim, collapseWhitespace })\" and compose that into your normalizer",
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return normalizer;
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
const normalizeText = (text: string, options?: MatcherOptions): string => {
|
|
39
296
|
const normalizer = buildNormalizer(options);
|
|
297
|
+
|
|
40
298
|
return normalizer(text);
|
|
41
299
|
};
|
|
42
300
|
|
|
43
|
-
const
|
|
301
|
+
const isTextMatch = (
|
|
44
302
|
actual: string | null,
|
|
45
|
-
expected:
|
|
303
|
+
expected: Matcher,
|
|
46
304
|
widget: Gtk.Widget,
|
|
47
|
-
options?:
|
|
305
|
+
options?: MatcherOptions,
|
|
48
306
|
): boolean => {
|
|
49
|
-
if (actual === null)
|
|
307
|
+
if (actual === null) {
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
50
310
|
|
|
51
311
|
const normalizedActual = normalizeText(actual, options);
|
|
52
312
|
|
|
@@ -56,452 +316,281 @@ const matchText = (
|
|
|
56
316
|
|
|
57
317
|
if (expected instanceof RegExp) {
|
|
58
318
|
expected.lastIndex = 0;
|
|
319
|
+
|
|
59
320
|
return expected.test(normalizedActual);
|
|
60
321
|
}
|
|
61
322
|
|
|
62
|
-
const normalizedExpected = normalizeText(expected, options);
|
|
63
|
-
const
|
|
64
|
-
|
|
323
|
+
const normalizedExpected = normalizeText(String(expected), options);
|
|
324
|
+
const isExact = options?.exact ?? true;
|
|
325
|
+
|
|
326
|
+
return isExact
|
|
65
327
|
? normalizedActual === normalizedExpected
|
|
66
328
|
: normalizedActual.toLowerCase().includes(normalizedExpected.toLowerCase());
|
|
67
329
|
};
|
|
68
330
|
|
|
69
|
-
const
|
|
70
|
-
if (
|
|
71
|
-
|
|
72
|
-
if (options.name !== undefined) {
|
|
73
|
-
const text = getWidgetAccessibleName(widget);
|
|
74
|
-
if (!matchText(text, options.name, widget, options)) return false;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (options.checked !== undefined) {
|
|
78
|
-
const checked = getWidgetCheckedState(widget);
|
|
79
|
-
if (checked !== options.checked) return false;
|
|
331
|
+
const hasMatchingAccessibleName = (widget: Gtk.Widget, options: ByRoleOptions): boolean => {
|
|
332
|
+
if (options.name === undefined) {
|
|
333
|
+
return true;
|
|
80
334
|
}
|
|
81
335
|
|
|
82
|
-
|
|
83
|
-
const pressed = getWidgetPressedState(widget);
|
|
84
|
-
if (pressed !== options.pressed) return false;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (options.expanded !== undefined) {
|
|
88
|
-
const expanded = getWidgetExpandedState(widget);
|
|
89
|
-
if (expanded !== options.expanded) return false;
|
|
90
|
-
}
|
|
336
|
+
const text = getWidgetAccessibleName(widget);
|
|
91
337
|
|
|
92
|
-
|
|
93
|
-
const selected = getWidgetSelectedState(widget);
|
|
94
|
-
if (selected !== options.selected) return false;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return true;
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Finds all elements matching a role without throwing.
|
|
102
|
-
*
|
|
103
|
-
* @param container - The container to search within
|
|
104
|
-
* @param role - The GTK accessible role to match
|
|
105
|
-
* @param options - Query options including name and state filters
|
|
106
|
-
* @returns Array of matching widgets (empty if none found)
|
|
107
|
-
*/
|
|
108
|
-
export const queryAllByRole = (
|
|
109
|
-
container: Container,
|
|
110
|
-
role: Gtk.AccessibleRole,
|
|
111
|
-
options?: ByRoleOptions,
|
|
112
|
-
): Gtk.Widget[] => {
|
|
113
|
-
return findAll(container, (node) => {
|
|
114
|
-
if (node.getAccessibleRole() !== role) return false;
|
|
115
|
-
return matchByRoleOptions(node, options);
|
|
116
|
-
});
|
|
338
|
+
return isTextMatch(text, options.name, widget, options);
|
|
117
339
|
};
|
|
118
340
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
*
|
|
122
|
-
* @param container - The container to search within
|
|
123
|
-
* @param role - The GTK accessible role to match
|
|
124
|
-
* @param options - Query options including name and state filters
|
|
125
|
-
* @returns The matching widget or null if not found
|
|
126
|
-
* @throws Error if multiple elements match
|
|
127
|
-
*/
|
|
128
|
-
export const queryByRole = (
|
|
129
|
-
container: Container,
|
|
130
|
-
role: Gtk.AccessibleRole,
|
|
131
|
-
options?: ByRoleOptions,
|
|
132
|
-
): Gtk.Widget | null => {
|
|
133
|
-
const matches = queryAllByRole(container, role, options);
|
|
341
|
+
const isNumericValueMatch = (expected: number | undefined, actual: number | null): boolean =>
|
|
342
|
+
expected === undefined || actual === expected;
|
|
134
343
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
344
|
+
const hasMatchingAccessibleValue = (widget: Gtk.Widget, value: ByRoleValue, options: ByRoleOptions): boolean => {
|
|
345
|
+
const actual = getWidgetValue(widget);
|
|
138
346
|
|
|
139
|
-
|
|
140
|
-
|
|
347
|
+
const numericChecks: [number | undefined, number | null][] = [
|
|
348
|
+
[value.now, actual.now],
|
|
349
|
+
[value.min, actual.min],
|
|
350
|
+
[value.max, actual.max],
|
|
351
|
+
];
|
|
141
352
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
* Uses GtkLabel's mnemonic widget association to find form elements
|
|
146
|
-
* by their label text. Only returns widgets that are properly labelled
|
|
147
|
-
* via GtkLabel's mnemonic-widget property.
|
|
148
|
-
*
|
|
149
|
-
* @param container - The container to search within
|
|
150
|
-
* @param text - Label text to match (string, RegExp, or custom matcher)
|
|
151
|
-
* @param options - Query options including normalization
|
|
152
|
-
* @returns Array of labelled widgets (empty if none found)
|
|
153
|
-
*/
|
|
154
|
-
export const queryAllByLabelText = (
|
|
155
|
-
container: Container,
|
|
156
|
-
text: TextMatch,
|
|
157
|
-
options?: TextMatchOptions,
|
|
158
|
-
): Gtk.Widget[] => {
|
|
159
|
-
const results: Gtk.Widget[] = [];
|
|
160
|
-
|
|
161
|
-
for (const node of traverse(container)) {
|
|
162
|
-
if (!(node instanceof Gtk.Label)) continue;
|
|
163
|
-
|
|
164
|
-
const labelText = node.getLabel();
|
|
165
|
-
if (!labelText) continue;
|
|
166
|
-
if (!matchText(labelText, text, node, options)) continue;
|
|
167
|
-
|
|
168
|
-
const target = node.getMnemonicWidget();
|
|
169
|
-
if (target) {
|
|
170
|
-
results.push(target);
|
|
353
|
+
for (const [expected, current] of numericChecks) {
|
|
354
|
+
if (!isNumericValueMatch(expected, current)) {
|
|
355
|
+
return false;
|
|
171
356
|
}
|
|
172
357
|
}
|
|
173
358
|
|
|
174
|
-
return
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Finds a single element matching label text without throwing.
|
|
179
|
-
*
|
|
180
|
-
* @param container - The container to search within
|
|
181
|
-
* @param text - Text to match (string, RegExp, or custom matcher)
|
|
182
|
-
* @param options - Query options including normalization
|
|
183
|
-
* @returns The matching widget or null if not found
|
|
184
|
-
* @throws Error if multiple elements match
|
|
185
|
-
*/
|
|
186
|
-
export const queryByLabelText = (
|
|
187
|
-
container: Container,
|
|
188
|
-
text: TextMatch,
|
|
189
|
-
options?: TextMatchOptions,
|
|
190
|
-
): Gtk.Widget | null => {
|
|
191
|
-
const matches = queryAllByLabelText(container, text, options);
|
|
192
|
-
|
|
193
|
-
if (matches.length > 1) {
|
|
194
|
-
throw buildMultipleFoundError(container, "labelText", { text, options }, matches.length);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return matches[0] ?? null;
|
|
359
|
+
return value.text === undefined || isTextMatch(actual.text, value.text, widget, options);
|
|
198
360
|
};
|
|
199
361
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Finds a single element matching text content without throwing.
|
|
216
|
-
*
|
|
217
|
-
* @param container - The container to search within
|
|
218
|
-
* @param text - Text to match (string, RegExp, or custom matcher)
|
|
219
|
-
* @param options - Query options including normalization
|
|
220
|
-
* @returns The matching widget or null if not found
|
|
221
|
-
* @throws Error if multiple elements match
|
|
222
|
-
*/
|
|
223
|
-
export const queryByText = (container: Container, text: TextMatch, options?: TextMatchOptions): Gtk.Widget | null => {
|
|
224
|
-
const matches = queryAllByText(container, text, options);
|
|
225
|
-
|
|
226
|
-
if (matches.length > 1) {
|
|
227
|
-
throw buildMultipleFoundError(container, "text", { text, options }, matches.length);
|
|
362
|
+
const hasMatchingBooleanStates = (widget: Gtk.Widget, options: ByRoleOptions): boolean => {
|
|
363
|
+
const stateChecks: [boolean | undefined, () => boolean | null][] = [
|
|
364
|
+
[options.checked, () => getWidgetCheckedState(widget)],
|
|
365
|
+
[options.pressed, () => getWidgetPressedState(widget)],
|
|
366
|
+
[options.expanded, () => getWidgetExpandedState(widget)],
|
|
367
|
+
[options.selected, () => getWidgetSelectedState(widget)],
|
|
368
|
+
[options.busy, () => getWidgetBusyState(widget) ?? false],
|
|
369
|
+
];
|
|
370
|
+
|
|
371
|
+
for (const [expected, getActual] of stateChecks) {
|
|
372
|
+
if (expected !== undefined && getActual() !== expected) {
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
228
375
|
}
|
|
229
376
|
|
|
230
|
-
return
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* Finds all elements matching a widget name without throwing.
|
|
235
|
-
*
|
|
236
|
-
* @param container - The container to search within
|
|
237
|
-
* @param name - Widget name to match (string, RegExp, or custom matcher)
|
|
238
|
-
* @param options - Query options including normalization
|
|
239
|
-
* @returns Array of matching widgets (empty if none found)
|
|
240
|
-
*/
|
|
241
|
-
export const queryAllByName = (container: Container, name: TextMatch, options?: TextMatchOptions): Gtk.Widget[] => {
|
|
242
|
-
return findAll(container, (node) => {
|
|
243
|
-
const widgetName = getWidgetName(node);
|
|
244
|
-
return matchText(widgetName, name, node, options);
|
|
245
|
-
});
|
|
377
|
+
return true;
|
|
246
378
|
};
|
|
247
379
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
*
|
|
251
|
-
* @param container - The container to search within
|
|
252
|
-
* @param name - Widget name to match (string, RegExp, or custom matcher)
|
|
253
|
-
* @param options - Query options including normalization
|
|
254
|
-
* @returns The matching widget or null if not found
|
|
255
|
-
* @throws Error if multiple elements match
|
|
256
|
-
*/
|
|
257
|
-
export const queryByName = (container: Container, name: TextMatch, options?: TextMatchOptions): Gtk.Widget | null => {
|
|
258
|
-
const matches = queryAllByName(container, name, options);
|
|
380
|
+
const hasMatchingLevelState = (widget: Gtk.Widget, options: ByRoleOptions): boolean =>
|
|
381
|
+
options.level === undefined || getWidgetLevel(widget) === options.level;
|
|
259
382
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
383
|
+
const hasMatchingDescriptionState = (widget: Gtk.Widget, options: ByRoleOptions): boolean =>
|
|
384
|
+
options.description === undefined ||
|
|
385
|
+
isTextMatch(getWidgetDescription(widget), options.description, widget, options);
|
|
263
386
|
|
|
264
|
-
|
|
265
|
-
|
|
387
|
+
const hasMatchingValueState = (widget: Gtk.Widget, options: ByRoleOptions): boolean =>
|
|
388
|
+
options.value === undefined || hasMatchingAccessibleValue(widget, options.value, options);
|
|
266
389
|
|
|
267
|
-
const
|
|
268
|
-
|
|
390
|
+
const hasMatchingAccessibleStates = (widget: Gtk.Widget, options: ByRoleOptions): boolean =>
|
|
391
|
+
hasMatchingBooleanStates(widget, options) &&
|
|
392
|
+
hasMatchingLevelState(widget, options) &&
|
|
393
|
+
hasMatchingDescriptionState(widget, options) &&
|
|
394
|
+
hasMatchingValueState(widget, options);
|
|
269
395
|
|
|
270
|
-
|
|
271
|
-
|
|
396
|
+
const hasMatchingByRoleOptions = (widget: Gtk.Widget, options?: ByRoleOptions): boolean => {
|
|
397
|
+
if (!options) {
|
|
398
|
+
return true;
|
|
272
399
|
}
|
|
273
400
|
|
|
274
|
-
return
|
|
401
|
+
return hasMatchingAccessibleName(widget, options) && hasMatchingAccessibleStates(widget, options);
|
|
275
402
|
};
|
|
276
403
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
404
|
+
function nameQueryFamily<Suffix extends string, Args extends unknown[]>(
|
|
405
|
+
suffix: Suffix,
|
|
406
|
+
queryAllBy: QueryAllBy<Args>,
|
|
407
|
+
built: BuiltQueries<Args>,
|
|
408
|
+
): NamedFamily<Suffix, Args> {
|
|
409
|
+
const family = {
|
|
410
|
+
[`queryBy${suffix}`]: built.queryBy,
|
|
411
|
+
[`queryAllBy${suffix}`]: queryAllBy,
|
|
412
|
+
[`getBy${suffix}`]: built.getBy,
|
|
413
|
+
[`getAllBy${suffix}`]: built.getAllBy,
|
|
414
|
+
[`findBy${suffix}`]: built.findBy,
|
|
415
|
+
[`findAllBy${suffix}`]: built.findAllBy,
|
|
416
|
+
};
|
|
286
417
|
|
|
287
|
-
|
|
288
|
-
|
|
418
|
+
return family as NamedFamily<Suffix, Args>;
|
|
419
|
+
}
|
|
289
420
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
421
|
+
/**
|
|
422
|
+
* Finds every widget under the container whose accessible role matches `role` and that satisfies the given options.
|
|
423
|
+
* Widgets excluded from the accessibility tree are skipped unless `options.hidden` is set.
|
|
424
|
+
* @param container Widget subtree to search.
|
|
425
|
+
* @param role Accessible role to match.
|
|
426
|
+
* @param options Additional accessible name, state, and value constraints.
|
|
427
|
+
* @returns Every matching widget, or an empty array when none match.
|
|
428
|
+
*/
|
|
429
|
+
function queryAllByRole(
|
|
430
|
+
container: Container,
|
|
431
|
+
role: Gtk.AccessibleRole,
|
|
432
|
+
options?: ByRoleOptions,
|
|
433
|
+
): Gtk.Widget[] {
|
|
434
|
+
return findAll(container, (widget) => {
|
|
435
|
+
if (widget.getAccessibleRole() !== role) {
|
|
436
|
+
return false;
|
|
437
|
+
}
|
|
293
438
|
|
|
294
|
-
|
|
295
|
-
|
|
439
|
+
if (!options?.hidden && isInaccessible(widget)) {
|
|
440
|
+
return false;
|
|
441
|
+
}
|
|
296
442
|
|
|
297
|
-
|
|
298
|
-
|
|
443
|
+
return hasMatchingByRoleOptions(widget, options);
|
|
444
|
+
});
|
|
445
|
+
}
|
|
299
446
|
|
|
300
|
-
|
|
301
|
-
|
|
447
|
+
const collectMnemonicMatch = (
|
|
448
|
+
widget: Gtk.Widget,
|
|
449
|
+
text: Matcher,
|
|
450
|
+
options: MatcherOptions | undefined,
|
|
451
|
+
): Gtk.Widget | null => {
|
|
452
|
+
if (!(widget instanceof Gtk.Label)) {
|
|
453
|
+
return null;
|
|
302
454
|
}
|
|
303
455
|
|
|
304
|
-
|
|
305
|
-
};
|
|
306
|
-
|
|
307
|
-
const getAllByText = (container: Container, text: TextMatch, options?: TextMatchOptions): Gtk.Widget[] => {
|
|
308
|
-
const matches = queryAllByText(container, text, options);
|
|
456
|
+
const labelText = widget.getLabel();
|
|
309
457
|
|
|
310
|
-
if (
|
|
311
|
-
|
|
458
|
+
if (!labelText || !isTextMatch(labelText, text, widget, options)) {
|
|
459
|
+
return null;
|
|
312
460
|
}
|
|
313
461
|
|
|
314
|
-
return
|
|
462
|
+
return widget.getMnemonicWidget();
|
|
315
463
|
};
|
|
316
464
|
|
|
317
|
-
const
|
|
318
|
-
|
|
465
|
+
const collectLabelMatches = (
|
|
466
|
+
results: Set<Gtk.Widget>,
|
|
467
|
+
widget: Gtk.Widget,
|
|
468
|
+
text: Matcher,
|
|
469
|
+
options: MatcherOptions | undefined,
|
|
470
|
+
): void => {
|
|
471
|
+
const mnemonicTarget = collectMnemonicMatch(widget, text, options);
|
|
319
472
|
|
|
320
|
-
if (
|
|
321
|
-
|
|
473
|
+
if (mnemonicTarget) {
|
|
474
|
+
results.add(mnemonicTarget);
|
|
322
475
|
}
|
|
323
476
|
|
|
324
|
-
|
|
325
|
-
};
|
|
326
|
-
|
|
327
|
-
const getAllByName = (container: Container, name: TextMatch, options?: TextMatchOptions): Gtk.Widget[] => {
|
|
328
|
-
const matches = queryAllByName(container, name, options);
|
|
477
|
+
const ownLabel = getWidgetOwnLabel(widget);
|
|
329
478
|
|
|
330
|
-
if (
|
|
331
|
-
|
|
479
|
+
if (ownLabel !== null && isTextMatch(ownLabel, text, widget, options)) {
|
|
480
|
+
results.add(widget);
|
|
332
481
|
}
|
|
333
482
|
|
|
334
|
-
|
|
335
|
-
};
|
|
336
|
-
|
|
337
|
-
const getByName = (container: Container, name: TextMatch, options?: TextMatchOptions): Gtk.Widget => {
|
|
338
|
-
const matches = getAllByName(container, name, options);
|
|
483
|
+
const labelledByText = getWidgetLabelledByText(widget);
|
|
339
484
|
|
|
340
|
-
if (
|
|
341
|
-
|
|
485
|
+
if (labelledByText !== null && isTextMatch(labelledByText, text, widget, options)) {
|
|
486
|
+
results.add(widget);
|
|
342
487
|
}
|
|
343
|
-
|
|
344
|
-
return matches[0] as Gtk.Widget;
|
|
345
488
|
};
|
|
346
489
|
|
|
347
490
|
/**
|
|
348
|
-
* Finds a
|
|
349
|
-
*
|
|
350
|
-
*
|
|
351
|
-
*
|
|
352
|
-
* @param
|
|
353
|
-
* @
|
|
354
|
-
* @param options - Query options including name, state filters, and timeout
|
|
355
|
-
* @returns Promise resolving to the matching widget
|
|
356
|
-
*
|
|
357
|
-
* @example
|
|
358
|
-
* ```tsx
|
|
359
|
-
* const button = await findByRole(container, Gtk.AccessibleRole.BUTTON, { name: "Submit" });
|
|
360
|
-
* ```
|
|
491
|
+
* Finds every widget associated with a label whose text matches: a Gtk.Label mnemonic target, the
|
|
492
|
+
* widget's own accessible label, or its labelled-by relation.
|
|
493
|
+
* @param container Widget subtree to search.
|
|
494
|
+
* @param text Matcher for the label text.
|
|
495
|
+
* @param options Text matching options.
|
|
496
|
+
* @returns Every matching widget, or an empty array when none match.
|
|
361
497
|
*/
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
role: Gtk.AccessibleRole,
|
|
365
|
-
options?: ByRoleOptions,
|
|
366
|
-
): Promise<Gtk.Widget> =>
|
|
367
|
-
waitFor(() => getByRole(container, role, options), {
|
|
368
|
-
timeout: options?.timeout,
|
|
369
|
-
});
|
|
498
|
+
function queryAllByLabelText(container: Container, text: Matcher, options?: MatcherOptions): Gtk.Widget[] {
|
|
499
|
+
const results: Set<Gtk.Widget> = new Set();
|
|
370
500
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
* @param container - The container to search within
|
|
375
|
-
* @param role - The GTK accessible role to match
|
|
376
|
-
* @param options - Query options including name, state filters, and timeout
|
|
377
|
-
* @returns Promise resolving to array of matching widgets
|
|
378
|
-
*/
|
|
379
|
-
export const findAllByRole = async (
|
|
380
|
-
container: Container,
|
|
381
|
-
role: Gtk.AccessibleRole,
|
|
382
|
-
options?: ByRoleOptions,
|
|
383
|
-
): Promise<Gtk.Widget[]> =>
|
|
384
|
-
waitFor(() => getAllByRole(container, role, options), {
|
|
385
|
-
timeout: options?.timeout,
|
|
386
|
-
});
|
|
501
|
+
for (const widget of traverse(container)) {
|
|
502
|
+
collectLabelMatches(results, widget, text, options);
|
|
503
|
+
}
|
|
387
504
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
*
|
|
391
|
-
* Waits for the element to appear, throwing if not found within timeout.
|
|
392
|
-
* Uses GtkLabel's mnemonic widget association to find form elements.
|
|
393
|
-
*
|
|
394
|
-
* @param container - The container to search within
|
|
395
|
-
* @param text - Label text to match (string, RegExp, or custom matcher)
|
|
396
|
-
* @param options - Query options including normalization and timeout
|
|
397
|
-
* @returns Promise resolving to the labelled widget
|
|
398
|
-
*
|
|
399
|
-
* @example
|
|
400
|
-
* ```tsx
|
|
401
|
-
* const input = await findByLabelText(container, "Username");
|
|
402
|
-
* ```
|
|
403
|
-
*/
|
|
404
|
-
export const findByLabelText = async (
|
|
405
|
-
container: Container,
|
|
406
|
-
text: TextMatch,
|
|
407
|
-
options?: TextMatchOptions,
|
|
408
|
-
): Promise<Gtk.Widget> =>
|
|
409
|
-
waitFor(() => getByLabelText(container, text, options), {
|
|
410
|
-
timeout: options?.timeout,
|
|
411
|
-
});
|
|
505
|
+
return [...results];
|
|
506
|
+
}
|
|
412
507
|
|
|
413
508
|
/**
|
|
414
|
-
* Finds
|
|
415
|
-
*
|
|
416
|
-
* @param
|
|
417
|
-
* @param
|
|
418
|
-
* @
|
|
419
|
-
* @returns Promise resolving to array of matching widgets
|
|
509
|
+
* Finds every widget whose rendered text content matches.
|
|
510
|
+
* @param container Widget subtree to search.
|
|
511
|
+
* @param text Matcher for the widget text.
|
|
512
|
+
* @param options Text matching options.
|
|
513
|
+
* @returns Every matching widget, or an empty array when none match.
|
|
420
514
|
*/
|
|
421
|
-
|
|
422
|
-
container
|
|
423
|
-
|
|
424
|
-
options?: TextMatchOptions,
|
|
425
|
-
): Promise<Gtk.Widget[]> =>
|
|
426
|
-
waitFor(() => getAllByLabelText(container, text, options), {
|
|
427
|
-
timeout: options?.timeout,
|
|
428
|
-
});
|
|
515
|
+
function queryAllByText(container: Container, text: Matcher, options?: MatcherOptions): Gtk.Widget[] {
|
|
516
|
+
return findAll(container, (widget) => isTextMatch(getWidgetLabelText(widget), text, widget, options));
|
|
517
|
+
}
|
|
429
518
|
|
|
430
519
|
/**
|
|
431
|
-
* Finds
|
|
432
|
-
*
|
|
433
|
-
*
|
|
434
|
-
*
|
|
435
|
-
* @
|
|
436
|
-
* @param text - Text to match (string, RegExp, or custom matcher)
|
|
437
|
-
* @param options - Query options including normalization and timeout
|
|
438
|
-
* @returns Promise resolving to the matching widget
|
|
520
|
+
* Finds every widget whose widget name matches.
|
|
521
|
+
* @param container Widget subtree to search.
|
|
522
|
+
* @param name Matcher for the widget name.
|
|
523
|
+
* @param options Text matching options.
|
|
524
|
+
* @returns Every matching widget, or an empty array when none match.
|
|
439
525
|
*/
|
|
440
|
-
|
|
441
|
-
container
|
|
442
|
-
|
|
443
|
-
options?: TextMatchOptions,
|
|
444
|
-
): Promise<Gtk.Widget> =>
|
|
445
|
-
waitFor(() => getByText(container, text, options), {
|
|
446
|
-
timeout: options?.timeout,
|
|
447
|
-
});
|
|
448
|
-
|
|
449
|
-
/**
|
|
450
|
-
* Finds all elements matching visible text content.
|
|
451
|
-
*
|
|
452
|
-
* @param container - The container to search within
|
|
453
|
-
* @param text - Text to match (string, RegExp, or custom matcher)
|
|
454
|
-
* @param options - Query options including normalization and timeout
|
|
455
|
-
* @returns Promise resolving to array of matching widgets
|
|
456
|
-
*/
|
|
457
|
-
export const findAllByText = async (
|
|
458
|
-
container: Container,
|
|
459
|
-
text: TextMatch,
|
|
460
|
-
options?: TextMatchOptions,
|
|
461
|
-
): Promise<Gtk.Widget[]> =>
|
|
462
|
-
waitFor(() => getAllByText(container, text, options), {
|
|
463
|
-
timeout: options?.timeout,
|
|
464
|
-
});
|
|
526
|
+
function queryAllByName(container: Container, name: Matcher, options?: MatcherOptions): Gtk.Widget[] {
|
|
527
|
+
return findAll(container, (widget) => isTextMatch(getWidgetName(widget), name, widget, options));
|
|
528
|
+
}
|
|
465
529
|
|
|
466
530
|
/**
|
|
467
|
-
* Finds
|
|
468
|
-
*
|
|
469
|
-
*
|
|
470
|
-
*
|
|
471
|
-
*
|
|
472
|
-
* @param container - The container to search within
|
|
473
|
-
* @param name - Widget name to match (string, RegExp, or custom matcher)
|
|
474
|
-
* @param options - Query options including normalization and timeout
|
|
475
|
-
* @returns Promise resolving to the matching widget
|
|
476
|
-
*
|
|
477
|
-
* @example
|
|
478
|
-
* ```tsx
|
|
479
|
-
* // In component: <GtkButton name="submit-btn" />
|
|
480
|
-
* const button = await findByName(container, "submit-btn");
|
|
481
|
-
* ```
|
|
531
|
+
* Finds every widget whose placeholder text matches.
|
|
532
|
+
* @param container Widget subtree to search.
|
|
533
|
+
* @param text Matcher for the placeholder text.
|
|
534
|
+
* @param options Text matching options.
|
|
535
|
+
* @returns Every matching widget, or an empty array when none match.
|
|
482
536
|
*/
|
|
483
|
-
|
|
537
|
+
function queryAllByPlaceholderText(
|
|
484
538
|
container: Container,
|
|
485
|
-
|
|
486
|
-
options?:
|
|
487
|
-
):
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
});
|
|
539
|
+
text: Matcher,
|
|
540
|
+
options?: MatcherOptions,
|
|
541
|
+
): Gtk.Widget[] {
|
|
542
|
+
return findAll(container, (widget) => isTextMatch(getWidgetPlaceholderText(widget), text, widget, options));
|
|
543
|
+
}
|
|
491
544
|
|
|
492
545
|
/**
|
|
493
|
-
* Finds
|
|
494
|
-
*
|
|
495
|
-
* @param
|
|
496
|
-
* @param
|
|
497
|
-
* @
|
|
498
|
-
* @returns Promise resolving to array of matching widgets
|
|
546
|
+
* Finds every widget whose current display value matches.
|
|
547
|
+
* @param container Widget subtree to search.
|
|
548
|
+
* @param value Matcher for the display value.
|
|
549
|
+
* @param options Text matching options.
|
|
550
|
+
* @returns Every matching widget, or an empty array when none match.
|
|
499
551
|
*/
|
|
500
|
-
|
|
501
|
-
container
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
552
|
+
function queryAllByDisplayValue(container: Container, value: Matcher, options?: MatcherOptions): Gtk.Widget[] {
|
|
553
|
+
return findAll(container, (widget) => isTextMatch(getWidgetDisplayValue(widget), value, widget, options));
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
export {
|
|
557
|
+
builtinQueries,
|
|
558
|
+
queryByRole,
|
|
559
|
+
getAllByRole,
|
|
560
|
+
getByRole,
|
|
561
|
+
findAllByRole,
|
|
562
|
+
findByRole,
|
|
563
|
+
queryByLabelText,
|
|
564
|
+
getAllByLabelText,
|
|
565
|
+
getByLabelText,
|
|
566
|
+
findAllByLabelText,
|
|
567
|
+
findByLabelText,
|
|
568
|
+
queryByText,
|
|
569
|
+
getAllByText,
|
|
570
|
+
getByText,
|
|
571
|
+
findAllByText,
|
|
572
|
+
findByText,
|
|
573
|
+
queryByName,
|
|
574
|
+
getAllByName,
|
|
575
|
+
getByName,
|
|
576
|
+
findAllByName,
|
|
577
|
+
findByName,
|
|
578
|
+
queryByPlaceholderText,
|
|
579
|
+
getAllByPlaceholderText,
|
|
580
|
+
getByPlaceholderText,
|
|
581
|
+
findAllByPlaceholderText,
|
|
582
|
+
findByPlaceholderText,
|
|
583
|
+
queryByDisplayValue,
|
|
584
|
+
getAllByDisplayValue,
|
|
585
|
+
getByDisplayValue,
|
|
586
|
+
findAllByDisplayValue,
|
|
587
|
+
findByDisplayValue,
|
|
588
|
+
getDefaultNormalizer,
|
|
589
|
+
queryAllByRole,
|
|
590
|
+
queryAllByLabelText,
|
|
591
|
+
queryAllByText,
|
|
592
|
+
queryAllByName,
|
|
593
|
+
queryAllByPlaceholderText,
|
|
594
|
+
queryAllByDisplayValue,
|
|
595
|
+
type BuiltinQueries,
|
|
596
|
+
};
|