@gtkx/testing 1.0.0-rc.2 → 1.0.0-rc.4
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 +4 -5
- package/dist/act.d.ts +2 -0
- package/dist/act.d.ts.map +1 -1
- package/dist/act.js.map +1 -1
- package/dist/bound-queries.d.ts +2 -3
- package/dist/bound-queries.d.ts.map +1 -1
- package/dist/bound-queries.js.map +1 -1
- package/dist/build-queries.d.ts.map +1 -1
- package/dist/build-queries.js +18 -7
- package/dist/build-queries.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -3
- package/dist/config.js.map +1 -1
- package/dist/errors.js +2 -2
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +7 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/matchers.d.ts +125 -21
- package/dist/matchers.d.ts.map +1 -1
- package/dist/matchers.js +258 -21
- package/dist/matchers.js.map +1 -1
- package/dist/normalize.d.ts +10 -0
- package/dist/normalize.d.ts.map +1 -0
- package/dist/normalize.js +20 -0
- package/dist/normalize.js.map +1 -0
- package/dist/pretty-widget.d.ts +2 -1
- package/dist/pretty-widget.d.ts.map +1 -1
- package/dist/pretty-widget.js +3 -3
- package/dist/pretty-widget.js.map +1 -1
- package/dist/queries.d.ts +4 -21
- package/dist/queries.d.ts.map +1 -1
- package/dist/queries.js +46 -59
- package/dist/queries.js.map +1 -1
- package/dist/render.js +3 -3
- package/dist/render.js.map +1 -1
- package/dist/suggestions.d.ts +3 -0
- package/dist/suggestions.d.ts.map +1 -1
- package/dist/suggestions.js.map +1 -1
- package/dist/traversal.d.ts +5 -0
- package/dist/traversal.d.ts.map +1 -1
- package/dist/traversal.js +1 -0
- package/dist/traversal.js.map +1 -1
- package/dist/types.d.ts +69 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/user-event/adjustment.d.ts +13 -0
- package/dist/user-event/adjustment.d.ts.map +1 -1
- package/dist/user-event/adjustment.js +11 -0
- package/dist/user-event/adjustment.js.map +1 -1
- package/dist/user-event/click.d.ts +7 -0
- package/dist/user-event/click.d.ts.map +1 -1
- package/dist/user-event/click.js +7 -0
- package/dist/user-event/click.js.map +1 -1
- package/dist/user-event/controller.d.ts +31 -1
- package/dist/user-event/controller.d.ts.map +1 -1
- package/dist/user-event/controller.js +36 -1
- package/dist/user-event/controller.js.map +1 -1
- package/dist/user-event/gesture.d.ts +51 -0
- package/dist/user-event/gesture.d.ts.map +1 -1
- package/dist/user-event/gesture.js +47 -4
- package/dist/user-event/gesture.js.map +1 -1
- package/dist/user-event/index.d.ts +27 -0
- package/dist/user-event/index.d.ts.map +1 -1
- package/dist/user-event/index.js.map +1 -1
- package/dist/user-event/keyboard.d.ts +4 -2
- package/dist/user-event/keyboard.d.ts.map +1 -1
- package/dist/user-event/keyboard.js +13 -12
- package/dist/user-event/keyboard.js.map +1 -1
- package/dist/user-event/pointer.js +5 -5
- package/dist/user-event/pointer.js.map +1 -1
- package/dist/user-event/selection.d.ts +15 -0
- package/dist/user-event/selection.d.ts.map +1 -1
- package/dist/user-event/selection.js +15 -0
- package/dist/user-event/selection.js.map +1 -1
- package/dist/user-event/state.d.ts +1 -1
- package/dist/user-event/state.d.ts.map +1 -1
- package/dist/user-event/state.js +1 -1
- package/dist/user-event/state.js.map +1 -1
- package/dist/user-event/text.d.ts +30 -3
- package/dist/user-event/text.d.ts.map +1 -1
- package/dist/user-event/text.js +28 -1
- package/dist/user-event/text.js.map +1 -1
- package/dist/wait-for.d.ts +2 -0
- package/dist/wait-for.d.ts.map +1 -1
- package/dist/wait-for.js.map +1 -1
- package/dist/widget-accessible-properties.d.ts +28 -2
- package/dist/widget-accessible-properties.d.ts.map +1 -1
- package/dist/widget-accessible-properties.js +129 -10
- package/dist/widget-accessible-properties.js.map +1 -1
- package/dist/within.js.map +1 -1
- package/package.json +7 -7
- package/src/act.ts +2 -0
- package/src/bound-queries.ts +2 -3
- package/src/build-queries.ts +20 -8
- package/src/config.ts +4 -3
- package/src/errors.ts +2 -2
- package/src/index.ts +11 -2
- package/src/matchers.ts +500 -53
- package/src/normalize.ts +28 -0
- package/src/pretty-widget.ts +5 -4
- package/src/queries.ts +79 -105
- package/src/render.tsx +3 -3
- package/src/suggestions.ts +3 -0
- package/src/traversal.ts +5 -0
- package/src/types.ts +88 -4
- package/src/user-event/adjustment.ts +13 -0
- package/src/user-event/click.ts +7 -0
- package/src/user-event/controller.ts +50 -1
- package/src/user-event/gesture.ts +57 -6
- package/src/user-event/index.ts +27 -0
- package/src/user-event/keyboard.ts +18 -16
- package/src/user-event/pointer.ts +5 -5
- package/src/user-event/selection.ts +15 -0
- package/src/user-event/state.ts +2 -2
- package/src/user-event/text.ts +31 -4
- package/src/wait-for.ts +2 -0
- package/src/widget-accessible-properties.ts +188 -10
- package/src/within.ts +1 -1
package/src/normalize.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { NormalizerFn, NormalizerOptions } from "./types.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Builds the default text normalizer, which optionally trims surrounding whitespace and collapses
|
|
5
|
+
* runs of whitespace into single spaces.
|
|
6
|
+
* @param options Toggles for trimming and whitespace collapsing.
|
|
7
|
+
* @returns A function that normalizes a string for comparison against a matcher.
|
|
8
|
+
*/
|
|
9
|
+
const getDefaultNormalizer = ({
|
|
10
|
+
trim = true,
|
|
11
|
+
collapseWhitespace = true,
|
|
12
|
+
}: NormalizerOptions = {}): NormalizerFn => {
|
|
13
|
+
return (text: string): string => {
|
|
14
|
+
let result = text;
|
|
15
|
+
|
|
16
|
+
if (trim) {
|
|
17
|
+
result = result.trim();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (collapseWhitespace) {
|
|
21
|
+
result = result.replaceAll(/\s+/g, " ");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return result;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export { getDefaultNormalizer };
|
package/src/pretty-widget.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { formatRole } from "./role-helpers.js";
|
|
|
4
4
|
import { type Container, roots } from "./traversal.js";
|
|
5
5
|
import { getWidgetNodeText } from "./widget-accessible-properties.js";
|
|
6
6
|
|
|
7
|
+
/** Produces the value of the `id` attribute printed first on a widget's opening tag. */
|
|
7
8
|
type WidgetIdResolver = (widget: Gtk.Widget) => string;
|
|
8
9
|
|
|
9
10
|
/**
|
|
@@ -14,7 +15,7 @@ type PrettyWidgetOptions = {
|
|
|
14
15
|
/** Truncates the output once it exceeds this many characters. */
|
|
15
16
|
maxLength?: number;
|
|
16
17
|
/** Whether to apply ANSI color highlighting; defaults to the terminal capabilities. */
|
|
17
|
-
|
|
18
|
+
shouldHighlight?: boolean;
|
|
18
19
|
/** Resolves an `id` attribute to show for each widget. */
|
|
19
20
|
getId?: WidgetIdResolver;
|
|
20
21
|
/** Stops descending past this depth, replacing deeper children with a summary line. */
|
|
@@ -76,7 +77,7 @@ const buildAttrs = (widget: Gtk.Widget, getId: WidgetIdResolver | undefined): [s
|
|
|
76
77
|
return [...idAttrs, ...otherAttrs];
|
|
77
78
|
};
|
|
78
79
|
|
|
79
|
-
const
|
|
80
|
+
const isHighlightSupported = (): boolean => {
|
|
80
81
|
if (typeof process === "undefined") {
|
|
81
82
|
return false;
|
|
82
83
|
}
|
|
@@ -206,8 +207,8 @@ const prettyWidget = (container: Container, options: PrettyWidgetOptions = {}):
|
|
|
206
207
|
return "";
|
|
207
208
|
}
|
|
208
209
|
|
|
209
|
-
const
|
|
210
|
-
const colors = createColors(
|
|
210
|
+
const shouldHighlight = options.shouldHighlight ?? isHighlightSupported();
|
|
211
|
+
const colors = createColors(shouldHighlight);
|
|
211
212
|
let output = "";
|
|
212
213
|
|
|
213
214
|
for (const root of roots(container)) {
|
package/src/queries.ts
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
import * as Gtk from "@gtkx/gi/gtk";
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
ByRoleOptions,
|
|
4
|
+
ByRoleValue,
|
|
5
|
+
Matcher,
|
|
6
|
+
MatcherOptions,
|
|
7
|
+
NormalizerFn,
|
|
8
|
+
QueryFamilies,
|
|
9
|
+
} from "./types.js";
|
|
3
10
|
import { buildQueries, type BuiltQueries, type QueryAllBy } from "./build-queries.js";
|
|
4
11
|
import { multipleFoundError, notFoundError } from "./errors.js";
|
|
12
|
+
import { getDefaultNormalizer } from "./normalize.js";
|
|
5
13
|
import { type Container, findAll, traverse } from "./traversal.js";
|
|
6
14
|
import {
|
|
7
15
|
getWidgetAccessibleName,
|
|
8
16
|
getWidgetBusyState,
|
|
9
|
-
getWidgetCheckedState,
|
|
10
17
|
getWidgetDescription,
|
|
11
18
|
getWidgetDisplayValue,
|
|
12
19
|
getWidgetExpandedState,
|
|
@@ -20,30 +27,11 @@ import {
|
|
|
20
27
|
getWidgetSelectedState,
|
|
21
28
|
getWidgetValue,
|
|
22
29
|
isInaccessible,
|
|
30
|
+
isWidgetChecked,
|
|
23
31
|
} from "./widget-accessible-properties.js";
|
|
24
32
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
queryAllBy: Gtk.Widget[];
|
|
28
|
-
getBy: Gtk.Widget;
|
|
29
|
-
getAllBy: Gtk.Widget[];
|
|
30
|
-
findBy: Promise<Gtk.Widget>;
|
|
31
|
-
findAllBy: Promise<Gtk.Widget[]>;
|
|
32
|
-
};
|
|
33
|
-
|
|
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]>;
|
|
33
|
+
/** The built-in queries in their unbound form, each taking the container to search as its first argument. */
|
|
34
|
+
type BuiltinQueries = QueryFamilies<[container: Container]>;
|
|
47
35
|
|
|
48
36
|
const roleQueries = nameQueryFamily(
|
|
49
37
|
"Role",
|
|
@@ -112,167 +100,132 @@ const displayValueQueries = nameQueryFamily(
|
|
|
112
100
|
),
|
|
113
101
|
);
|
|
114
102
|
|
|
115
|
-
const builtinQueries
|
|
103
|
+
const builtinQueries = {
|
|
116
104
|
...roleQueries,
|
|
117
105
|
...labelTextQueries,
|
|
118
106
|
...textQueries,
|
|
119
107
|
...nameQueries,
|
|
120
108
|
...placeholderTextQueries,
|
|
121
109
|
...displayValueQueries,
|
|
122
|
-
};
|
|
110
|
+
} as BuiltinQueries;
|
|
123
111
|
|
|
124
112
|
/**
|
|
125
113
|
* Returns the single widget with a matching accessible role and options, or null when none match.
|
|
126
114
|
* Throws when more than one matches.
|
|
127
115
|
*/
|
|
128
|
-
const queryByRole: BuiltinQueries["queryByRole"] =
|
|
116
|
+
const queryByRole: BuiltinQueries["queryByRole"] = builtinQueries.queryByRole;
|
|
129
117
|
/** Returns every widget with a matching accessible role and options. Throws when none match. */
|
|
130
|
-
const getAllByRole: BuiltinQueries["getAllByRole"] =
|
|
118
|
+
const getAllByRole: BuiltinQueries["getAllByRole"] = builtinQueries.getAllByRole;
|
|
131
119
|
/**
|
|
132
120
|
* Returns the single widget with a matching accessible role and options.
|
|
133
121
|
* Throws when none or more than one matches.
|
|
134
122
|
*/
|
|
135
|
-
const getByRole: BuiltinQueries["getByRole"] =
|
|
123
|
+
const getByRole: BuiltinQueries["getByRole"] = builtinQueries.getByRole;
|
|
136
124
|
/**
|
|
137
125
|
* Waits for and returns every widget with a matching accessible role and options, retrying until at
|
|
138
126
|
* least one appears or the timeout elapses.
|
|
139
127
|
*/
|
|
140
|
-
const findAllByRole: BuiltinQueries["findAllByRole"] =
|
|
128
|
+
const findAllByRole: BuiltinQueries["findAllByRole"] = builtinQueries.findAllByRole;
|
|
141
129
|
/**
|
|
142
130
|
* Waits for and returns the single widget with a matching accessible role and options, retrying
|
|
143
131
|
* until it appears or the timeout elapses. Rejects when none or more than one matches.
|
|
144
132
|
*/
|
|
145
|
-
const findByRole: BuiltinQueries["findByRole"] =
|
|
133
|
+
const findByRole: BuiltinQueries["findByRole"] = builtinQueries.findByRole;
|
|
146
134
|
/**
|
|
147
135
|
* Returns the single widget with matching associated label text, or null when none match.
|
|
148
136
|
* Throws when more than one matches.
|
|
149
137
|
*/
|
|
150
|
-
const queryByLabelText: BuiltinQueries["queryByLabelText"] =
|
|
138
|
+
const queryByLabelText: BuiltinQueries["queryByLabelText"] = builtinQueries.queryByLabelText;
|
|
151
139
|
/** Returns every widget with matching associated label text. Throws when none match. */
|
|
152
|
-
const getAllByLabelText: BuiltinQueries["getAllByLabelText"] =
|
|
140
|
+
const getAllByLabelText: BuiltinQueries["getAllByLabelText"] = builtinQueries.getAllByLabelText;
|
|
153
141
|
/** Returns the single widget with matching associated label text. Throws when none or more than one matches. */
|
|
154
|
-
const getByLabelText: BuiltinQueries["getByLabelText"] =
|
|
142
|
+
const getByLabelText: BuiltinQueries["getByLabelText"] = builtinQueries.getByLabelText;
|
|
155
143
|
/**
|
|
156
144
|
* Waits for and returns every widget with matching associated label text, retrying until at least
|
|
157
145
|
* one appears or the timeout elapses.
|
|
158
146
|
*/
|
|
159
|
-
const findAllByLabelText: BuiltinQueries["findAllByLabelText"] =
|
|
147
|
+
const findAllByLabelText: BuiltinQueries["findAllByLabelText"] = builtinQueries.findAllByLabelText;
|
|
160
148
|
/**
|
|
161
149
|
* Waits for and returns the single widget with matching associated label text, retrying until it
|
|
162
150
|
* appears or the timeout elapses. Rejects when none or more than one matches.
|
|
163
151
|
*/
|
|
164
|
-
const findByLabelText: BuiltinQueries["findByLabelText"] =
|
|
152
|
+
const findByLabelText: BuiltinQueries["findByLabelText"] = builtinQueries.findByLabelText;
|
|
165
153
|
/**
|
|
166
154
|
* Returns the single widget with matching rendered text content, or null when none match.
|
|
167
155
|
* Throws when more than one matches.
|
|
168
156
|
*/
|
|
169
|
-
const queryByText: BuiltinQueries["queryByText"] =
|
|
157
|
+
const queryByText: BuiltinQueries["queryByText"] = builtinQueries.queryByText;
|
|
170
158
|
/** Returns every widget with matching rendered text content. Throws when none match. */
|
|
171
|
-
const getAllByText: BuiltinQueries["getAllByText"] =
|
|
159
|
+
const getAllByText: BuiltinQueries["getAllByText"] = builtinQueries.getAllByText;
|
|
172
160
|
/** Returns the single widget with matching rendered text content. Throws when none or more than one matches. */
|
|
173
|
-
const getByText: BuiltinQueries["getByText"] =
|
|
161
|
+
const getByText: BuiltinQueries["getByText"] = builtinQueries.getByText;
|
|
174
162
|
/**
|
|
175
163
|
* Waits for and returns every widget with matching rendered text content, retrying until at least
|
|
176
164
|
* one appears or the timeout elapses.
|
|
177
165
|
*/
|
|
178
|
-
const findAllByText: BuiltinQueries["findAllByText"] =
|
|
166
|
+
const findAllByText: BuiltinQueries["findAllByText"] = builtinQueries.findAllByText;
|
|
179
167
|
/**
|
|
180
168
|
* Waits for and returns the single widget with matching rendered text content, retrying until it
|
|
181
169
|
* appears or the timeout elapses. Rejects when none or more than one matches.
|
|
182
170
|
*/
|
|
183
|
-
const findByText: BuiltinQueries["findByText"] =
|
|
171
|
+
const findByText: BuiltinQueries["findByText"] = builtinQueries.findByText;
|
|
184
172
|
/**
|
|
185
173
|
* Returns the single widget with a matching widget name, or null when none match.
|
|
186
174
|
* Throws when more than one matches.
|
|
187
175
|
*/
|
|
188
|
-
const queryByName: BuiltinQueries["queryByName"] =
|
|
176
|
+
const queryByName: BuiltinQueries["queryByName"] = builtinQueries.queryByName;
|
|
189
177
|
/** Returns every widget with a matching widget name. Throws when none match. */
|
|
190
|
-
const getAllByName: BuiltinQueries["getAllByName"] =
|
|
178
|
+
const getAllByName: BuiltinQueries["getAllByName"] = builtinQueries.getAllByName;
|
|
191
179
|
/** Returns the single widget with a matching widget name. Throws when none or more than one matches. */
|
|
192
|
-
const getByName: BuiltinQueries["getByName"] =
|
|
180
|
+
const getByName: BuiltinQueries["getByName"] = builtinQueries.getByName;
|
|
193
181
|
/**
|
|
194
182
|
* Waits for and returns every widget with a matching widget name, retrying until at least one
|
|
195
183
|
* appears or the timeout elapses.
|
|
196
184
|
*/
|
|
197
|
-
const findAllByName: BuiltinQueries["findAllByName"] =
|
|
185
|
+
const findAllByName: BuiltinQueries["findAllByName"] = builtinQueries.findAllByName;
|
|
198
186
|
/**
|
|
199
187
|
* Waits for and returns the single widget with a matching widget name, retrying until it appears or
|
|
200
188
|
* the timeout elapses. Rejects when none or more than one matches.
|
|
201
189
|
*/
|
|
202
|
-
const findByName: BuiltinQueries["findByName"] =
|
|
203
|
-
|
|
190
|
+
const findByName: BuiltinQueries["findByName"] = builtinQueries.findByName;
|
|
204
191
|
/**
|
|
205
192
|
* Returns the single widget with matching placeholder text, or null when none match.
|
|
206
193
|
* Throws when more than one matches.
|
|
207
194
|
*/
|
|
208
|
-
const queryByPlaceholderText: BuiltinQueries["queryByPlaceholderText"] =
|
|
209
|
-
placeholderTextQueries.queryByPlaceholderText;
|
|
210
|
-
|
|
195
|
+
const queryByPlaceholderText: BuiltinQueries["queryByPlaceholderText"] = builtinQueries.queryByPlaceholderText;
|
|
211
196
|
/** Returns every widget with matching placeholder text. Throws when none match. */
|
|
212
|
-
const getAllByPlaceholderText: BuiltinQueries["getAllByPlaceholderText"] =
|
|
213
|
-
placeholderTextQueries.getAllByPlaceholderText;
|
|
214
|
-
|
|
197
|
+
const getAllByPlaceholderText: BuiltinQueries["getAllByPlaceholderText"] = builtinQueries.getAllByPlaceholderText;
|
|
215
198
|
/** Returns the single widget with matching placeholder text. Throws when none or more than one matches. */
|
|
216
|
-
const getByPlaceholderText: BuiltinQueries["getByPlaceholderText"] =
|
|
217
|
-
|
|
199
|
+
const getByPlaceholderText: BuiltinQueries["getByPlaceholderText"] = builtinQueries.getByPlaceholderText;
|
|
218
200
|
/**
|
|
219
201
|
* Waits for and returns every widget with matching placeholder text, retrying until at least one
|
|
220
202
|
* appears or the timeout elapses.
|
|
221
203
|
*/
|
|
222
|
-
const findAllByPlaceholderText: BuiltinQueries["findAllByPlaceholderText"] =
|
|
223
|
-
placeholderTextQueries.findAllByPlaceholderText;
|
|
224
|
-
|
|
204
|
+
const findAllByPlaceholderText: BuiltinQueries["findAllByPlaceholderText"] = builtinQueries.findAllByPlaceholderText;
|
|
225
205
|
/**
|
|
226
206
|
* Waits for and returns the single widget with matching placeholder text, retrying until it appears
|
|
227
207
|
* or the timeout elapses. Rejects when none or more than one matches.
|
|
228
208
|
*/
|
|
229
|
-
const findByPlaceholderText: BuiltinQueries["findByPlaceholderText"] =
|
|
230
|
-
placeholderTextQueries.findByPlaceholderText;
|
|
231
|
-
|
|
209
|
+
const findByPlaceholderText: BuiltinQueries["findByPlaceholderText"] = builtinQueries.findByPlaceholderText;
|
|
232
210
|
/**
|
|
233
211
|
* Returns the single widget with a matching display value, or null when none match.
|
|
234
212
|
* Throws when more than one matches.
|
|
235
213
|
*/
|
|
236
|
-
const queryByDisplayValue: BuiltinQueries["queryByDisplayValue"] =
|
|
214
|
+
const queryByDisplayValue: BuiltinQueries["queryByDisplayValue"] = builtinQueries.queryByDisplayValue;
|
|
237
215
|
/** Returns every widget with a matching display value. Throws when none match. */
|
|
238
|
-
const getAllByDisplayValue: BuiltinQueries["getAllByDisplayValue"] =
|
|
216
|
+
const getAllByDisplayValue: BuiltinQueries["getAllByDisplayValue"] = builtinQueries.getAllByDisplayValue;
|
|
239
217
|
/** Returns the single widget with a matching display value. Throws when none or more than one matches. */
|
|
240
|
-
const getByDisplayValue: BuiltinQueries["getByDisplayValue"] =
|
|
218
|
+
const getByDisplayValue: BuiltinQueries["getByDisplayValue"] = builtinQueries.getByDisplayValue;
|
|
241
219
|
/**
|
|
242
220
|
* Waits for and returns every widget with a matching display value, retrying until at least one
|
|
243
221
|
* appears or the timeout elapses.
|
|
244
222
|
*/
|
|
245
|
-
const findAllByDisplayValue: BuiltinQueries["findAllByDisplayValue"] =
|
|
223
|
+
const findAllByDisplayValue: BuiltinQueries["findAllByDisplayValue"] = builtinQueries.findAllByDisplayValue;
|
|
246
224
|
/**
|
|
247
225
|
* Waits for and returns the single widget with a matching display value, retrying until it appears
|
|
248
226
|
* or the timeout elapses. Rejects when none or more than one matches.
|
|
249
227
|
*/
|
|
250
|
-
const findByDisplayValue: BuiltinQueries["findByDisplayValue"] =
|
|
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 => {
|
|
262
|
-
return (text: string): string => {
|
|
263
|
-
let result = text;
|
|
264
|
-
|
|
265
|
-
if (trim) {
|
|
266
|
-
result = result.trim();
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
if (collapseWhitespace) {
|
|
270
|
-
result = result.replaceAll(/\s+/g, " ");
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
return result;
|
|
274
|
-
};
|
|
275
|
-
};
|
|
228
|
+
const findByDisplayValue: BuiltinQueries["findByDisplayValue"] = builtinQueries.findByDisplayValue;
|
|
276
229
|
|
|
277
230
|
const buildNormalizer = (options?: MatcherOptions): NormalizerFn => {
|
|
278
231
|
const { normalizer, trim, collapseWhitespace } = options ?? {};
|
|
@@ -361,7 +314,7 @@ const hasMatchingAccessibleValue = (widget: Gtk.Widget, value: ByRoleValue, opti
|
|
|
361
314
|
|
|
362
315
|
const hasMatchingBooleanStates = (widget: Gtk.Widget, options: ByRoleOptions): boolean => {
|
|
363
316
|
const stateChecks: [boolean | undefined, () => boolean | null][] = [
|
|
364
|
-
[options.checked, () =>
|
|
317
|
+
[options.checked, () => isWidgetChecked(widget)],
|
|
365
318
|
[options.pressed, () => getWidgetPressedState(widget)],
|
|
366
319
|
[options.expanded, () => getWidgetExpandedState(widget)],
|
|
367
320
|
[options.selected, () => getWidgetSelectedState(widget)],
|
|
@@ -393,20 +346,27 @@ const hasMatchingAccessibleStates = (widget: Gtk.Widget, options: ByRoleOptions)
|
|
|
393
346
|
hasMatchingDescriptionState(widget, options) &&
|
|
394
347
|
hasMatchingValueState(widget, options);
|
|
395
348
|
|
|
349
|
+
const isMatchingWidgetType = (widget: Gtk.Widget, options?: MatcherOptions): boolean =>
|
|
350
|
+
options?.as === undefined || widget instanceof options.as;
|
|
351
|
+
|
|
396
352
|
const hasMatchingByRoleOptions = (widget: Gtk.Widget, options?: ByRoleOptions): boolean => {
|
|
397
353
|
if (!options) {
|
|
398
354
|
return true;
|
|
399
355
|
}
|
|
400
356
|
|
|
401
|
-
return
|
|
357
|
+
return (
|
|
358
|
+
isMatchingWidgetType(widget, options) &&
|
|
359
|
+
hasMatchingAccessibleName(widget, options) &&
|
|
360
|
+
hasMatchingAccessibleStates(widget, options)
|
|
361
|
+
);
|
|
402
362
|
};
|
|
403
363
|
|
|
404
|
-
function nameQueryFamily<
|
|
405
|
-
suffix:
|
|
364
|
+
function nameQueryFamily<Args extends unknown[]>(
|
|
365
|
+
suffix: string,
|
|
406
366
|
queryAllBy: QueryAllBy<Args>,
|
|
407
367
|
built: BuiltQueries<Args>,
|
|
408
|
-
):
|
|
409
|
-
|
|
368
|
+
): Record<string, unknown> {
|
|
369
|
+
return {
|
|
410
370
|
[`queryBy${suffix}`]: built.queryBy,
|
|
411
371
|
[`queryAllBy${suffix}`]: queryAllBy,
|
|
412
372
|
[`getBy${suffix}`]: built.getBy,
|
|
@@ -414,8 +374,6 @@ function nameQueryFamily<Suffix extends string, Args extends unknown[]>(
|
|
|
414
374
|
[`findBy${suffix}`]: built.findBy,
|
|
415
375
|
[`findAllBy${suffix}`]: built.findAllBy,
|
|
416
376
|
};
|
|
417
|
-
|
|
418
|
-
return family as NamedFamily<Suffix, Args>;
|
|
419
377
|
}
|
|
420
378
|
|
|
421
379
|
/**
|
|
@@ -502,7 +460,7 @@ function queryAllByLabelText(container: Container, text: Matcher, options?: Matc
|
|
|
502
460
|
collectLabelMatches(results, widget, text, options);
|
|
503
461
|
}
|
|
504
462
|
|
|
505
|
-
return [...results];
|
|
463
|
+
return [...results].filter((widget) => isMatchingWidgetType(widget, options));
|
|
506
464
|
}
|
|
507
465
|
|
|
508
466
|
/**
|
|
@@ -513,7 +471,11 @@ function queryAllByLabelText(container: Container, text: Matcher, options?: Matc
|
|
|
513
471
|
* @returns Every matching widget, or an empty array when none match.
|
|
514
472
|
*/
|
|
515
473
|
function queryAllByText(container: Container, text: Matcher, options?: MatcherOptions): Gtk.Widget[] {
|
|
516
|
-
return findAll(
|
|
474
|
+
return findAll(
|
|
475
|
+
container,
|
|
476
|
+
(widget) =>
|
|
477
|
+
isMatchingWidgetType(widget, options) && isTextMatch(getWidgetLabelText(widget), text, widget, options),
|
|
478
|
+
);
|
|
517
479
|
}
|
|
518
480
|
|
|
519
481
|
/**
|
|
@@ -524,7 +486,10 @@ function queryAllByText(container: Container, text: Matcher, options?: MatcherOp
|
|
|
524
486
|
* @returns Every matching widget, or an empty array when none match.
|
|
525
487
|
*/
|
|
526
488
|
function queryAllByName(container: Container, name: Matcher, options?: MatcherOptions): Gtk.Widget[] {
|
|
527
|
-
return findAll(
|
|
489
|
+
return findAll(
|
|
490
|
+
container,
|
|
491
|
+
(widget) => isMatchingWidgetType(widget, options) && isTextMatch(getWidgetName(widget), name, widget, options),
|
|
492
|
+
);
|
|
528
493
|
}
|
|
529
494
|
|
|
530
495
|
/**
|
|
@@ -539,7 +504,12 @@ function queryAllByPlaceholderText(
|
|
|
539
504
|
text: Matcher,
|
|
540
505
|
options?: MatcherOptions,
|
|
541
506
|
): Gtk.Widget[] {
|
|
542
|
-
return findAll(
|
|
507
|
+
return findAll(
|
|
508
|
+
container,
|
|
509
|
+
(widget) =>
|
|
510
|
+
isMatchingWidgetType(widget, options) &&
|
|
511
|
+
isTextMatch(getWidgetPlaceholderText(widget), text, widget, options),
|
|
512
|
+
);
|
|
543
513
|
}
|
|
544
514
|
|
|
545
515
|
/**
|
|
@@ -550,7 +520,12 @@ function queryAllByPlaceholderText(
|
|
|
550
520
|
* @returns Every matching widget, or an empty array when none match.
|
|
551
521
|
*/
|
|
552
522
|
function queryAllByDisplayValue(container: Container, value: Matcher, options?: MatcherOptions): Gtk.Widget[] {
|
|
553
|
-
return findAll(
|
|
523
|
+
return findAll(
|
|
524
|
+
container,
|
|
525
|
+
(widget) =>
|
|
526
|
+
isMatchingWidgetType(widget, options) &&
|
|
527
|
+
isTextMatch(getWidgetDisplayValue(widget), value, widget, options),
|
|
528
|
+
);
|
|
554
529
|
}
|
|
555
530
|
|
|
556
531
|
export {
|
|
@@ -585,7 +560,6 @@ export {
|
|
|
585
560
|
getByDisplayValue,
|
|
586
561
|
findAllByDisplayValue,
|
|
587
562
|
findByDisplayValue,
|
|
588
|
-
getDefaultNormalizer,
|
|
589
563
|
queryAllByRole,
|
|
590
564
|
queryAllByLabelText,
|
|
591
565
|
queryAllByText,
|
package/src/render.tsx
CHANGED
|
@@ -97,7 +97,7 @@ const resolveContainer = (container: RenderOptions["container"]): ResolvedContai
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
const window = new Gtk.Window({ defaultWidth: HARNESS_WINDOW_WIDTH, defaultHeight: HARNESS_WINDOW_HEIGHT });
|
|
100
|
-
window.
|
|
100
|
+
window.setDecorated(false);
|
|
101
101
|
|
|
102
102
|
return { containerInfo: window, window };
|
|
103
103
|
};
|
|
@@ -165,7 +165,7 @@ const render = async <Q extends QueryMap = Record<never, never>>(
|
|
|
165
165
|
options?: RenderOptions<Q>,
|
|
166
166
|
): Promise<RenderResult<Q>> => {
|
|
167
167
|
installErrorHandler();
|
|
168
|
-
applyEnableAnimations(options?.
|
|
168
|
+
applyEnableAnimations(options?.areAnimationsEnabled === true);
|
|
169
169
|
const baseElement: Container = options?.baseElement ?? TOPLEVELS;
|
|
170
170
|
const Wrapper = options?.wrapper;
|
|
171
171
|
const resolved = resolveContainer(options?.container);
|
|
@@ -184,7 +184,7 @@ const render = async <Q extends QueryMap = Record<never, never>>(
|
|
|
184
184
|
const wrap = (node: ReactNode): ReactNode => {
|
|
185
185
|
const wrapped = Wrapper ? <Wrapper>{node}</Wrapper> : node;
|
|
186
186
|
|
|
187
|
-
return options?.
|
|
187
|
+
return options?.isReactStrictMode ? <StrictMode>{wrapped}</StrictMode> : wrapped;
|
|
188
188
|
};
|
|
189
189
|
|
|
190
190
|
await update(wrap(element), root);
|
package/src/suggestions.ts
CHANGED
|
@@ -20,10 +20,13 @@ type Method = "Role" | "LabelText" | "PlaceholderText" | "Text" | "DisplayValue"
|
|
|
20
20
|
* `toString` that renders the full call.
|
|
21
21
|
*/
|
|
22
22
|
type Suggestion = {
|
|
23
|
+
/** The query family, such as `Role`. */
|
|
23
24
|
queryName: Method;
|
|
24
25
|
/** The full query function name, such as `getByRole`. */
|
|
25
26
|
queryMethod: string;
|
|
27
|
+
/** The variant the suggestion was asked for, which prefixes `Suggestion.queryMethod`. */
|
|
26
28
|
variant: Variant;
|
|
29
|
+
/** Renders the suggested call with its arguments, such as `getByRole(Gtk.AccessibleRole.BUTTON)`. */
|
|
27
30
|
toString: () => string;
|
|
28
31
|
};
|
|
29
32
|
|
package/src/traversal.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import * as Gtk from "@gtkx/gi/gtk";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* A scope that resolves to a single root widget: the widget itself, the widget a controller or
|
|
5
|
+
* layout manager is attached to, or a list item's or header's child.
|
|
6
|
+
*/
|
|
3
7
|
type QueryContainer = Gtk.Widget | Gtk.EventController | Gtk.LayoutManager | Gtk.ListItem | Gtk.ListHeader;
|
|
4
8
|
/**
|
|
5
9
|
* A scope that queries and traversal can run against: a widget, an event
|
|
@@ -8,6 +12,7 @@ type QueryContainer = Gtk.Widget | Gtk.EventController | Gtk.LayoutManager | Gtk
|
|
|
8
12
|
*/
|
|
9
13
|
type Container = QueryContainer | Gtk.Application | typeof TOPLEVELS;
|
|
10
14
|
|
|
15
|
+
/** Container sentinel that widens a query to every toplevel window currently open. */
|
|
11
16
|
const TOPLEVELS: unique symbol = Symbol("gtkx.toplevels");
|
|
12
17
|
|
|
13
18
|
const isApplication = (container: Container): container is Gtk.Application => container instanceof Gtk.Application;
|