@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.
Files changed (121) hide show
  1. package/README.md +4 -5
  2. package/dist/act.d.ts +2 -0
  3. package/dist/act.d.ts.map +1 -1
  4. package/dist/act.js.map +1 -1
  5. package/dist/bound-queries.d.ts +2 -3
  6. package/dist/bound-queries.d.ts.map +1 -1
  7. package/dist/bound-queries.js.map +1 -1
  8. package/dist/build-queries.d.ts.map +1 -1
  9. package/dist/build-queries.js +18 -7
  10. package/dist/build-queries.js.map +1 -1
  11. package/dist/config.d.ts +1 -0
  12. package/dist/config.d.ts.map +1 -1
  13. package/dist/config.js +3 -3
  14. package/dist/config.js.map +1 -1
  15. package/dist/errors.js +2 -2
  16. package/dist/errors.js.map +1 -1
  17. package/dist/index.d.ts +7 -4
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +4 -2
  20. package/dist/index.js.map +1 -1
  21. package/dist/matchers.d.ts +125 -21
  22. package/dist/matchers.d.ts.map +1 -1
  23. package/dist/matchers.js +258 -21
  24. package/dist/matchers.js.map +1 -1
  25. package/dist/normalize.d.ts +10 -0
  26. package/dist/normalize.d.ts.map +1 -0
  27. package/dist/normalize.js +20 -0
  28. package/dist/normalize.js.map +1 -0
  29. package/dist/pretty-widget.d.ts +2 -1
  30. package/dist/pretty-widget.d.ts.map +1 -1
  31. package/dist/pretty-widget.js +3 -3
  32. package/dist/pretty-widget.js.map +1 -1
  33. package/dist/queries.d.ts +4 -21
  34. package/dist/queries.d.ts.map +1 -1
  35. package/dist/queries.js +46 -59
  36. package/dist/queries.js.map +1 -1
  37. package/dist/render.js +3 -3
  38. package/dist/render.js.map +1 -1
  39. package/dist/suggestions.d.ts +3 -0
  40. package/dist/suggestions.d.ts.map +1 -1
  41. package/dist/suggestions.js.map +1 -1
  42. package/dist/traversal.d.ts +5 -0
  43. package/dist/traversal.d.ts.map +1 -1
  44. package/dist/traversal.js +1 -0
  45. package/dist/traversal.js.map +1 -1
  46. package/dist/types.d.ts +69 -5
  47. package/dist/types.d.ts.map +1 -1
  48. package/dist/types.js.map +1 -1
  49. package/dist/user-event/adjustment.d.ts +13 -0
  50. package/dist/user-event/adjustment.d.ts.map +1 -1
  51. package/dist/user-event/adjustment.js +11 -0
  52. package/dist/user-event/adjustment.js.map +1 -1
  53. package/dist/user-event/click.d.ts +7 -0
  54. package/dist/user-event/click.d.ts.map +1 -1
  55. package/dist/user-event/click.js +7 -0
  56. package/dist/user-event/click.js.map +1 -1
  57. package/dist/user-event/controller.d.ts +31 -1
  58. package/dist/user-event/controller.d.ts.map +1 -1
  59. package/dist/user-event/controller.js +36 -1
  60. package/dist/user-event/controller.js.map +1 -1
  61. package/dist/user-event/gesture.d.ts +51 -0
  62. package/dist/user-event/gesture.d.ts.map +1 -1
  63. package/dist/user-event/gesture.js +47 -4
  64. package/dist/user-event/gesture.js.map +1 -1
  65. package/dist/user-event/index.d.ts +27 -0
  66. package/dist/user-event/index.d.ts.map +1 -1
  67. package/dist/user-event/index.js.map +1 -1
  68. package/dist/user-event/keyboard.d.ts +4 -2
  69. package/dist/user-event/keyboard.d.ts.map +1 -1
  70. package/dist/user-event/keyboard.js +13 -12
  71. package/dist/user-event/keyboard.js.map +1 -1
  72. package/dist/user-event/pointer.js +5 -5
  73. package/dist/user-event/pointer.js.map +1 -1
  74. package/dist/user-event/selection.d.ts +15 -0
  75. package/dist/user-event/selection.d.ts.map +1 -1
  76. package/dist/user-event/selection.js +15 -0
  77. package/dist/user-event/selection.js.map +1 -1
  78. package/dist/user-event/state.d.ts +1 -1
  79. package/dist/user-event/state.d.ts.map +1 -1
  80. package/dist/user-event/state.js +1 -1
  81. package/dist/user-event/state.js.map +1 -1
  82. package/dist/user-event/text.d.ts +30 -3
  83. package/dist/user-event/text.d.ts.map +1 -1
  84. package/dist/user-event/text.js +28 -1
  85. package/dist/user-event/text.js.map +1 -1
  86. package/dist/wait-for.d.ts +2 -0
  87. package/dist/wait-for.d.ts.map +1 -1
  88. package/dist/wait-for.js.map +1 -1
  89. package/dist/widget-accessible-properties.d.ts +28 -2
  90. package/dist/widget-accessible-properties.d.ts.map +1 -1
  91. package/dist/widget-accessible-properties.js +129 -10
  92. package/dist/widget-accessible-properties.js.map +1 -1
  93. package/dist/within.js.map +1 -1
  94. package/package.json +7 -7
  95. package/src/act.ts +2 -0
  96. package/src/bound-queries.ts +2 -3
  97. package/src/build-queries.ts +20 -8
  98. package/src/config.ts +4 -3
  99. package/src/errors.ts +2 -2
  100. package/src/index.ts +11 -2
  101. package/src/matchers.ts +500 -53
  102. package/src/normalize.ts +28 -0
  103. package/src/pretty-widget.ts +5 -4
  104. package/src/queries.ts +79 -105
  105. package/src/render.tsx +3 -3
  106. package/src/suggestions.ts +3 -0
  107. package/src/traversal.ts +5 -0
  108. package/src/types.ts +88 -4
  109. package/src/user-event/adjustment.ts +13 -0
  110. package/src/user-event/click.ts +7 -0
  111. package/src/user-event/controller.ts +50 -1
  112. package/src/user-event/gesture.ts +57 -6
  113. package/src/user-event/index.ts +27 -0
  114. package/src/user-event/keyboard.ts +18 -16
  115. package/src/user-event/pointer.ts +5 -5
  116. package/src/user-event/selection.ts +15 -0
  117. package/src/user-event/state.ts +2 -2
  118. package/src/user-event/text.ts +31 -4
  119. package/src/wait-for.ts +2 -0
  120. package/src/widget-accessible-properties.ts +188 -10
  121. package/src/within.ts +1 -1
