@gtkx/testing 1.6.0 → 2.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +5 -5
  2. package/dist/config.d.ts.map +1 -1
  3. package/dist/config.js +1 -3
  4. package/dist/config.js.map +1 -1
  5. package/dist/fire-event.js +1 -1
  6. package/dist/fire-event.js.map +1 -1
  7. package/dist/matchers.d.ts.map +1 -1
  8. package/dist/matchers.js +1 -14
  9. package/dist/matchers.js.map +1 -1
  10. package/dist/queries.d.ts +30 -126
  11. package/dist/queries.d.ts.map +1 -1
  12. package/dist/queries.js +30 -126
  13. package/dist/queries.js.map +1 -1
  14. package/dist/query-helpers.d.ts.map +1 -1
  15. package/dist/query-helpers.js +8 -2
  16. package/dist/query-helpers.js.map +1 -1
  17. package/dist/screenshot.d.ts.map +1 -1
  18. package/dist/screenshot.js +1 -3
  19. package/dist/screenshot.js.map +1 -1
  20. package/dist/user-event/adjustment.d.ts +2 -14
  21. package/dist/user-event/adjustment.d.ts.map +1 -1
  22. package/dist/user-event/adjustment.js +2 -14
  23. package/dist/user-event/adjustment.js.map +1 -1
  24. package/dist/user-event/click.d.ts +3 -41
  25. package/dist/user-event/click.d.ts.map +1 -1
  26. package/dist/user-event/click.js +5 -43
  27. package/dist/user-event/click.js.map +1 -1
  28. package/dist/user-event/gesture.d.ts +9 -43
  29. package/dist/user-event/gesture.d.ts.map +1 -1
  30. package/dist/user-event/gesture.js +9 -43
  31. package/dist/user-event/gesture.js.map +1 -1
  32. package/dist/user-event/index.d.ts +16 -85
  33. package/dist/user-event/index.d.ts.map +1 -1
  34. package/dist/user-event/index.js +1 -5
  35. package/dist/user-event/index.js.map +1 -1
  36. package/dist/user-event/keyboard.d.ts +1 -1
  37. package/dist/user-event/keyboard.d.ts.map +1 -1
  38. package/dist/user-event/keyboard.js +1 -1
  39. package/dist/user-event/keyboard.js.map +1 -1
  40. package/dist/user-event/list-row-click.d.ts +1 -1
  41. package/dist/user-event/list-row-click.d.ts.map +1 -1
  42. package/dist/user-event/list-row-click.js +2 -1
  43. package/dist/user-event/list-row-click.js.map +1 -1
  44. package/dist/user-event/selection.d.ts +2 -18
  45. package/dist/user-event/selection.d.ts.map +1 -1
  46. package/dist/user-event/selection.js +3 -21
  47. package/dist/user-event/selection.js.map +1 -1
  48. package/dist/user-event/text.d.ts +5 -34
  49. package/dist/user-event/text.d.ts.map +1 -1
  50. package/dist/user-event/text.js +5 -34
  51. package/dist/user-event/text.js.map +1 -1
  52. package/dist/widget-accessible-properties.d.ts.map +1 -1
  53. package/dist/widget-accessible-properties.js +14 -34
  54. package/dist/widget-accessible-properties.js.map +1 -1
  55. package/package.json +12 -8
  56. package/src/config.ts +1 -3
  57. package/src/fire-event.ts +1 -1
  58. package/src/matchers.ts +1 -22
  59. package/src/queries.ts +30 -126
  60. package/src/query-helpers.ts +8 -2
  61. package/src/screenshot.ts +1 -3
  62. package/src/user-event/adjustment.ts +2 -14
  63. package/src/user-event/click.ts +5 -43
  64. package/src/user-event/gesture.ts +9 -43
  65. package/src/user-event/index.ts +16 -85
  66. package/src/user-event/keyboard.ts +1 -1
  67. package/src/user-event/list-row-click.ts +2 -2
  68. package/src/user-event/selection.ts +3 -21
  69. package/src/user-event/text.ts +5 -34
  70. package/src/widget-accessible-properties.ts +22 -44
@@ -15,73 +15,31 @@ type UserEventOptions = {
15
15
  delay?: number | null | undefined;
16
16
  };
17
17
 
