@gtkx/testing 1.0.0-rc.2 → 1.0.0-rc.3
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/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/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 +81 -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/queries.d.ts +3 -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 +1 -1
- package/dist/render.js.map +1 -1
- package/dist/types.d.ts +29 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/user-event/controller.d.ts +2 -1
- package/dist/user-event/controller.d.ts.map +1 -1
- package/dist/user-event/controller.js +8 -1
- package/dist/user-event/controller.js.map +1 -1
- package/dist/widget-accessible-properties.d.ts +12 -2
- package/dist/widget-accessible-properties.d.ts.map +1 -1
- package/dist/widget-accessible-properties.js +112 -10
- package/dist/widget-accessible-properties.js.map +1 -1
- package/dist/within.js.map +1 -1
- package/package.json +6 -6
- package/src/bound-queries.ts +2 -3
- package/src/index.ts +11 -2
- package/src/matchers.ts +456 -53
- package/src/normalize.ts +28 -0
- package/src/queries.ts +78 -105
- package/src/render.tsx +1 -1
- package/src/types.ts +48 -2
- package/src/user-event/controller.ts +21 -1
- package/src/widget-accessible-properties.ts +172 -10
- package/src/within.ts +1 -1
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,10 @@ import {
|
|
|
20
27
|
getWidgetSelectedState,
|
|
21
28
|
getWidgetValue,
|
|
22
29
|
isInaccessible,
|
|
30
|
+
isWidgetChecked,
|
|
23
31
|
} from "./widget-accessible-properties.js";
|
|
24
32
|
|
|
25
|
-
type
|
|
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
|
-
};
|
|
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
|
+
type BuiltinQueries = QueryFamilies<[container: Container]>;
|
|
47
34
|
|
|
48
35
|
const roleQueries = nameQueryFamily(
|
|
49
36
|
"Role",
|
|
@@ -112,167 +99,132 @@ const displayValueQueries = nameQueryFamily(
|
|
|
112
99
|
),
|
|
113
100
|
);
|
|
114
101
|
|
|
115
|
-
const builtinQueries
|
|
102
|
+
const builtinQueries = {
|
|
116
103
|
...roleQueries,
|
|
117
104
|
...labelTextQueries,
|
|
118
105
|
...textQueries,
|
|
119
106
|
...nameQueries,
|
|
120
107
|
...placeholderTextQueries,
|
|
121
108
|
...displayValueQueries,
|
|
122
|
-
};
|
|
109
|
+
} as BuiltinQueries;
|
|
123
110
|
|
|
124
111
|
/**
|
|
125
112
|
* Returns the single widget with a matching accessible role and options, or null when none match.
|
|
126
113
|
* Throws when more than one matches.
|
|
127
114
|
*/
|
|
128
|
-
const queryByRole: BuiltinQueries["queryByRole"] =
|
|
115
|
+
const queryByRole: BuiltinQueries["queryByRole"] = builtinQueries.queryByRole;
|
|
129
116
|
/** Returns every widget with a matching accessible role and options. Throws when none match. */
|
|
130
|
-
const getAllByRole: BuiltinQueries["getAllByRole"] =
|
|
117
|
+
const getAllByRole: BuiltinQueries["getAllByRole"] = builtinQueries.getAllByRole;
|
|
131
118
|
/**
|
|
132
119
|
* Returns the single widget with a matching accessible role and options.
|
|
133
120
|
* Throws when none or more than one matches.
|
|
134
121
|
*/
|
|
135
|
-
const getByRole: BuiltinQueries["getByRole"] =
|
|
122
|
+
const getByRole: BuiltinQueries["getByRole"] = builtinQueries.getByRole;
|
|
136
123
|
/**
|
|
137
124
|
* Waits for and returns every widget with a matching accessible role and options, retrying until at
|
|
138
125
|
* least one appears or the timeout elapses.
|
|
139
126
|
*/
|
|
140
|
-
const findAllByRole: BuiltinQueries["findAllByRole"] =
|
|
127
|
+
const findAllByRole: BuiltinQueries["findAllByRole"] = builtinQueries.findAllByRole;
|
|
141
128
|
/**
|
|
142
129
|
* Waits for and returns the single widget with a matching accessible role and options, retrying
|
|
143
130
|
* until it appears or the timeout elapses. Rejects when none or more than one matches.
|
|
144
131
|
*/
|
|
145
|
-
const findByRole: BuiltinQueries["findByRole"] =
|
|
132
|
+
const findByRole: BuiltinQueries["findByRole"] = builtinQueries.findByRole;
|
|
146
133
|
/**
|
|
147
134
|
* Returns the single widget with matching associated label text, or null when none match.
|
|
148
135
|
* Throws when more than one matches.
|
|
149
136
|
*/
|
|
150
|
-
const queryByLabelText: BuiltinQueries["queryByLabelText"] =
|
|
137
|
+
const queryByLabelText: BuiltinQueries["queryByLabelText"] = builtinQueries.queryByLabelText;
|
|
151
138
|
/** Returns every widget with matching associated label text. Throws when none match. */
|
|
152
|
-
const getAllByLabelText: BuiltinQueries["getAllByLabelText"] =
|
|
139
|
+
const getAllByLabelText: BuiltinQueries["getAllByLabelText"] = builtinQueries.getAllByLabelText;
|
|
153
140
|
/** Returns the single widget with matching associated label text. Throws when none or more than one matches. */
|
|
154
|
-
const getByLabelText: BuiltinQueries["getByLabelText"] =
|
|
141
|
+
const getByLabelText: BuiltinQueries["getByLabelText"] = builtinQueries.getByLabelText;
|
|
155
142
|
/**
|
|
156
143
|
* Waits for and returns every widget with matching associated label text, retrying until at least
|
|
157
144
|
* one appears or the timeout elapses.
|
|
158
145
|
*/
|
|
159
|
-
const findAllByLabelText: BuiltinQueries["findAllByLabelText"] =
|
|
146
|
+
const findAllByLabelText: BuiltinQueries["findAllByLabelText"] = builtinQueries.findAllByLabelText;
|
|
160
147
|
/**
|
|
161
148
|
* Waits for and returns the single widget with matching associated label text, retrying until it
|
|
162
149
|
* appears or the timeout elapses. Rejects when none or more than one matches.
|
|
163
150
|
*/
|
|
164
|
-
const findByLabelText: BuiltinQueries["findByLabelText"] =
|
|
151
|
+
const findByLabelText: BuiltinQueries["findByLabelText"] = builtinQueries.findByLabelText;
|
|
165
152
|
/**
|
|
166
153
|
* Returns the single widget with matching rendered text content, or null when none match.
|
|
167
154
|
* Throws when more than one matches.
|
|
168
155
|
*/
|
|
169
|
-
const queryByText: BuiltinQueries["queryByText"] =
|
|
156
|
+
const queryByText: BuiltinQueries["queryByText"] = builtinQueries.queryByText;
|
|
170
157
|
/** Returns every widget with matching rendered text content. Throws when none match. */
|
|
171
|
-
const getAllByText: BuiltinQueries["getAllByText"] =
|
|
158
|
+
const getAllByText: BuiltinQueries["getAllByText"] = builtinQueries.getAllByText;
|
|
172
159
|
/** Returns the single widget with matching rendered text content. Throws when none or more than one matches. */
|
|
173
|
-
const getByText: BuiltinQueries["getByText"] =
|
|
160
|
+
const getByText: BuiltinQueries["getByText"] = builtinQueries.getByText;
|
|
174
161
|
/**
|
|
175
162
|
* Waits for and returns every widget with matching rendered text content, retrying until at least
|
|
176
163
|
* one appears or the timeout elapses.
|
|
177
164
|
*/
|
|
178
|
-
const findAllByText: BuiltinQueries["findAllByText"] =
|
|
165
|
+
const findAllByText: BuiltinQueries["findAllByText"] = builtinQueries.findAllByText;
|
|
179
166
|
/**
|
|
180
167
|
* Waits for and returns the single widget with matching rendered text content, retrying until it
|
|
181
168
|
* appears or the timeout elapses. Rejects when none or more than one matches.
|
|
182
169
|
*/
|
|
183
|
-
const findByText: BuiltinQueries["findByText"] =
|
|
170
|
+
const findByText: BuiltinQueries["findByText"] = builtinQueries.findByText;
|
|
184
171
|
/**
|
|
185
172
|
* Returns the single widget with a matching widget name, or null when none match.
|
|
186
173
|
* Throws when more than one matches.
|
|
187
174
|
*/
|
|
188
|
-
const queryByName: BuiltinQueries["queryByName"] =
|
|
175
|
+
const queryByName: BuiltinQueries["queryByName"] = builtinQueries.queryByName;
|
|
189
176
|
/** Returns every widget with a matching widget name. Throws when none match. */
|
|
190
|
-
const getAllByName: BuiltinQueries["getAllByName"] =
|
|
177
|
+
const getAllByName: BuiltinQueries["getAllByName"] = builtinQueries.getAllByName;
|
|
191
178
|
/** Returns the single widget with a matching widget name. Throws when none or more than one matches. */
|
|
192
|
-
const getByName: BuiltinQueries["getByName"] =
|
|
179
|
+
const getByName: BuiltinQueries["getByName"] = builtinQueries.getByName;
|
|
193
180
|
/**
|
|
194
181
|
* Waits for and returns every widget with a matching widget name, retrying until at least one
|
|
195
182
|
* appears or the timeout elapses.
|
|
196
183
|
*/
|
|
197
|
-
const findAllByName: BuiltinQueries["findAllByName"] =
|
|
184
|
+
const findAllByName: BuiltinQueries["findAllByName"] = builtinQueries.findAllByName;
|
|
198
185
|
/**
|
|
199
186
|
* Waits for and returns the single widget with a matching widget name, retrying until it appears or
|
|
200
187
|
* the timeout elapses. Rejects when none or more than one matches.
|
|
201
188
|
*/
|
|
202
|
-
const findByName: BuiltinQueries["findByName"] =
|
|
203
|
-
|
|
189
|
+
const findByName: BuiltinQueries["findByName"] = builtinQueries.findByName;
|
|
204
190
|
/**
|
|
205
191
|
* Returns the single widget with matching placeholder text, or null when none match.
|
|
206
192
|
* Throws when more than one matches.
|
|
207
193
|
*/
|
|
208
|
-
const queryByPlaceholderText: BuiltinQueries["queryByPlaceholderText"] =
|
|
209
|
-
placeholderTextQueries.queryByPlaceholderText;
|
|
210
|
-
|
|
194
|
+
const queryByPlaceholderText: BuiltinQueries["queryByPlaceholderText"] = builtinQueries.queryByPlaceholderText;
|
|
211
195
|
/** Returns every widget with matching placeholder text. Throws when none match. */
|
|
212
|
-
const getAllByPlaceholderText: BuiltinQueries["getAllByPlaceholderText"] =
|
|
213
|
-
placeholderTextQueries.getAllByPlaceholderText;
|
|
214
|
-
|
|
196
|
+
const getAllByPlaceholderText: BuiltinQueries["getAllByPlaceholderText"] = builtinQueries.getAllByPlaceholderText;
|
|
215
197
|
/** Returns the single widget with matching placeholder text. Throws when none or more than one matches. */
|
|
216
|
-
const getByPlaceholderText: BuiltinQueries["getByPlaceholderText"] =
|
|
217
|
-
|
|
198
|
+
const getByPlaceholderText: BuiltinQueries["getByPlaceholderText"] = builtinQueries.getByPlaceholderText;
|
|
218
199
|
/**
|
|
219
200
|
* Waits for and returns every widget with matching placeholder text, retrying until at least one
|
|
220
201
|
* appears or the timeout elapses.
|
|
221
202
|
*/
|
|
222
|
-
const findAllByPlaceholderText: BuiltinQueries["findAllByPlaceholderText"] =
|
|
223
|
-
placeholderTextQueries.findAllByPlaceholderText;
|
|
224
|
-
|
|
203
|
+
const findAllByPlaceholderText: BuiltinQueries["findAllByPlaceholderText"] = builtinQueries.findAllByPlaceholderText;
|
|
225
204
|
/**
|
|
226
205
|
* Waits for and returns the single widget with matching placeholder text, retrying until it appears
|
|
227
206
|
* or the timeout elapses. Rejects when none or more than one matches.
|
|
228
207
|
*/
|
|
229
|
-
const findByPlaceholderText: BuiltinQueries["findByPlaceholderText"] =
|
|
230
|
-
placeholderTextQueries.findByPlaceholderText;
|
|
231
|
-
|
|
208
|
+
const findByPlaceholderText: BuiltinQueries["findByPlaceholderText"] = builtinQueries.findByPlaceholderText;
|
|
232
209
|
/**
|
|
233
210
|
* Returns the single widget with a matching display value, or null when none match.
|
|
234
211
|
* Throws when more than one matches.
|
|
235
212
|
*/
|
|
236
|
-
const queryByDisplayValue: BuiltinQueries["queryByDisplayValue"] =
|
|
213
|
+
const queryByDisplayValue: BuiltinQueries["queryByDisplayValue"] = builtinQueries.queryByDisplayValue;
|
|
237
214
|
/** Returns every widget with a matching display value. Throws when none match. */
|
|
238
|
-
const getAllByDisplayValue: BuiltinQueries["getAllByDisplayValue"] =
|
|
215
|
+
const getAllByDisplayValue: BuiltinQueries["getAllByDisplayValue"] = builtinQueries.getAllByDisplayValue;
|
|
239
216
|
/** Returns the single widget with a matching display value. Throws when none or more than one matches. */
|
|
240
|
-
const getByDisplayValue: BuiltinQueries["getByDisplayValue"] =
|
|
217
|
+
const getByDisplayValue: BuiltinQueries["getByDisplayValue"] = builtinQueries.getByDisplayValue;
|
|
241
218
|
/**
|
|
242
219
|
* Waits for and returns every widget with a matching display value, retrying until at least one
|
|
243
220
|
* appears or the timeout elapses.
|
|
244
221
|
*/
|
|
245
|
-
const findAllByDisplayValue: BuiltinQueries["findAllByDisplayValue"] =
|
|
222
|
+
const findAllByDisplayValue: BuiltinQueries["findAllByDisplayValue"] = builtinQueries.findAllByDisplayValue;
|
|
246
223
|
/**
|
|
247
224
|
* Waits for and returns the single widget with a matching display value, retrying until it appears
|
|
248
225
|
* or the timeout elapses. Rejects when none or more than one matches.
|
|
249
226
|
*/
|
|
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
|
-
};
|
|
227
|
+
const findByDisplayValue: BuiltinQueries["findByDisplayValue"] = builtinQueries.findByDisplayValue;
|
|
276
228
|
|
|
277
229
|
const buildNormalizer = (options?: MatcherOptions): NormalizerFn => {
|
|
278
230
|
const { normalizer, trim, collapseWhitespace } = options ?? {};
|
|
@@ -361,7 +313,7 @@ const hasMatchingAccessibleValue = (widget: Gtk.Widget, value: ByRoleValue, opti
|
|
|
361
313
|
|
|
362
314
|
const hasMatchingBooleanStates = (widget: Gtk.Widget, options: ByRoleOptions): boolean => {
|
|
363
315
|
const stateChecks: [boolean | undefined, () => boolean | null][] = [
|
|
364
|
-
[options.checked, () =>
|
|
316
|
+
[options.checked, () => isWidgetChecked(widget)],
|
|
365
317
|
[options.pressed, () => getWidgetPressedState(widget)],
|
|
366
318
|
[options.expanded, () => getWidgetExpandedState(widget)],
|
|
367
319
|
[options.selected, () => getWidgetSelectedState(widget)],
|
|
@@ -393,20 +345,27 @@ const hasMatchingAccessibleStates = (widget: Gtk.Widget, options: ByRoleOptions)
|
|
|
393
345
|
hasMatchingDescriptionState(widget, options) &&
|
|
394
346
|
hasMatchingValueState(widget, options);
|
|
395
347
|
|
|
348
|
+
const isMatchingWidgetType = (widget: Gtk.Widget, options?: MatcherOptions): boolean =>
|
|
349
|
+
options?.as === undefined || widget instanceof options.as;
|
|
350
|
+
|
|
396
351
|
const hasMatchingByRoleOptions = (widget: Gtk.Widget, options?: ByRoleOptions): boolean => {
|
|
397
352
|
if (!options) {
|
|
398
353
|
return true;
|
|
399
354
|
}
|
|
400
355
|
|
|
401
|
-
return
|
|
356
|
+
return (
|
|
357
|
+
isMatchingWidgetType(widget, options) &&
|
|
358
|
+
hasMatchingAccessibleName(widget, options) &&
|
|
359
|
+
hasMatchingAccessibleStates(widget, options)
|
|
360
|
+
);
|
|
402
361
|
};
|
|
403
362
|
|
|
404
|
-
function nameQueryFamily<
|
|
405
|
-
suffix:
|
|
363
|
+
function nameQueryFamily<Args extends unknown[]>(
|
|
364
|
+
suffix: string,
|
|
406
365
|
queryAllBy: QueryAllBy<Args>,
|
|
407
366
|
built: BuiltQueries<Args>,
|
|
408
|
-
):
|
|
409
|
-
|
|
367
|
+
): Record<string, unknown> {
|
|
368
|
+
return {
|
|
410
369
|
[`queryBy${suffix}`]: built.queryBy,
|
|
411
370
|
[`queryAllBy${suffix}`]: queryAllBy,
|
|
412
371
|
[`getBy${suffix}`]: built.getBy,
|
|
@@ -414,8 +373,6 @@ function nameQueryFamily<Suffix extends string, Args extends unknown[]>(
|
|
|
414
373
|
[`findBy${suffix}`]: built.findBy,
|
|
415
374
|
[`findAllBy${suffix}`]: built.findAllBy,
|
|
416
375
|
};
|
|
417
|
-
|
|
418
|
-
return family as NamedFamily<Suffix, Args>;
|
|
419
376
|
}
|
|
420
377
|
|
|
421
378
|
/**
|
|
@@ -502,7 +459,7 @@ function queryAllByLabelText(container: Container, text: Matcher, options?: Matc
|
|
|
502
459
|
collectLabelMatches(results, widget, text, options);
|
|
503
460
|
}
|
|
504
461
|
|
|
505
|
-
return [...results];
|
|
462
|
+
return [...results].filter((widget) => isMatchingWidgetType(widget, options));
|
|
506
463
|
}
|
|
507
464
|
|
|
508
465
|
/**
|
|
@@ -513,7 +470,11 @@ function queryAllByLabelText(container: Container, text: Matcher, options?: Matc
|
|
|
513
470
|
* @returns Every matching widget, or an empty array when none match.
|
|
514
471
|
*/
|
|
515
472
|
function queryAllByText(container: Container, text: Matcher, options?: MatcherOptions): Gtk.Widget[] {
|
|
516
|
-
return findAll(
|
|
473
|
+
return findAll(
|
|
474
|
+
container,
|
|
475
|
+
(widget) =>
|
|
476
|
+
isMatchingWidgetType(widget, options) && isTextMatch(getWidgetLabelText(widget), text, widget, options),
|
|
477
|
+
);
|
|
517
478
|
}
|
|
518
479
|
|
|
519
480
|
/**
|
|
@@ -524,7 +485,10 @@ function queryAllByText(container: Container, text: Matcher, options?: MatcherOp
|
|
|
524
485
|
* @returns Every matching widget, or an empty array when none match.
|
|
525
486
|
*/
|
|
526
487
|
function queryAllByName(container: Container, name: Matcher, options?: MatcherOptions): Gtk.Widget[] {
|
|
527
|
-
return findAll(
|
|
488
|
+
return findAll(
|
|
489
|
+
container,
|
|
490
|
+
(widget) => isMatchingWidgetType(widget, options) && isTextMatch(getWidgetName(widget), name, widget, options),
|
|
491
|
+
);
|
|
528
492
|
}
|
|
529
493
|
|
|
530
494
|
/**
|
|
@@ -539,7 +503,12 @@ function queryAllByPlaceholderText(
|
|
|
539
503
|
text: Matcher,
|
|
540
504
|
options?: MatcherOptions,
|
|
541
505
|
): Gtk.Widget[] {
|
|
542
|
-
return findAll(
|
|
506
|
+
return findAll(
|
|
507
|
+
container,
|
|
508
|
+
(widget) =>
|
|
509
|
+
isMatchingWidgetType(widget, options) &&
|
|
510
|
+
isTextMatch(getWidgetPlaceholderText(widget), text, widget, options),
|
|
511
|
+
);
|
|
543
512
|
}
|
|
544
513
|
|
|
545
514
|
/**
|
|
@@ -550,7 +519,12 @@ function queryAllByPlaceholderText(
|
|
|
550
519
|
* @returns Every matching widget, or an empty array when none match.
|
|
551
520
|
*/
|
|
552
521
|
function queryAllByDisplayValue(container: Container, value: Matcher, options?: MatcherOptions): Gtk.Widget[] {
|
|
553
|
-
return findAll(
|
|
522
|
+
return findAll(
|
|
523
|
+
container,
|
|
524
|
+
(widget) =>
|
|
525
|
+
isMatchingWidgetType(widget, options) &&
|
|
526
|
+
isTextMatch(getWidgetDisplayValue(widget), value, widget, options),
|
|
527
|
+
);
|
|
554
528
|
}
|
|
555
529
|
|
|
556
530
|
export {
|
|
@@ -585,7 +559,6 @@ export {
|
|
|
585
559
|
getByDisplayValue,
|
|
586
560
|
findAllByDisplayValue,
|
|
587
561
|
findByDisplayValue,
|
|
588
|
-
getDefaultNormalizer,
|
|
589
562
|
queryAllByRole,
|
|
590
563
|
queryAllByLabelText,
|
|
591
564
|
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
|
};
|
package/src/types.ts
CHANGED
|
@@ -13,6 +13,11 @@ type MatcherFunction = (content: string, widget: Gtk.Widget) => boolean;
|
|
|
13
13
|
type Matcher = string | number | RegExp | MatcherFunction;
|
|
14
14
|
/** Normalizes a widget's text before it is compared against a matcher. */
|
|
15
15
|
type NormalizerFn = (text: string) => string;
|
|
16
|
+
/**
|
|
17
|
+
* A widget class usable as a query's `as` constraint, such as `Gtk.Button`. Abstract classes and
|
|
18
|
+
* generated GInterface pseudo-classes are accepted.
|
|
19
|
+
*/
|
|
20
|
+
type WidgetType<T extends Gtk.Widget = Gtk.Widget> = abstract new (...args: never[]) => T;
|
|
16
21
|
|
|
17
22
|
/** Options controlling the default text normalizer. */
|
|
18
23
|
type NormalizerOptions = {
|
|
@@ -35,7 +40,7 @@ type WaitForOptions = {
|
|
|
35
40
|
};
|
|
36
41
|
|
|
37
42
|
/** Options controlling text matching and, for asynchronous queries, polling behavior. */
|
|
38
|
-
type MatcherOptions = {
|
|
43
|
+
type MatcherOptions<T extends Gtk.Widget = Gtk.Widget> = {
|
|
39
44
|
/** When true (the default), require an exact match; when false, match case-insensitively as a substring. */
|
|
40
45
|
exact?: boolean | undefined;
|
|
41
46
|
/** Custom normalizer replacing the default; cannot be combined with `trim` or `collapseWhitespace`. */
|
|
@@ -46,6 +51,8 @@ type MatcherOptions = {
|
|
|
46
51
|
collapseWhitespace?: boolean | undefined;
|
|
47
52
|
/** Whether to include a suggested better query in error messages. */
|
|
48
53
|
suggest?: boolean | undefined;
|
|
54
|
+
/** Restricts matches to instances of this widget class, and narrows the query's return type to it. */
|
|
55
|
+
as?: WidgetType<T> | undefined;
|
|
49
56
|
} & WaitForOptions;
|
|
50
57
|
|
|
51
58
|
/** Constraints on a widget's numeric range value used by role queries. */
|
|
@@ -59,7 +66,7 @@ type ByRoleValue = {
|
|
|
59
66
|
};
|
|
60
67
|
|
|
61
68
|
/** Options for role queries: an accessible name matcher plus accessible state and value constraints. */
|
|
62
|
-
type ByRoleOptions = MatcherOptions & {
|
|
69
|
+
type ByRoleOptions<T extends Gtk.Widget = Gtk.Widget> = MatcherOptions<T> & {
|
|
63
70
|
name?: Matcher | undefined;
|
|
64
71
|
checked?: boolean | undefined;
|
|
65
72
|
pressed?: boolean | undefined;
|
|
@@ -88,6 +95,43 @@ type BoundQuery<Q extends Query> = Q extends (container: Container, ...args: inf
|
|
|
88
95
|
|
|
89
96
|
type BoundCustomQueries<Q extends QueryMap> = { [K in keyof Q]: BoundQuery<Q[K]> };
|
|
90
97
|
|
|
98
|
+
type QueryFamilyReturns<T extends Gtk.Widget> = {
|
|
99
|
+
queryBy: T | null;
|
|
100
|
+
queryAllBy: T[];
|
|
101
|
+
getBy: T;
|
|
102
|
+
getAllBy: T[];
|
|
103
|
+
findBy: Promise<T>;
|
|
104
|
+
findAllBy: Promise<T[]>;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
type QueryKind = "role" | "text" | "name" | "value";
|
|
108
|
+
|
|
109
|
+
type QueryArgs<Kind extends QueryKind, T extends Gtk.Widget> = Kind extends "role"
|
|
110
|
+
? [role: Gtk.AccessibleRole, options?: ByRoleOptions<T>]
|
|
111
|
+
: Kind extends "name"
|
|
112
|
+
? [name: Matcher, options?: MatcherOptions<T>]
|
|
113
|
+
: Kind extends "value"
|
|
114
|
+
? [value: Matcher, options?: MatcherOptions<T>]
|
|
115
|
+
: [text: Matcher, options?: MatcherOptions<T>];
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* One query family (`queryBy`, `getBy`, `findBy` and their `All` variants) for a single suffix.
|
|
119
|
+
* Each member takes an explicit widget type, as Testing Library's queries do, and also infers it
|
|
120
|
+
* from an `as` option.
|
|
121
|
+
*/
|
|
122
|
+
type QueryFamily<Suffix extends string, Kind extends QueryKind, Head extends unknown[]> = {
|
|
123
|
+
[K in keyof QueryFamilyReturns<Gtk.Widget> as `${K & string}${Suffix}`]: <T extends Gtk.Widget = Gtk.Widget>(
|
|
124
|
+
...args: [...Head, ...QueryArgs<Kind, T>]
|
|
125
|
+
) => QueryFamilyReturns<T>[K];
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
type QueryFamilies<Head extends unknown[]> = QueryFamily<"Role", "role", Head> &
|
|
129
|
+
QueryFamily<"LabelText", "text", Head> &
|
|
130
|
+
QueryFamily<"Text", "text", Head> &
|
|
131
|
+
QueryFamily<"Name", "name", Head> &
|
|
132
|
+
QueryFamily<"PlaceholderText", "text", Head> &
|
|
133
|
+
QueryFamily<"DisplayValue", "value", Head>;
|
|
134
|
+
|
|
91
135
|
/**
|
|
92
136
|
* Options for {@link render}: the container and base element to mount into, an optional wrapper,
|
|
93
137
|
* React behavior toggles, error callbacks, and custom queries to bind.
|
|
@@ -169,9 +213,11 @@ export {
|
|
|
169
213
|
type MatcherOptions,
|
|
170
214
|
type ByRoleValue,
|
|
171
215
|
type ByRoleOptions,
|
|
216
|
+
type WidgetType,
|
|
172
217
|
type WrapperComponent,
|
|
173
218
|
type QueryMap,
|
|
174
219
|
type BoundCustomQueries,
|
|
220
|
+
type QueryFamilies,
|
|
175
221
|
type RenderOptions,
|
|
176
222
|
type DebugUtilities,
|
|
177
223
|
type ScreenshotResult,
|
|
@@ -39,6 +39,19 @@ const getAllControllers = <T extends Gtk.EventController>(
|
|
|
39
39
|
return controllers;
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
+
const getController = <T extends Gtk.EventController>(
|
|
43
|
+
widget: Gtk.Widget,
|
|
44
|
+
controllerType: ControllerConstructor<T>,
|
|
45
|
+
): T => {
|
|
46
|
+
const [controller] = getAllControllers(widget, controllerType);
|
|
47
|
+
|
|
48
|
+
if (controller === undefined) {
|
|
49
|
+
throw new Error(`No ${controllerType.name} controller is attached to the widget`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return controller;
|
|
53
|
+
};
|
|
54
|
+
|
|
42
55
|
const getOrCreateControllers = <T extends Gtk.EventController>(
|
|
43
56
|
widget: Gtk.Widget,
|
|
44
57
|
controllerType: ControllerConstructor<T>,
|
|
@@ -55,4 +68,11 @@ const getOrCreateControllers = <T extends Gtk.EventController>(
|
|
|
55
68
|
return [controller];
|
|
56
69
|
};
|
|
57
70
|
|
|
58
|
-
export {
|
|
71
|
+
export {
|
|
72
|
+
queryAllControllers,
|
|
73
|
+
queryController,
|
|
74
|
+
getAllControllers,
|
|
75
|
+
getController,
|
|
76
|
+
getOrCreateControllers,
|
|
77
|
+
type ControllerConstructor,
|
|
78
|
+
};
|