@@ -20,21 +20,21 @@ const applyPointerInput = (widget: Gtk.Widget, state: UserEventState, input: Poi
20
20
  if (CLICK_INPUTS.has(input)) {
21
21
  emitPress(widget, controllers, 1);
22
22
  emitRelease(widget, controllers, 1);
23
- state.mouseLeftDown = false;
23
+ state.isMouseLeftDown = false;
24
24
 
25
25
  return;
26
26
  }
27
27
 
28
- if (PRESS_INPUTS.has(input) && !state.mouseLeftDown) {
28
+ if (PRESS_INPUTS.has(input) && !state.isMouseLeftDown) {
29
29
  emitPress(widget, controllers, 1);
30
- state.mouseLeftDown = true;
30
+ state.isMouseLeftDown = true;
31
31
 
32
32
  return;
33
33
  }
34
34
 
35
- if (RELEASE_INPUTS.has(input) && state.mouseLeftDown) {
35
+ if (RELEASE_INPUTS.has(input) && state.isMouseLeftDown) {
36
36
  emitRelease(widget, controllers, 1);
37
- state.mouseLeftDown = false;
37
+ state.isMouseLeftDown = false;
38
38
  }
39
39
  };
40
40
 
@@ -134,6 +134,14 @@ const runSelectionEvent = (
134
134
  byRole(widget, valueArray);
135
135
  });
136
136
 
137
+ /**
138
+ * Selects the items at the given positions through a list, grid, or column view's selection model,
139
+ * by setting the active item of a drop-down or combo box, or by selecting list box rows. An empty
140
+ * array clears a view's selection.
141
+ *
142
+ * @throws When a view has no selection model, when a combo box is given more than one position, or
143
+ * when the widget is neither a view nor something with the combo box or list role.
144
+ */
137
145
  const selectOptions = (widget: Gtk.Widget, values: number | number[]): Promise<void> =>
138
146
  runSelectionEvent(widget, values, selectInListView, selectByRole);
139
147
 
@@ -153,6 +161,13 @@ const deselectByRole = (widget: Gtk.Widget, valueArray: number[]): void => {
153
161
  applyListBoxRows(widget, valueArray, unselectListBoxRow);
154
162
  };
155
163
 
164
+ /**
165
+ * Unselects the items at the given positions in a list, grid, or column view, or the rows at those
166
+ * indices in a Gtk.ListBox.
167
+ *
168
+ * @throws When a view has no selection model, or when the widget is neither one of those views nor
169
+ * a Gtk.ListBox.
170
+ */
156
171
  const deselectOptions = (widget: Gtk.Widget, values: number | number[]): Promise<void> =>
157
172
  runSelectionEvent(widget, values, deselectInListView, deselectByRole);
158
173
 
@@ -1,8 +1,8 @@
1
1
  type UserEventState = {
2
2
  modifierState: number;
3
- mouseLeftDown: boolean;
3
+ isMouseLeftDown: boolean;
4
4
  };
5
5
 
6
- const createInitialState = (): UserEventState => ({ modifierState: 0, mouseLeftDown: false });
6
+ const createInitialState = (): UserEventState => ({ modifierState: 0, isMouseLeftDown: false });
7
7
 
8
8
  export { createInitialState, type UserEventState };
@@ -5,10 +5,10 @@ import { EDITABLE_ROLES, type EditableTarget, getEditableDelegate, isEditable }
5
5
  import { formatRoleList } from "../role-helpers.js";
6
6
  import { wrapEvent } from "./event-wrapper.js";
7
7
 
8
- /** Options for {@link type}. */
8
+ /** Options for `userEvent.type`. */
9
9
  type TypeOptions = {
10
- /** Do not focus the widget before typing. */
11
- skipClick?: boolean | undefined;
10
+ /** Focus the widget before typing; defaults to true. */
11
+ shouldFocus?: boolean | undefined;
12
12
  /** Select from this offset before typing, replacing the selected range with the typed text. */
13
13
  initialSelectionStart?: number | undefined;
14
14
  /** End offset of the initial selection (defaults to the start offset). */
@@ -131,9 +131,15 @@ const runEditableEvent = (
131
131
  action(widget);
132
132
  });
133
133
 
134
+ /**
135
+ * Focuses the widget unless `shouldFocus` is false, applies any initial selection, and inserts the text
136
+ * at the cursor.
137
+ *
138
+ * @throws When the widget is neither a Gtk.Editable nor a Gtk.TextView.
139
+ */
134
140
  const type = (widget: Gtk.Widget, text: string, options?: TypeOptions): Promise<void> =>
135
141
  runEditableEvent(widget, "Cannot type into element", (editable) => {
136
- if (!options?.skipClick) {
142
+ if (options?.shouldFocus ?? true) {
137
143
  editable.grabFocus();
138
144
  }
139
145
 
@@ -141,22 +147,43 @@ const type = (widget: Gtk.Widget, text: string, options?: TypeOptions): Promise<
141
147
  insertEditableText(editable, text);
142
148
  });
143
149
 
150
+ /**
151
+ * Replaces an editable widget's text with the empty string.
152
+ *
153
+ * @throws When the widget is neither a Gtk.Editable nor a Gtk.TextView.
154
+ */
144
155
  const clear = (widget: Gtk.Widget): Promise<void> =>
145
156
  runEditableEvent(widget, "Cannot clear element", (editable) => {
146
157
  setEditableText(editable, "");
147
158
  });
148
159
 
160
+ /**
161
+ * Writes an editable widget's selected text to its clipboard, or the empty string when nothing is selected.
162
+ *
163
+ * @throws When the widget is neither a Gtk.Editable nor a Gtk.TextView.
164
+ */
149
165
  const copy = (widget: Gtk.Widget): Promise<void> =>
150
166
  runEditableEvent(widget, "Cannot copy", (editable) => {
151
167
  writeClipboardText(editable, readSelection(editable));
152
168
  });
153
169
 
170
+ /**
171
+ * Writes an editable widget's selected text to its clipboard, then deletes that selection.
172
+ *
173
+ * @throws When the widget is neither a Gtk.Editable nor a Gtk.TextView.
174
+ */
154
175
  const cut = (widget: Gtk.Widget): Promise<void> =>
155
176
  runEditableEvent(widget, "Cannot cut", (editable) => {
156
177
  writeClipboardText(editable, readSelection(editable));
157
178
  deleteSelection(editable);
158
179
  });
159
180
 
181
+ /**
182
+ * Inserts the given text at an editable widget's cursor, reading the clipboard instead when no text
183
+ * is given.
184
+ *
185
+ * @throws When the widget is neither a Gtk.Editable nor a Gtk.TextView.
186
+ */
160
187
  const paste = async (widget: Gtk.Widget, text?: string): Promise<void> => {
161
188
  if (!isEditable(widget)) {
162
189
  throw new Error(`Cannot paste: ${EDITABLE_REQUIRED}`);
package/src/wait-for.ts CHANGED
@@ -5,7 +5,9 @@ import { getConfig } from "./config.js";
5
5
  import { timeoutError } from "./errors.js";
6
6
 
7
7
  type PollResult<T> = { status: "resolved"; value: T } | { status: "timedout"; lastError: Error | null };
8
+ /** Widgets watched for removal; null counts as already removed. */
8
9
  type RemovalTarget = Gtk.Widget | Gtk.Widget[] | null;
10
+ /** The widgets to watch for removal, or a function re-read on every poll to locate them. */
9
11
  type ElementOrCallback = Gtk.Widget | Gtk.Widget[] | (() => RemovalTarget);
10
12
 
11
13
  const DEFAULT_INTERVAL = 50;
@@ -11,9 +11,18 @@ type WidgetValue = {
11
11
  };
12
12
 
13
13
  type ValueTriplet = { now: number | null; min: number | null; max: number | null };
14
+ type CheckedState = "checked" | "unchecked" | "mixed";
14
15
 
15
16
  const DEFAULT_TEXT_GETTERS = ["getLabel", "getText", "getTitle"] as const;
16
17
 
18
+ const SELECTABLE_ROLES: Set<Gtk.AccessibleRole> = new Set<Gtk.AccessibleRole>([
19
+ Gtk.AccessibleRole.ROW,
20
+ Gtk.AccessibleRole.LIST_ITEM,
21
+ Gtk.AccessibleRole.GRID_CELL,
22
+ Gtk.AccessibleRole.OPTION,
23
+ Gtk.AccessibleRole.TREE_ITEM,
24
+ ]);
25
+
17
26
  const callStringGetter = (widget: Gtk.Widget, method: string): string | null => {
18
27
  const fn: unknown = Reflect.get(widget, method);
19
28
 
@@ -129,6 +138,55 @@ const getWidgetLabelText = (widget: Gtk.Widget): string | null => {
129
138
  return getLabelText(widget);
130
139
  };
131
140
 
141
+ const getChildren = function* (widget: Gtk.Widget): Generator<Gtk.Widget> {
142
+ let child = widget.getFirstChild();
143
+
144
+ while (child) {
145
+ yield child;
146
+ child = child.getNextSibling();
147
+ }
148
+ };
149
+
150
+ const textContentParts = (widget: Gtk.Widget): string[] => {
151
+ const own = getWidgetNodeText(widget);
152
+
153
+ if (own !== null) {
154
+ return [own];
155
+ }
156
+
157
+ return [...getChildren(widget)].flatMap((child) => textContentParts(child));
158
+ };
159
+
160
+ /**
161
+ * Returns a widget's own text, or the space-joined text of its descendants when it has none of its
162
+ * own, or null when neither produces a value.
163
+ *
164
+ * @param widget The widget whose subtree is read.
165
+ */
166
+ const getWidgetTextContent = (widget: Gtk.Widget): string | null => {
167
+ const parts = textContentParts(widget);
168
+
169
+ return parts.length > 0 ? parts.join(" ") : null;
170
+ };
171
+
172
+ const isComboBoxFaceCandidate = (widget: Gtk.Widget): boolean =>
173
+ !(widget instanceof Gtk.Popover) && widget.getChildVisible();
174
+
175
+ const comboBoxChildFaceText = (child: Gtk.Widget): string | null =>
176
+ isComboBoxFaceCandidate(child) ? getWidgetLabelText(child) ?? comboBoxFaceText(child) : null;
177
+
178
+ const comboBoxFaceText = (widget: Gtk.Widget): string | null => {
179
+ for (const child of getChildren(widget)) {
180
+ const text = comboBoxChildFaceText(child);
181
+
182
+ if (text !== null) {
183
+ return text;
184
+ }
185
+ }
186
+
187
+ return null;
188
+ };
189
+
132
190
  const tabPanelTitle = (widget: Gtk.Widget): string | null => {
133
191
  const parent = widget.getParent();
134
192
 
@@ -146,6 +204,12 @@ const getWidgetAccessibleName = (widget: Gtk.Widget): string | null => {
146
204
  return tabPanelTitle(widget);
147
205
  }
148
206
 
207
+ const labelledByText = getWidgetLabelledByText(widget);
208
+
209
+ if (labelledByText) {
210
+ return labelledByText;
211
+ }
212
+
149
213
  const accessibleLabel = readAccessibleString(widget, "accessibleLabel");
150
214
 
151
215
  if (accessibleLabel) {
@@ -176,7 +240,15 @@ const getWidgetPlaceholderText = (widget: Gtk.Widget): string | null => {
176
240
  return null;
177
241
  }
178
242
 
179
- return callStringGetter(widget, "getPlaceholderText");
243
+ const fromGetter = callStringGetter(widget, "getPlaceholderText");
244
+
245
+ if (fromGetter !== null) {
246
+ return fromGetter;
247
+ }
248
+
249
+ const fromAccessor: unknown = Reflect.get(widget, "placeholderText");
250
+
251
+ return typeof fromAccessor === "string" && fromAccessor !== "" ? fromAccessor : null;
180
252
  };
181
253
 
182
254
  const getWidgetDisplayValue = (widget: Gtk.Widget): string | null => {
@@ -184,25 +256,89 @@ const getWidgetDisplayValue = (widget: Gtk.Widget): string | null => {
184
256
  return readEditableText(widget);
185
257
  }
186
258
 
259
+ if (widget.getAccessibleRole() === Gtk.AccessibleRole.COMBO_BOX) {
260
+ return comboBoxFaceText(widget);
261
+ }
262
+
187
263
  return null;
188
264
  };
189
265
 
190
- const getWidgetCheckedState = (widget: Gtk.Widget): boolean | null => {
191
- if (widget instanceof Gtk.CheckButton) {
192
- return widget.getActive();
266
+ const hasDisplayValue = (widget: Gtk.Widget): boolean => {
267
+ const role = widget.getAccessibleRole();
268
+
269
+ return (EDITABLE_ROLES.has(role) && isEditable(widget)) || role === Gtk.AccessibleRole.COMBO_BOX;
270
+ };
271
+
272
+ const isWidgetDisabled = (widget: Gtk.Widget): boolean => !widget.isSensitive();
273
+
274
+ const hasZeroOpacityAncestor = (widget: Gtk.Widget): boolean => {
275
+ let current: Gtk.Widget | null = widget;
276
+
277
+ while (current) {
278
+ if (current.getOpacity() === 0) {
279
+ return true;
280
+ }
281
+
282
+ current = current.getParent();
193
283
  }
194
284
 
195
- if (widget instanceof Gtk.Switch) {
196
- return widget.getActive();
285
+ return false;
286
+ };
287
+
288
+ const isWidgetVisible = (widget: Gtk.Widget): boolean => widget.isVisible() && !hasZeroOpacityAncestor(widget);
289
+
290
+ const getWidgetRequiredState = (widget: Gtk.Widget): boolean | null =>
291
+ readAccessibleBoolean(widget, "accessibleRequired");
292
+
293
+ const readTextViewSelection = (view: Gtk.TextView): string | null => {
294
+ const buffer = view.getBuffer();
295
+ const [hasSelection, start, end] = buffer.getSelectionBounds();
296
+
297
+ return hasSelection ? buffer.getText(start, end, true) : null;
298
+ };
299
+
300
+ const readEditableSelection = (editable: Gtk.Editable): string | null => {
301
+ const [hasSelection, start, end] = editable.getSelectionBounds();
302
+
303
+ return hasSelection ? editable.getChars(start, end) : null;
304
+ };
305
+
306
+ const getWidgetSelection = (widget: Gtk.Widget): string | null => {
307
+ if (widget instanceof Gtk.TextView) {
308
+ return readTextViewSelection(widget);
197
309
  }
198
310
 
199
- if (widget instanceof Gtk.ToggleButton && widget.getAccessibleRole() === Gtk.AccessibleRole.RADIO) {
200
- return widget.getActive();
311
+ if (widget instanceof Gtk.Editable) {
312
+ return readEditableSelection(widget);
201
313
  }
202
314
 
203
315
  return null;
204
316
  };
205
317
 
318
+ const checkedFromActive = (isActive: boolean): CheckedState => (isActive ? "checked" : "unchecked");
319
+
320
+ const isCheckableToggle = (widget: Gtk.Widget): boolean =>
321
+ widget instanceof Gtk.Switch ||
322
+ (widget instanceof Gtk.ToggleButton && widget.getAccessibleRole() === Gtk.AccessibleRole.RADIO);
323
+
324
+ const getWidgetCheckedState = (widget: Gtk.Widget): CheckedState | null => {
325
+ if (widget instanceof Gtk.CheckButton) {
326
+ return widget.getInconsistent() ? "mixed" : checkedFromActive(widget.getActive());
327
+ }
328
+
329
+ if (isCheckableToggle(widget)) {
330
+ return checkedFromActive(Reflect.get(widget, "active") === true);
331
+ }
332
+
333
+ return null;
334
+ };
335
+
336
+ const isWidgetChecked = (widget: Gtk.Widget): boolean | null => {
337
+ const state = getWidgetCheckedState(widget);
338
+
339
+ return state === null || state === "mixed" ? null : state === "checked";
340
+ };
341
+
206
342
  const getWidgetPressedState = (widget: Gtk.Widget): boolean | null => {
207
343
  if (widget instanceof Gtk.ToggleButton) {
208
344
  return widget.getActive();
@@ -224,11 +360,11 @@ const getWidgetExpandedState = (widget: Gtk.Widget): boolean | null => {
224
360
  };
225
361
 
226
362
  const getWidgetSelectedState = (widget: Gtk.Widget): boolean | null => {
227
- if (widget instanceof Gtk.ListBoxRow) {
363
+ if (widget instanceof Gtk.ListBoxRow || widget instanceof Gtk.FlowBoxChild) {
228
364
  return widget.isSelected();
229
365
  }
230
366
 
231
- if (widget.getAccessibleRole() === Gtk.AccessibleRole.ROW) {
367
+ if (SELECTABLE_ROLES.has(widget.getAccessibleRole())) {
232
368
  return (widget.getStateFlags() & Gtk.StateFlags.SELECTED) !== 0;
233
369
  }
234
370
 
@@ -239,12 +375,23 @@ const getWidgetLevel = (widget: Gtk.Widget): number | null => {
239
375
  return readAccessibleNumber(widget, "accessibleLevel");
240
376
  };
241
377
 
378
+ /**
379
+ * Returns the accessible invalid state declared on a widget, or null when it declares none.
380
+ *
381
+ * @param widget The widget to read the state from.
382
+ */
242
383
  const getWidgetInvalidState = (widget: Gtk.Widget): Gtk.AccessibleInvalidState | null => {
243
384
  const value = readAccessibleNumber(widget, "accessibleInvalid");
244
385
 
245
386
  return value ?? null;
246
387
  };
247
388
 
389
+ /**
390
+ * Returns the widgets a widget's accessible error-message relation points at, or null when it
391
+ * declares none.
392
+ *
393
+ * @param widget The widget to read the relation from.
394
+ */
248
395
  const getWidgetErrorMessage = (widget: Gtk.Widget): Gtk.Widget[] | null =>
249
396
  readAccessibleWidgets(widget, "accessibleErrorMessage");
250
397
 
@@ -346,6 +493,28 @@ const getWidgetLabelledByText = (widget: Gtk.Widget): string | null => {
346
493
  return texts.length > 0 ? texts.join(" ") : null;
347
494
  };
348
495
 
496
+ const isTooltipUsedAsName = (widget: Gtk.Widget): boolean =>
497
+ readAccessibleString(widget, "accessibleLabel") === null &&
498
+ getWidgetNodeText(widget) === null &&
499
+ collectLabels(widget).length === 0;
500
+
501
+ const getWidgetDescribedByText = (widget: Gtk.Widget): string | null => {
502
+ const targets = readAccessibleWidgets(widget, "accessibleDescribedBy");
503
+ const texts = targets === null ? [] : collectAccessibleNames(targets);
504
+
505
+ if (texts.length > 0) {
506
+ return texts.join(" ");
507
+ }
508
+
509
+ const description = readAccessibleString(widget, "accessibleDescription");
510
+
511
+ if (description !== null) {
512
+ return description;
513
+ }
514
+
515
+ return isTooltipUsedAsName(widget) ? null : callStringGetter(widget, "getTooltipText");
516
+ };
517
+
349
518
  const isInaccessible = (widget: Gtk.Widget): boolean => {
350
519
  let current: Gtk.Widget | null = widget;
351
520
 
@@ -366,12 +535,20 @@ const isInaccessible = (widget: Gtk.Widget): boolean => {
366
535
 
367
536
  export {
368
537
  getWidgetNodeText,
538
+ getWidgetTextContent,
369
539
  getWidgetLabelText,
370
540
  getWidgetAccessibleName,
371
541
  getWidgetName,
372
542
  getWidgetPlaceholderText,
373
543
  getWidgetDisplayValue,
544
+ hasDisplayValue,
545
+ isWidgetDisabled,
546
+ isWidgetVisible,
547
+ getWidgetRequiredState,
548
+ getWidgetSelection,
549
+ getWidgetDescribedByText,
374
550
  getWidgetCheckedState,
551
+ isWidgetChecked,
375
552
  getWidgetPressedState,
376
553
  getWidgetExpandedState,
377
554
  getWidgetSelectedState,
@@ -384,5 +561,6 @@ export {
384
561
  getWidgetOwnLabel,
385
562
  getWidgetLabelledByText,
386
563
  isInaccessible,
564
+ type CheckedState,
387
565
  type WidgetValue,
388
566
  };
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