18
- /**
19
- * The set of user interaction helpers exposed by {@link userEvent}, covering clicks, typing,
20
- * keyboard, pointer, gestures, selection, and scrolling.
21
- */
18
+ /** User interactions exposed by {@link userEvent}. */
22
19
  type UserEvent = {
23
- /**
24
- * Returns a fresh instance whose helpers share one keyboard and pointer state, so held modifiers
25
- * and buttons carry across its calls but not across instances.
26
- */
20
+ /** Creates an instance with shared keyboard and pointer state. */
27
21
  setup: (options?: UserEventOptions) => UserEvent;
28
- /**
29
- * Activates a widget that neither claims the click nor carries a click gesture of its own, and
30
- * otherwise presses and releases outwards from the clicked widget through every widget carrying
31
- * a click gesture, stopping at the first button or indexed child. A list box row or flow box
32
- * child receives its click gesture at the clicked position, passes one on to the gestures its
33
- * container carries, and is then activated, or exclusively selected when its container does not
34
- * activate on a single click. The press also stops at a widget whose click GTK4 implements
35
- * itself, where the gestures that widget carries of its own still take the press and the same
36
- * outcome is then applied through GTK's own public action: a list, grid, or column-view row is
37
- * focused and selected, and activated as well when its view activates on a single click; an
38
- * expandable tree expander that is itself the clicked widget toggles its expansion; a notebook
39
- * tab, clicked directly or through its label, focuses its notebook and switches to its page; a
40
- * column header sorts by its column. A column-view cell and the row carrying the column headers
41
- * stand in the way of the click rather than taking it, so a click on either reaches the row or
42
- * the view behind it.
43
- */
22
+ /** Activates or presses and releases a widget. */
44
23
  click: typeof click;
45
- /**
46
- * Delivers a two-press click gesture along the same path a single click takes, without trying
47
- * activation first, activating a list box row or flow box child on that path and replacing its
48
- * container's selection whether or not that container activates on a single click. A widget
49
- * whose click GTK4 implements itself receives that outcome once per press, so a row is selected
50
- * and activated by the second press, a tree expander ends back where it started, a notebook tab
51
- * stays on the page the first press opened, and a column header inverts its order after sorting.
52
- */
24
+ /** Delivers a double-click gesture. */
53
25
  dblClick: typeof dblClick;
54
- /**
55
- * Delivers a three-press click gesture the same way a double click is delivered, applying the
56
- * same outcome to a list box row or flow box child, and applying the outcome GTK4 implements
57
- * itself once per press to a row, tree expander, notebook tab, or column header.
58
- */
26
+ /** Delivers a triple-click gesture. */
59
27
  tripleClick: typeof tripleClick;
60
- /** Moves focus within the widget's root, forward by default and backward with `isShiftHeld`. */
28
+ /** Moves focus forward or backward within the root. */
61
29
  tab: typeof tab;
62
- /**
63
- * Focuses an editable widget the way clicking into it does, leaving its text unselected, applies
64
- * any initial selection, and inserts the text at the cursor, deleting the text the widget has
65
- * selected first, the way GTK4 does.
66
- */
30
+ /** Types into an editable widget. */
67
31
  type: typeof type;
68
- /** Focuses an editable widget and deletes its whole text, leaving nothing selected. */
32
+ /** Deletes all text from an editable widget. */
69
33
  clear: typeof clear;
70
- /** Writes an editable widget's current selection to the clipboard. */
34
+ /** Copies the current selection. */
71
35
  copy: typeof copy;
72
- /** Writes an editable widget's current selection to the clipboard and deletes it. */
36
+ /** Cuts the current selection. */
73
37
  cut: typeof cut;
74
- /**
75
- * Inserts the given text, or the clipboard's text, at an editable widget's cursor, deleting the
76
- * text the widget has selected first, the way GTK4 does.
77
- */
38
+ /** Pastes text or clipboard contents. */
78
39
  paste: typeof paste;
79
- /**
80
- * Selects the items at those positions in a view or drop-down, or selects the indexed children of
81
- * a list box or flow box through their container, without activating them.
82
- */
40
+ /** Selects positions without activating them. */
83
41
  selectOptions: typeof selectOptions;
84
- /** Unselects the items at those positions, leaving list box and flow box children unactivated. */
42
+ /** Unselects positions without activating them. */
85
43
  deselectOptions: typeof deselectOptions;
86
44
  /** Emits a motion `enter` on the widget, adding a motion controller when it has none. */
87
45
  hover: typeof hover;
@@ -105,40 +63,13 @@ type UserEvent = {
105
63
  slide: typeof slide;
106
64
  /** Adds the delta to the adjustments of the widget itself, or of its nearest scrollable ancestor. */
107
65
  scroll: typeof scroll;
108
- /**
109
- * Sends a key sequence along the chain GTK4 propagates a key event through: the application's
110
- * accelerators first, then the capture-phase controllers from the root down to the event widget,
111
- * the event widget's target-phase controllers, and the bubble-phase controllers from it back up
112
- * to the root, so a key controller or shortcut controller a container or window above the widget
113
- * carries receives the key too, each in the phase it declares. The event widget is the editable
114
- * delegate GTK4 focuses when the widget has one, the `Gtk.Text` inside a `Gtk.Entry` for
115
- * instance, so the delegate stands ahead of the widget in the chain. A shortcut controller whose
116
- * scope is not local runs where it registered instead, the root for a global one and the nearest
117
- * `Gtk.ShortcutManager` for a managed one, so it fires wherever focus sits inside that subtree
118
- * and never at its own widget, while a shortcut whose widget is insensitive or unmapped stays
119
- * inert wherever it sits. The first controller that handles a press ends the chain, and a
120
- * `Gdk.KEY_Return` press none of them handled reaches an editable widget's activate handler.
121
- * Built-in key bindings take part, since GTK4 carries them on a shortcut controller: a
122
- * `Gtk.Text`'s arrow keys or a `Gtk.TextView`'s undo can consume a press before an ancestor
123
- * sees it. Key controllers GTK4 attaches itself are the exception, since they read a GDK event
124
- * that off-screen synthesis cannot produce, so only the key controllers the tree connected a
125
- * `key-pressed` or `key-released` handler to take part. Held modifiers carry across calls.
126
- */
66
+ /** Sends a key sequence through GTK's propagation chain. */
127
67
  keyboard: (widget: Gtk.Widget, input: string) => Promise<void>;
128
- /**
129
- * Applies a pointer token to the click gestures the widget already carries, tracking whether the
130
- * left button is held across calls. On a widget whose click GTK4 implements itself, the release
131
- * also applies GTK's own outcome, the way {@link UserEvent.click} does, and a column-view cell
132
- * or the row carrying the column headers passes the token to the row or view behind it.
133
- */
68
+ /** Applies a pointer token while preserving held-button state. */
134
69
  pointer: (widget: Gtk.Widget, input: PointerInput) => Promise<void>;
135
70
  };
136
71
 
137
- /**
138
- * High-level helpers that drive widgets by dispatching the same events and gestures GTK4 delivers
139
- * when someone clicks, types, or drags. Call `setup` for an instance with its own keyboard and
140
- * pointer state.
141
- */
72
+ /** User interactions that dispatch GTK events and gestures. */
142
73
  const userEvent: UserEvent = {
143
74
  ...createInstance(createInitialState(), {}),
144
75
  setup: (options?: UserEventOptions): UserEvent => createInstance(createInitialState(), options ?? {}),
@@ -65,7 +65,7 @@ const MODIFIER_KEYVAL_TO_MASK: Record<number, number> = {
65
65
  [Gdk.KEY_Meta_R]: Gdk.ModifierType.META_MASK,
66
66
  };
67
67
 
68
- /** Moves focus within the widget's root, forward by default and backward when `isShiftHeld` is set. */
68
+ /** Moves focus within the widget's root. */
69
69
  const tab = (widget: Gtk.Widget, options?: TabOptions): Promise<void> =>
70
70
  wrapEvent(widget, () => {
71
71
  const direction = options?.isShiftHeld ? Gtk.DirectionType.TAB_BACKWARD : Gtk.DirectionType.TAB_FORWARD;
@@ -1,5 +1,5 @@
1
- import type * as Gtk from "@gtkx/gi/gtk";
2
1
  import * as GLib from "@gtkx/gi/glib";
2
+ import * as Gtk from "@gtkx/gi/gtk";
3
3
  import { ancestors } from "../traversal.js";
4
4
  import { callBooleanGetter, hasWidgetMethod } from "../widget-getters.js";
5
5
 
@@ -41,7 +41,7 @@ const applyRowPress = (row: Gtk.Widget, press: number): void => {
41
41
  selectRow(row);
42
42
 
43
43
  if (isRowActivatedByPress(row, press)) {
44
- row.activate();
44
+ Gtk.Widget.prototype.activate.call(row);
45
45
  }
46
46
  };
47
47
 
@@ -19,9 +19,7 @@ const SELECTABLE_ROLES: Set<Gtk.AccessibleRole> = new Set([
19
19
  Gtk.AccessibleRole.LIST,
20
20
  ]);
21
21
 
22
- const isSelectable = (widget: Gtk.Widget): boolean => {
23
- return SELECTABLE_ROLES.has(widget.getAccessibleRole());
24
- };
22
+ const isSelectable = (widget: Gtk.Widget): boolean => SELECTABLE_ROLES.has(widget.getAccessibleRole());
25
23
 
26
24
  const selectListViewItems = (
27
25
  selectionModel: Gtk.SelectionModel,
@@ -155,16 +153,7 @@ const runSelectionEvent = (
155
153
  byRole(widget, valueArray);
156
154
  });
157
155
 
158
- /**
159
- * Selects the items at the given positions through a list, grid, or column view's selection model,
160
- * by setting the selected position of a widget with the COMBO_BOX role, or by selecting the indexed
161
- * children of a list box or flow box through their container. An empty array clears a view's
162
- * selection. The children are never activated, so no row-activated handler runs.
163
- *
164
- * @throws When a view has no selection model, when a COMBO_BOX-role widget is given more than one
165
- * position or exposes no `setSelected`, or when the widget's role is none of COMBO_BOX, GRID, or
166
- * LIST.
167
- */
156
+ /** Selects positions without activating them. */
168
157
  const selectOptions = (widget: Gtk.Widget, values: number | number[]): Promise<void> =>
169
158
  runSelectionEvent(widget, values, selectInListView, selectByRole);
170
159
 
@@ -186,14 +175,7 @@ const deselectByRole = (widget: Gtk.Widget, valueArray: number[]): void => {
186
175
  applyIndexedChildren(widget, valueArray, unselectChildRow);
187
176
  };
188
177
 
189
- /**
190
- * Unselects the items at the given positions in a list, grid, or column view, or unselects the
191
- * indexed children of a list box or flow box through their container. A child that is not selected
192
- * is left alone, and no child is activated.
193
- *
194
- * @throws When a view has no selection model, when the widget's role is none of COMBO_BOX, GRID, or
195
- * LIST, or when it exposes no indexed children.
196
- */
178
+ /** Unselects positions without activating them. */
197
179
  const deselectOptions = (widget: Gtk.Widget, values: number | number[]): Promise<void> =>
198
180
  runSelectionEvent(widget, values, deselectInListView, deselectByRole);
199
181
 
@@ -198,15 +198,7 @@ const runEditableEvent = (
198
198
  action(widget);
199
199
  });
200
200
 
201
- /**
202
- * Focuses the widget unless `shouldFocus` is false, applies any initial selection, and inserts the
203
- * text at the cursor, deleting the text the widget has selected first, the way typing over a
204
- * selection does in GTK4. Focusing works the way clicking into the widget does, leaving its text
205
- * unselected: a `Gtk.Editable` takes its caret to the end of its text, a `Gtk.TextView` keeps the
206
- * caret where it stands, and the replaced text stays on the widget's undo stack either way.
207
- *
208
- * @throws When the widget is neither a Gtk.Editable nor a Gtk.TextView.
209
- */
201
+ /** Types into an editable widget. */
210
202
  const type = (widget: Gtk.Widget, text: string, options?: TypeOptions): Promise<void> =>
211
203
  runEditableEvent(widget, "Cannot type into element", (editable) => {
212
204
  if (options?.shouldFocus ?? true) {
@@ -286,45 +278,24 @@ const clearEditable = (editable: EditableTarget): void => {
286
278
  }
287
279
  };
288
280
 
289
- /**
290
- * Focuses an editable widget and deletes its whole text through the widget's own editing API, so the
291
- * deletion emits the signals an edit made by hand emits. Text a tag protects is detected before the
292
- * deletion runs, leaving such a widget untouched. A widget that writes a new value back in response
293
- * to the deletion, as an input mask does, is cleared successfully and keeps whatever it wrote.
294
- *
295
- * @throws When the widget is neither a Gtk.Editable nor a Gtk.TextView, when it refuses edits, when
296
- * a tag protects part of its text, or when a handler blocks the deletion.
297
- */
281
+ /** Deletes all text from an editable widget. */
298
282
  const clear = (widget: Gtk.Widget): Promise<void> =>
299
283
  runEditableEvent(widget, "Cannot clear element", clearEditable);
300
284
 
301
- /**
302
- * Writes an editable widget's selected text to its clipboard, or the empty string when nothing is selected.
303
- *
304
- * @throws When the widget is neither a Gtk.Editable nor a Gtk.TextView.
305
- */
285
+ /** Copies the current selection. */
306
286
  const copy = (widget: Gtk.Widget): Promise<void> =>
307
287
  runEditableEvent(widget, "Cannot copy", (editable) => {
308
288
  writeClipboardText(editable, readSelection(editable));
309
289
  });
310
290
 
311
- /**
312
- * Writes an editable widget's selected text to its clipboard, then deletes that selection.
313
- *
314
- * @throws When the widget is neither a Gtk.Editable nor a Gtk.TextView.
315
- */
291
+ /** Cuts the current selection. */
316
292
  const cut = (widget: Gtk.Widget): Promise<void> =>
317
293
  runEditableEvent(widget, "Cannot cut", (editable) => {
318
294
  writeClipboardText(editable, readSelection(editable));
319
295
  deleteSelection(editable);
320
296
  });
321
297
 
322
- /**
323
- * Inserts the given text at an editable widget's cursor, reading the clipboard instead when no text
324
- * is given, and deleting the text the widget has selected first, the way a paste does in GTK4.
325
- *
326
- * @throws When the widget is neither a Gtk.Editable nor a Gtk.TextView.
327
- */
298
+ /** Pastes text or clipboard contents. */
328
299
  const paste = async (widget: Gtk.Widget, text?: string): Promise<void> => {
329
300
  if (!isEditable(widget)) {
330
301
  throw new Error(`Cannot paste: ${EDITABLE_REQUIRED}`);
@@ -4,10 +4,10 @@ import {
4
4
  readAccessibleBooleanProperty,
5
5
  readAccessibleFlag,
6
6
  readAccessibleInt,
7
+ readAccessibleNumber,
7
8
  readAccessibleRelation,
8
9
  readAccessibleState,
9
- readAccessibleNumber as readNativeNumber,
10
- readAccessibleString as readNativeString,
10
+ readAccessibleString,
11
11
  } from "./accessible-native.js";
12
12
  import { EDITABLE_ROLES, isEditable, readEditableText } from "./editable.js";
13
13
  import { isNameFromAuthor, isNameProhibited } from "./role-naming.js";
@@ -45,12 +45,6 @@ const VALUE_PROPERTIES: Record<WidgetValueField, Gtk.AccessibleProperty> = {
45
45
  max: Gtk.AccessibleProperty.VALUE_MAX,
46
46
  };
47
47
 
48
- const readAccessibleString = (widget: Gtk.Widget, property: Gtk.AccessibleProperty): string | null =>
49
- readNativeString(widget, property);
50
-
51
- const readAccessibleNumber = (widget: Gtk.Widget, property: Gtk.AccessibleProperty): number | null =>
52
- readNativeNumber(widget, property);
53
-
54
48
  const readAccessibleWidgets = (widget: Gtk.Widget, relation: Gtk.AccessibleRelation): Gtk.Widget[] | null => {
55
49
  const targets = readAccessibleRelation(widget, relation, relationCandidates(widget));
56
50
  const widgets = targets.filter((target): target is Gtk.Widget => target instanceof Gtk.Widget);
@@ -215,9 +209,7 @@ const getWidgetAccessibleName = (widget: Gtk.Widget): string | null => {
215
209
  return nameFromContent(widget) ?? callStringGetter(widget, "getTooltipText");
216
210
  };
217
211
 
218
- const getWidgetName = (widget: Gtk.Widget): string | null => {
219
- return widget.getName();
220
- };
212
+ const getWidgetName = (widget: Gtk.Widget): string | null => widget.getName();
221
213
 
222
214
  const nonEmptyText = (text: string | null): string | null => (text === null || text === "" ? null : text);
223
215
 
@@ -318,8 +310,6 @@ const readBoundedSelection = (widget: Gtk.Widget): string | null => {
318
310
  const getWidgetSelection = (widget: Gtk.Widget): string | null =>
319
311
  widget instanceof Gtk.TextView ? readTextViewSelection(widget) : readBoundedSelection(widget);
320
312
 
321
- const checkedFromActive = (isActive: boolean): CheckedState => (isActive ? "checked" : "unchecked");
322
-
323
313
  const isRadioToggle = (widget: Gtk.Widget): widget is Gtk.ToggleButton =>
324
314
  widget instanceof Gtk.ToggleButton && widget.getAccessibleRole() === Gtk.AccessibleRole.RADIO;
325
315
 
@@ -331,7 +321,11 @@ const getWidgetCheckedState = (widget: Gtk.Widget): CheckedState | null => {
331
321
  return state;
332
322
  }
333
323
 
334
- return isRadioToggle(widget) ? checkedFromActive(widget.getActive()) : null;
324
+ if (!isRadioToggle(widget)) {
325
+ return null;
326
+ }
327
+
328
+ return widget.getActive() ? "checked" : "unchecked";
335
329
  };
336
330
 
337
331
  const isWidgetChecked = (widget: Gtk.Widget): boolean | null => {
@@ -368,26 +362,20 @@ const getWidgetSelectedState = (widget: Gtk.Widget): boolean | null => {
368
362
  return null;
369
363
  };
370
364
 
371
- const getWidgetLevel = (widget: Gtk.Widget): number | null => {
372
- return readAccessibleInt(widget, Gtk.AccessibleProperty.LEVEL);
373
- };
365
+ const getWidgetLevel = (widget: Gtk.Widget): number | null =>
366
+ readAccessibleInt(widget, Gtk.AccessibleProperty.LEVEL);
374
367
 
375
- const getWidgetInvalidState = (widget: Gtk.Widget): Gtk.AccessibleInvalidState | null => {
376
- const value = readAccessibleState(widget, Gtk.AccessibleState.INVALID);
377
-
378
- return value ?? null;
379
- };
368
+ const getWidgetInvalidState = (widget: Gtk.Widget): Gtk.AccessibleInvalidState | null =>
369
+ readAccessibleState(widget, Gtk.AccessibleState.INVALID);
380
370
 
381
371
  const getWidgetErrorMessage = (widget: Gtk.Widget): Gtk.Widget[] | null =>
382
372
  readAccessibleWidgets(widget, Gtk.AccessibleRelation.ERROR_MESSAGE);
383
373
 
384
- const getWidgetBusyState = (widget: Gtk.Widget): boolean | null => {
385
- return readAccessibleBoolean(widget, Gtk.AccessibleState.BUSY);
386
- };
374
+ const getWidgetBusyState = (widget: Gtk.Widget): boolean | null =>
375
+ readAccessibleBoolean(widget, Gtk.AccessibleState.BUSY);
387
376
 
388
- const getWidgetDescription = (widget: Gtk.Widget): string | null => {
389
- return readAccessibleString(widget, Gtk.AccessibleProperty.DESCRIPTION);
390
- };
377
+ const getWidgetDescription = (widget: Gtk.Widget): string | null =>
378
+ readAccessibleString(widget, Gtk.AccessibleProperty.DESCRIPTION);
391
379
 
392
380
  const getWidgetValueNow = (widget: Gtk.Widget): number | null =>
393
381
  readAccessibleNumber(widget, Gtk.AccessibleProperty.VALUE_NOW);
@@ -398,23 +386,13 @@ const getWidgetValueText = (widget: Gtk.Widget): string | null =>
398
386
  const isWidgetValueMatch = (widget: Gtk.Widget, field: WidgetValueField, expected: number): boolean =>
399
387
  isAccessibleNumberMatch(widget, VALUE_PROPERTIES[field], expected);
400
388
 
401
- const getWidgetOwnLabel = (widget: Gtk.Widget): string | null => {
402
- return readAccessibleString(widget, Gtk.AccessibleProperty.LABEL);
403
- };
404
-
405
- const collectAccessibleNames = (targets: Gtk.Widget[]): string[] => {
406
- const texts: string[] = [];
389
+ const getWidgetOwnLabel = (widget: Gtk.Widget): string | null =>
390
+ readAccessibleString(widget, Gtk.AccessibleProperty.LABEL);
407
391
 
408
- for (const target of targets) {
409
- const text = getWidgetAccessibleName(target);
410
-
411
- if (text) {
412
- texts.push(text);
413
- }
414
- }
415
-
416
- return texts;
417
- };
392
+ const collectAccessibleNames = (targets: Gtk.Widget[]): string[] =>
393
+ targets
394
+ .map((target) => getWidgetAccessibleName(target))
395
+ .filter((text): text is string => text !== null && text !== "");
418
396
 
419
397
  const isSelfLabelling = (widget: Gtk.Widget, targets: Gtk.Widget[]): boolean => {
420
398
  const own = new Set(descendants(widget));