@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
|
@@ -11,9 +11,19 @@ type WidgetValue = {
|
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
type ValueTriplet = { now: number | null; min: number | null; max: number | null };
|
|
14
|
+
/** A widget's checked state: on, off, or the mixed state of an inconsistent check button. */
|
|
15
|
+
type CheckedState = "checked" | "unchecked" | "mixed";
|
|
14
16
|
|
|
15
17
|
const DEFAULT_TEXT_GETTERS = ["getLabel", "getText", "getTitle"] as const;
|
|
16
18
|
|
|
19
|
+
const SELECTABLE_ROLES: Set<Gtk.AccessibleRole> = new Set<Gtk.AccessibleRole>([
|
|
20
|
+
Gtk.AccessibleRole.ROW,
|
|
21
|
+
Gtk.AccessibleRole.LIST_ITEM,
|
|
22
|
+
Gtk.AccessibleRole.GRID_CELL,
|
|
23
|
+
Gtk.AccessibleRole.OPTION,
|
|
24
|
+
Gtk.AccessibleRole.TREE_ITEM,
|
|
25
|
+
]);
|
|
26
|
+
|
|
17
27
|
const callStringGetter = (widget: Gtk.Widget, method: string): string | null => {
|
|
18
28
|
const fn: unknown = Reflect.get(widget, method);
|
|
19
29
|
|
|
@@ -129,6 +139,49 @@ const getWidgetLabelText = (widget: Gtk.Widget): string | null => {
|
|
|
129
139
|
return getLabelText(widget);
|
|
130
140
|
};
|
|
131
141
|
|
|
142
|
+
const getChildren = function* (widget: Gtk.Widget): Generator<Gtk.Widget> {
|
|
143
|
+
let child = widget.getFirstChild();
|
|
144
|
+
|
|
145
|
+
while (child) {
|
|
146
|
+
yield child;
|
|
147
|
+
child = child.getNextSibling();
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const textContentParts = (widget: Gtk.Widget): string[] => {
|
|
152
|
+
const own = getWidgetNodeText(widget);
|
|
153
|
+
|
|
154
|
+
if (own !== null) {
|
|
155
|
+
return [own];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return [...getChildren(widget)].flatMap((child) => textContentParts(child));
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const getWidgetTextContent = (widget: Gtk.Widget): string | null => {
|
|
162
|
+
const parts = textContentParts(widget);
|
|
163
|
+
|
|
164
|
+
return parts.length > 0 ? parts.join(" ") : null;
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const isComboBoxFaceCandidate = (widget: Gtk.Widget): boolean =>
|
|
168
|
+
!(widget instanceof Gtk.Popover) && widget.getChildVisible();
|
|
169
|
+
|
|
170
|
+
const comboBoxChildFaceText = (child: Gtk.Widget): string | null =>
|
|
171
|
+
isComboBoxFaceCandidate(child) ? getWidgetLabelText(child) ?? comboBoxFaceText(child) : null;
|
|
172
|
+
|
|
173
|
+
const comboBoxFaceText = (widget: Gtk.Widget): string | null => {
|
|
174
|
+
for (const child of getChildren(widget)) {
|
|
175
|
+
const text = comboBoxChildFaceText(child);
|
|
176
|
+
|
|
177
|
+
if (text !== null) {
|
|
178
|
+
return text;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return null;
|
|
183
|
+
};
|
|
184
|
+
|
|
132
185
|
const tabPanelTitle = (widget: Gtk.Widget): string | null => {
|
|
133
186
|
const parent = widget.getParent();
|
|
134
187
|
|
|
@@ -146,6 +199,12 @@ const getWidgetAccessibleName = (widget: Gtk.Widget): string | null => {
|
|
|
146
199
|
return tabPanelTitle(widget);
|
|
147
200
|
}
|
|
148
201
|
|
|
202
|
+
const labelledByText = getWidgetLabelledByText(widget);
|
|
203
|
+
|
|
204
|
+
if (labelledByText) {
|
|
205
|
+
return labelledByText;
|
|
206
|
+
}
|
|
207
|
+
|
|
149
208
|
const accessibleLabel = readAccessibleString(widget, "accessibleLabel");
|
|
150
209
|
|
|
151
210
|
if (accessibleLabel) {
|
|
@@ -176,7 +235,15 @@ const getWidgetPlaceholderText = (widget: Gtk.Widget): string | null => {
|
|
|
176
235
|
return null;
|
|
177
236
|
}
|
|
178
237
|
|
|
179
|
-
|
|
238
|
+
const fromGetter = callStringGetter(widget, "getPlaceholderText");
|
|
239
|
+
|
|
240
|
+
if (fromGetter !== null) {
|
|
241
|
+
return fromGetter;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const fromAccessor: unknown = Reflect.get(widget, "placeholderText");
|
|
245
|
+
|
|
246
|
+
return typeof fromAccessor === "string" && fromAccessor !== "" ? fromAccessor : null;
|
|
180
247
|
};
|
|
181
248
|
|
|
182
249
|
const getWidgetDisplayValue = (widget: Gtk.Widget): string | null => {
|
|
@@ -184,25 +251,89 @@ const getWidgetDisplayValue = (widget: Gtk.Widget): string | null => {
|
|
|
184
251
|
return readEditableText(widget);
|
|
185
252
|
}
|
|
186
253
|
|
|
254
|
+
if (widget.getAccessibleRole() === Gtk.AccessibleRole.COMBO_BOX) {
|
|
255
|
+
return comboBoxFaceText(widget);
|
|
256
|
+
}
|
|
257
|
+
|
|
187
258
|
return null;
|
|
188
259
|
};
|
|
189
260
|
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
261
|
+
const hasDisplayValue = (widget: Gtk.Widget): boolean => {
|
|
262
|
+
const role = widget.getAccessibleRole();
|
|
263
|
+
|
|
264
|
+
return (EDITABLE_ROLES.has(role) && isEditable(widget)) || role === Gtk.AccessibleRole.COMBO_BOX;
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
const isWidgetDisabled = (widget: Gtk.Widget): boolean => !widget.isSensitive();
|
|
268
|
+
|
|
269
|
+
const hasZeroOpacityAncestor = (widget: Gtk.Widget): boolean => {
|
|
270
|
+
let current: Gtk.Widget | null = widget;
|
|
271
|
+
|
|
272
|
+
while (current) {
|
|
273
|
+
if (current.getOpacity() === 0) {
|
|
274
|
+
return true;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
current = current.getParent();
|
|
193
278
|
}
|
|
194
279
|
|
|
195
|
-
|
|
196
|
-
|
|
280
|
+
return false;
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
const isWidgetVisible = (widget: Gtk.Widget): boolean => widget.isVisible() && !hasZeroOpacityAncestor(widget);
|
|
284
|
+
|
|
285
|
+
const getWidgetRequiredState = (widget: Gtk.Widget): boolean | null =>
|
|
286
|
+
readAccessibleBoolean(widget, "accessibleRequired");
|
|
287
|
+
|
|
288
|
+
const readTextViewSelection = (view: Gtk.TextView): string | null => {
|
|
289
|
+
const buffer = view.getBuffer();
|
|
290
|
+
const [hasSelection, start, end] = buffer.getSelectionBounds();
|
|
291
|
+
|
|
292
|
+
return hasSelection ? buffer.getText(start, end, true) : null;
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
const readEditableSelection = (editable: Gtk.Editable): string | null => {
|
|
296
|
+
const [hasSelection, start, end] = editable.getSelectionBounds();
|
|
297
|
+
|
|
298
|
+
return hasSelection ? editable.getChars(start, end) : null;
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const getWidgetSelection = (widget: Gtk.Widget): string | null => {
|
|
302
|
+
if (widget instanceof Gtk.TextView) {
|
|
303
|
+
return readTextViewSelection(widget);
|
|
197
304
|
}
|
|
198
305
|
|
|
199
|
-
if (widget instanceof Gtk.
|
|
200
|
-
return widget
|
|
306
|
+
if (widget instanceof Gtk.Editable) {
|
|
307
|
+
return readEditableSelection(widget);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return null;
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
const checkedFromActive = (isActive: boolean): CheckedState => (isActive ? "checked" : "unchecked");
|
|
314
|
+
|
|
315
|
+
const isCheckableToggle = (widget: Gtk.Widget): boolean =>
|
|
316
|
+
widget instanceof Gtk.Switch ||
|
|
317
|
+
(widget instanceof Gtk.ToggleButton && widget.getAccessibleRole() === Gtk.AccessibleRole.RADIO);
|
|
318
|
+
|
|
319
|
+
const getWidgetCheckedState = (widget: Gtk.Widget): CheckedState | null => {
|
|
320
|
+
if (widget instanceof Gtk.CheckButton) {
|
|
321
|
+
return widget.getInconsistent() ? "mixed" : checkedFromActive(widget.getActive());
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (isCheckableToggle(widget)) {
|
|
325
|
+
return checkedFromActive(Reflect.get(widget, "active") === true);
|
|
201
326
|
}
|
|
202
327
|
|
|
203
328
|
return null;
|
|
204
329
|
};
|
|
205
330
|
|
|
331
|
+
const isWidgetChecked = (widget: Gtk.Widget): boolean | null => {
|
|
332
|
+
const state = getWidgetCheckedState(widget);
|
|
333
|
+
|
|
334
|
+
return state === null || state === "mixed" ? null : state === "checked";
|
|
335
|
+
};
|
|
336
|
+
|
|
206
337
|
const getWidgetPressedState = (widget: Gtk.Widget): boolean | null => {
|
|
207
338
|
if (widget instanceof Gtk.ToggleButton) {
|
|
208
339
|
return widget.getActive();
|
|
@@ -224,11 +355,11 @@ const getWidgetExpandedState = (widget: Gtk.Widget): boolean | null => {
|
|
|
224
355
|
};
|
|
225
356
|
|
|
226
357
|
const getWidgetSelectedState = (widget: Gtk.Widget): boolean | null => {
|
|
227
|
-
if (widget instanceof Gtk.ListBoxRow) {
|
|
358
|
+
if (widget instanceof Gtk.ListBoxRow || widget instanceof Gtk.FlowBoxChild) {
|
|
228
359
|
return widget.isSelected();
|
|
229
360
|
}
|
|
230
361
|
|
|
231
|
-
if (widget.getAccessibleRole()
|
|
362
|
+
if (SELECTABLE_ROLES.has(widget.getAccessibleRole())) {
|
|
232
363
|
return (widget.getStateFlags() & Gtk.StateFlags.SELECTED) !== 0;
|
|
233
364
|
}
|
|
234
365
|
|
|
@@ -346,6 +477,28 @@ const getWidgetLabelledByText = (widget: Gtk.Widget): string | null => {
|
|
|
346
477
|
return texts.length > 0 ? texts.join(" ") : null;
|
|
347
478
|
};
|
|
348
479
|
|
|
480
|
+
const isTooltipUsedAsName = (widget: Gtk.Widget): boolean =>
|
|
481
|
+
readAccessibleString(widget, "accessibleLabel") === null &&
|
|
482
|
+
getWidgetNodeText(widget) === null &&
|
|
483
|
+
collectLabels(widget).length === 0;
|
|
484
|
+
|
|
485
|
+
const getWidgetDescribedByText = (widget: Gtk.Widget): string | null => {
|
|
486
|
+
const targets = readAccessibleWidgets(widget, "accessibleDescribedBy");
|
|
487
|
+
const texts = targets === null ? [] : collectAccessibleNames(targets);
|
|
488
|
+
|
|
489
|
+
if (texts.length > 0) {
|
|
490
|
+
return texts.join(" ");
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const description = readAccessibleString(widget, "accessibleDescription");
|
|
494
|
+
|
|
495
|
+
if (description !== null) {
|
|
496
|
+
return description;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
return isTooltipUsedAsName(widget) ? null : callStringGetter(widget, "getTooltipText");
|
|
500
|
+
};
|
|
501
|
+
|
|
349
502
|
const isInaccessible = (widget: Gtk.Widget): boolean => {
|
|
350
503
|
let current: Gtk.Widget | null = widget;
|
|
351
504
|
|
|
@@ -366,12 +519,20 @@ const isInaccessible = (widget: Gtk.Widget): boolean => {
|
|
|
366
519
|
|
|
367
520
|
export {
|
|
368
521
|
getWidgetNodeText,
|
|
522
|
+
getWidgetTextContent,
|
|
369
523
|
getWidgetLabelText,
|
|
370
524
|
getWidgetAccessibleName,
|
|
371
525
|
getWidgetName,
|
|
372
526
|
getWidgetPlaceholderText,
|
|
373
527
|
getWidgetDisplayValue,
|
|
528
|
+
hasDisplayValue,
|
|
529
|
+
isWidgetDisabled,
|
|
530
|
+
isWidgetVisible,
|
|
531
|
+
getWidgetRequiredState,
|
|
532
|
+
getWidgetSelection,
|
|
533
|
+
getWidgetDescribedByText,
|
|
374
534
|
getWidgetCheckedState,
|
|
535
|
+
isWidgetChecked,
|
|
375
536
|
getWidgetPressedState,
|
|
376
537
|
getWidgetExpandedState,
|
|
377
538
|
getWidgetSelectedState,
|
|
@@ -384,5 +545,6 @@ export {
|
|
|
384
545
|
getWidgetOwnLabel,
|
|
385
546
|
getWidgetLabelledByText,
|
|
386
547
|
isInaccessible,
|
|
548
|
+
type CheckedState,
|
|
387
549
|
type WidgetValue,
|
|
388
550
|
};
|
package/src/within.ts
CHANGED
|
@@ -26,7 +26,7 @@ const within = <Q extends QueryMap = Record<never, never>>(
|
|
|
26
26
|
container: Container,
|
|
27
27
|
queries?: Q,
|
|
28
28
|
): BoundQueries & BoundCustomQueries<Q> => ({
|
|
29
|
-
...bindCustomQueries(builtinQueries, container),
|
|
29
|
+
...(bindCustomQueries(builtinQueries, container) as BoundQueries),
|
|
30
30
|
...(queries ? bindCustomQueries(queries, container) : ({} as BoundCustomQueries<Q>)),
|
|
31
31
|
});
|
|
32
32
|
|