@gtkx/testing 1.0.0-rc.1 → 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.
Files changed (187) hide show
  1. package/dist/act.d.ts +6 -6
  2. package/dist/act.d.ts.map +1 -1
  3. package/dist/act.js +34 -26
  4. package/dist/act.js.map +1 -1
  5. package/dist/bound-queries.d.ts +5 -5
  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 +5 -5
  9. package/dist/build-queries.d.ts.map +1 -1
  10. package/dist/build-queries.js +21 -9
  11. package/dist/build-queries.js.map +1 -1
  12. package/dist/cleanup-registry.d.ts +4 -3
  13. package/dist/cleanup-registry.d.ts.map +1 -1
  14. package/dist/cleanup-registry.js +13 -3
  15. package/dist/cleanup-registry.js.map +1 -1
  16. package/dist/config.d.ts +5 -4
  17. package/dist/config.d.ts.map +1 -1
  18. package/dist/config.js +11 -9
  19. package/dist/config.js.map +1 -1
  20. package/dist/editable.d.ts +6 -5
  21. package/dist/editable.d.ts.map +1 -1
  22. package/dist/editable.js +7 -5
  23. package/dist/editable.js.map +1 -1
  24. package/dist/errors.d.ts +7 -6
  25. package/dist/errors.d.ts.map +1 -1
  26. package/dist/errors.js +64 -48
  27. package/dist/errors.js.map +1 -1
  28. package/dist/fire-event.d.ts +2 -1
  29. package/dist/fire-event.d.ts.map +1 -1
  30. package/dist/fire-event.js +2 -1
  31. package/dist/fire-event.js.map +1 -1
  32. package/dist/frame-sync.d.ts +2 -1
  33. package/dist/frame-sync.d.ts.map +1 -1
  34. package/dist/frame-sync.js +28 -21
  35. package/dist/frame-sync.js.map +1 -1
  36. package/dist/index.d.ts +9 -6
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +5 -3
  39. package/dist/index.js.map +1 -1
  40. package/dist/matchers.d.ts +99 -35
  41. package/dist/matchers.d.ts.map +1 -1
  42. package/dist/matchers.js +314 -63
  43. package/dist/matchers.js.map +1 -1
  44. package/dist/normalize.d.ts +10 -0
  45. package/dist/normalize.d.ts.map +1 -0
  46. package/dist/normalize.js +20 -0
  47. package/dist/normalize.js.map +1 -0
  48. package/dist/pretty-widget.d.ts +6 -4
  49. package/dist/pretty-widget.d.ts.map +1 -1
  50. package/dist/pretty-widget.js +64 -24
  51. package/dist/pretty-widget.js.map +1 -1
  52. package/dist/queries.d.ts +129 -90
  53. package/dist/queries.d.ts.map +1 -1
  54. package/dist/queries.js +235 -164
  55. package/dist/queries.js.map +1 -1
  56. package/dist/register-test-hooks.js +2 -1
  57. package/dist/register-test-hooks.js.map +1 -1
  58. package/dist/render-hook.d.ts +3 -2
  59. package/dist/render-hook.d.ts.map +1 -1
  60. package/dist/render-hook.js +2 -1
  61. package/dist/render-hook.js.map +1 -1
  62. package/dist/render.d.ts +3 -2
  63. package/dist/render.d.ts.map +1 -1
  64. package/dist/render.js +25 -19
  65. package/dist/render.js.map +1 -1
  66. package/dist/role-helpers.d.ts +6 -5
  67. package/dist/role-helpers.d.ts.map +1 -1
  68. package/dist/role-helpers.js +16 -12
  69. package/dist/role-helpers.js.map +1 -1
  70. package/dist/screen.d.ts +4 -3
  71. package/dist/screen.d.ts.map +1 -1
  72. package/dist/screen.js +13 -11
  73. package/dist/screen.js.map +1 -1
  74. package/dist/screenshot.d.ts +4 -3
  75. package/dist/screenshot.d.ts.map +1 -1
  76. package/dist/screenshot.js +43 -36
  77. package/dist/screenshot.js.map +1 -1
  78. package/dist/suggestions.d.ts +11 -6
  79. package/dist/suggestions.d.ts.map +1 -1
  80. package/dist/suggestions.js +10 -5
  81. package/dist/suggestions.js.map +1 -1
  82. package/dist/traversal.d.ts +7 -7
  83. package/dist/traversal.d.ts.map +1 -1
  84. package/dist/traversal.js +17 -11
  85. package/dist/traversal.js.map +1 -1
  86. package/dist/types.d.ts +65 -24
  87. package/dist/types.d.ts.map +1 -1
  88. package/dist/types.js.map +1 -1
  89. package/dist/user-event/adjustment.d.ts +5 -3
  90. package/dist/user-event/adjustment.d.ts.map +1 -1
  91. package/dist/user-event/adjustment.js +6 -4
  92. package/dist/user-event/adjustment.js.map +1 -1
  93. package/dist/user-event/click.d.ts +6 -5
  94. package/dist/user-event/click.d.ts.map +1 -1
  95. package/dist/user-event/click.js +29 -21
  96. package/dist/user-event/click.js.map +1 -1
  97. package/dist/user-event/controller.d.ts +7 -5
  98. package/dist/user-event/controller.d.ts.map +1 -1
  99. package/dist/user-event/controller.js +16 -6
  100. package/dist/user-event/controller.js.map +1 -1
  101. package/dist/user-event/dispatch.d.ts +3 -3
  102. package/dist/user-event/dispatch.d.ts.map +1 -1
  103. package/dist/user-event/dispatch.js +3 -2
  104. package/dist/user-event/dispatch.js.map +1 -1
  105. package/dist/user-event/event-wrapper.d.ts +2 -1
  106. package/dist/user-event/event-wrapper.d.ts.map +1 -1
  107. package/dist/user-event/event-wrapper.js +27 -16
  108. package/dist/user-event/event-wrapper.js.map +1 -1
  109. package/dist/user-event/gesture.d.ts +18 -14
  110. package/dist/user-event/gesture.d.ts.map +1 -1
  111. package/dist/user-event/gesture.js +70 -37
  112. package/dist/user-event/gesture.js.map +1 -1
  113. package/dist/user-event/index.d.ts +17 -10
  114. package/dist/user-event/index.d.ts.map +1 -1
  115. package/dist/user-event/index.js +7 -3
  116. package/dist/user-event/index.js.map +1 -1
  117. package/dist/user-event/keyboard.d.ts +4 -3
  118. package/dist/user-event/keyboard.d.ts.map +1 -1
  119. package/dist/user-event/keyboard.js +89 -58
  120. package/dist/user-event/keyboard.js.map +1 -1
  121. package/dist/user-event/pointer.d.ts +7 -3
  122. package/dist/user-event/pointer.d.ts.map +1 -1
  123. package/dist/user-event/pointer.js +4 -1
  124. package/dist/user-event/pointer.js.map +1 -1
  125. package/dist/user-event/selection.d.ts +3 -2
  126. package/dist/user-event/selection.d.ts.map +1 -1
  127. package/dist/user-event/selection.js +26 -27
  128. package/dist/user-event/selection.js.map +1 -1
  129. package/dist/user-event/state.d.ts +3 -2
  130. package/dist/user-event/state.d.ts.map +1 -1
  131. package/dist/user-event/state.js +2 -1
  132. package/dist/user-event/state.js.map +1 -1
  133. package/dist/user-event/text.d.ts +8 -7
  134. package/dist/user-event/text.d.ts.map +1 -1
  135. package/dist/user-event/text.js +39 -33
  136. package/dist/user-event/text.js.map +1 -1
  137. package/dist/wait-for.d.ts +5 -5
  138. package/dist/wait-for.d.ts.map +1 -1
  139. package/dist/wait-for.js +45 -30
  140. package/dist/wait-for.js.map +1 -1
  141. package/dist/widget-accessible-properties.d.ts +36 -25
  142. package/dist/widget-accessible-properties.d.ts.map +1 -1
  143. package/dist/widget-accessible-properties.js +215 -68
  144. package/dist/widget-accessible-properties.js.map +1 -1
  145. package/dist/within.d.ts +2 -1
  146. package/dist/within.d.ts.map +1 -1
  147. package/dist/within.js +2 -1
  148. package/dist/within.js.map +1 -1
  149. package/package.json +11 -9
  150. package/src/act.ts +44 -35
  151. package/src/bound-queries.ts +6 -6
  152. package/src/build-queries.ts +84 -43
  153. package/src/cleanup-registry.ts +18 -5
  154. package/src/config.ts +16 -12
  155. package/src/editable.ts +13 -6
  156. package/src/errors.ts +106 -45
  157. package/src/fire-event.ts +3 -1
  158. package/src/frame-sync.ts +38 -21
  159. package/src/index.ts +13 -3
  160. package/src/matchers.ts +568 -114
  161. package/src/normalize.ts +28 -0
  162. package/src/pretty-widget.ts +114 -42
  163. package/src/queries.ts +418 -256
  164. package/src/register-test-hooks.ts +4 -1
  165. package/src/render-hook.tsx +10 -4
  166. package/src/render.tsx +59 -34
  167. package/src/role-helpers.ts +29 -16
  168. package/src/screen.ts +17 -12
  169. package/src/screenshot.ts +61 -38
  170. package/src/suggestions.ts +29 -10
  171. package/src/traversal.ts +35 -15
  172. package/src/types.ts +111 -32
  173. package/src/user-event/adjustment.ts +23 -10
  174. package/src/user-event/click.ts +49 -20
  175. package/src/user-event/controller.ts +41 -7
  176. package/src/user-event/dispatch.ts +4 -2
  177. package/src/user-event/event-wrapper.ts +42 -16
  178. package/src/user-event/gesture.ts +135 -50
  179. package/src/user-event/index.ts +19 -12
  180. package/src/user-event/keyboard.ts +147 -61
  181. package/src/user-event/pointer.ts +20 -8
  182. package/src/user-event/selection.ts +69 -32
  183. package/src/user-event/state.ts +4 -2
  184. package/src/user-event/text.ts +73 -38
  185. package/src/wait-for.ts +77 -36
  186. package/src/widget-accessible-properties.ts +385 -79
  187. package/src/within.ts +8 -5
@@ -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 };
@@ -4,22 +4,43 @@ 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
- const DEFAULT_MAX_LENGTH = 7000;
8
- const INDENT = " ";
9
-
10
7
  type WidgetIdResolver = (widget: Gtk.Widget) => string;
11
8
 
12
9
  /**
13
10
  * Options controlling how a widget tree is rendered to a string by
14
11
  * {@link prettyWidget} and {@link logWidget}.
15
12
  */
16
- export type PrettyWidgetOptions = {
13
+ type PrettyWidgetOptions = {
17
14
  /** Truncates the output once it exceeds this many characters. */
18
15
  maxLength?: number;
19
16
  /** Whether to apply ANSI color highlighting; defaults to the terminal capabilities. */
20
17
  highlight?: boolean;
21
18
  /** Resolves an `id` attribute to show for each widget. */
22
19
  getId?: WidgetIdResolver;
20
+ /** Stops descending past this depth, replacing deeper children with a summary line. */
21
+ maxDepth?: number;
22
+ };
23
+
24
+ type Colors = {
25
+ tag: (s: string) => string;
26
+ attr: (s: string) => string;
27
+ value: (s: string) => string;
28
+ };
29
+
30
+ type FormatContext = {
31
+ getId: WidgetIdResolver | undefined;
32
+ colors: Colors;
33
+ maxDepth: number | undefined;
34
+ };
35
+
36
+ const DEFAULT_MAX_LENGTH = 7000;
37
+ const INDENT = " ";
38
+
39
+ const ansi = {
40
+ cyan: "\u{1B}[36m",
41
+ yellow: "\u{1B}[33m",
42
+ green: "\u{1B}[32m",
43
+ reset: "\u{1B}[0m",
23
44
  };
24
45
 
25
46
  const buildAttrs = (widget: Gtk.Widget, getId: WidgetIdResolver | undefined): [string, string][] => {
@@ -30,6 +51,7 @@ const buildAttrs = (widget: Gtk.Widget, getId: WidgetIdResolver | undefined): [s
30
51
  }
31
52
 
32
53
  const name = widget.getName();
54
+
33
55
  if (name) {
34
56
  attrs.push(["name", name]);
35
57
  }
@@ -45,38 +67,38 @@ const buildAttrs = (widget: Gtk.Widget, getId: WidgetIdResolver | undefined): [s
45
67
  }
46
68
 
47
69
  const idAttrs = attrs.filter(([key]) => key === "id");
70
+
48
71
  const otherAttrs = sortStringsBy(
49
72
  attrs.filter(([key]) => key !== "id"),
50
73
  ([key]) => key,
51
74
  );
75
+
52
76
  return [...idAttrs, ...otherAttrs];
53
77
  };
54
78
 
55
- type Colors = {
56
- tag: (s: string) => string;
57
- attr: (s: string) => string;
58
- value: (s: string) => string;
59
- };
79
+ const shouldHighlight = (): boolean => {
80
+ if (typeof process === "undefined") {
81
+ return false;
82
+ }
60
83
 
61
- const ansi = {
62
- cyan: "\x1b[36m",
63
- yellow: "\x1b[33m",
64
- green: "\x1b[32m",
65
- reset: "\x1b[0m",
66
- };
84
+ if (process.env.COLORS === "false" || process.env.NO_COLOR) {
85
+ return false;
86
+ }
87
+
88
+ if (process.env.COLORS === "true" || process.env.FORCE_COLOR) {
89
+ return true;
90
+ }
67
91
 
68
- const shouldHighlight = (): boolean => {
69
- if (typeof process === "undefined") return false;
70
- if (process.env.COLORS === "false" || process.env.NO_COLOR) return false;
71
- if (process.env.COLORS === "true" || process.env.FORCE_COLOR) return true;
72
92
  return process.stdout.isTTY;
73
93
  };
74
94
 
75
- const createColors = (enabled: boolean): Colors => {
76
- if (!enabled) {
95
+ const createColors = (isEnabled: boolean): Colors => {
96
+ if (!isEnabled) {
77
97
  const identity = (s: string): string => s;
98
+
78
99
  return { tag: identity, attr: identity, value: identity };
79
100
  }
101
+
80
102
  return {
81
103
  tag: (s) => `${ansi.cyan}${s}${ansi.reset}`,
82
104
  attr: (s) => `${ansi.yellow}${s}${ansi.reset}`,
@@ -86,21 +108,57 @@ const createColors = (enabled: boolean): Colors => {
86
108
 
87
109
  const escapeAttrValue = (value: string): string => value.replaceAll('"', """);
88
110
 
111
+ const formatAttr = (key: string, value: string, colors: Colors): string => {
112
+ const quoted = `"${escapeAttrValue(value)}"`;
113
+
114
+ return ` ${colors.attr(key)}=${colors.value(quoted)}`;
115
+ };
116
+
89
117
  const formatAttrs = (attrs: [string, string][], colors: Colors): string =>
90
- attrs.map(([key, value]) => ` ${colors.attr(key)}=${colors.value(`"${escapeAttrValue(value)}"`)}`).join("");
91
-
92
- const formatWidget = (
93
- widget: Gtk.Widget,
94
- depth: number,
95
- getId: WidgetIdResolver | undefined,
96
- colors: Colors,
97
- ): string => {
118
+ attrs.map(([key, value]) => formatAttr(key, value, colors)).join("");
119
+
120
+ const countChildren = (widget: Gtk.Widget): number => {
121
+ let count = 0;
122
+ let child = widget.getFirstChild();
123
+
124
+ while (child) {
125
+ count += 1;
126
+ child = child.getNextSibling();
127
+ }
128
+
129
+ return count;
130
+ };
131
+
132
+ const formatHiddenChildrenLine = (widget: Gtk.Widget, depth: number, ctx: FormatContext): string => {
133
+ const { getId, colors } = ctx;
134
+ const indent = INDENT.repeat(depth);
135
+ const count = countChildren(widget);
136
+ const hint = getId ? ` (pass rootId="${getId(widget)}" or raise maxDepth to expand)` : "";
137
+ const plural = count === 1 ? "" : "s";
138
+ const summary = `… ${String(count)} child widget${plural} hidden${hint}`;
139
+
140
+ return `${indent}${INDENT}${colors.tag(summary)}\n`;
141
+ };
142
+
143
+ const formatChildren = (widget: Gtk.Widget, depth: number, ctx: FormatContext): string => {
144
+ let output = "";
145
+ let child = widget.getFirstChild();
146
+
147
+ while (child) {
148
+ output += formatWidget(child, depth + 1, ctx);
149
+ child = child.getNextSibling();
150
+ }
151
+
152
+ return output;
153
+ };
154
+
155
+ const formatWidget = (widget: Gtk.Widget, depth: number, ctx: FormatContext): string => {
156
+ const { getId, colors, maxDepth } = ctx;
98
157
  const indent = INDENT.repeat(depth);
99
158
  const tag = widget.constructor.name;
100
159
  const attrs = formatAttrs(buildAttrs(widget, getId), colors);
101
160
  const openTag = `${colors.tag("<")}${colors.tag(tag)}${attrs}${colors.tag(">")}`;
102
161
  const closeTag = `${colors.tag("</")}${colors.tag(tag)}${colors.tag(">")}`;
103
-
104
162
  const text = getWidgetNodeText(widget);
105
163
  const firstChild = widget.getFirstChild();
106
164
 
@@ -109,18 +167,30 @@ const formatWidget = (
109
167
  }
110
168
 
111
169
  let output = `${indent}${openTag}\n`;
170
+
112
171
  if (text) {
113
172
  output += `${indent}${INDENT}${text}\n`;
114
173
  }
115
- let child = firstChild;
116
- while (child) {
117
- output += formatWidget(child, depth + 1, getId, colors);
118
- child = child.getNextSibling();
174
+
175
+ if (firstChild && maxDepth !== undefined && depth >= maxDepth) {
176
+ output += formatHiddenChildrenLine(widget, depth, ctx);
177
+ output += `${indent}${closeTag}\n`;
178
+
179
+ return output;
119
180
  }
181
+
182
+ output += formatChildren(widget, depth, ctx);
120
183
  output += `${indent}${closeTag}\n`;
184
+
121
185
  return output;
122
186
  };
123
187
 
188
+ const resolveMaxLength = (options: PrettyWidgetOptions): number => {
189
+ const envLimit = process.env.DEBUG_PRINT_LIMIT ? Number(process.env.DEBUG_PRINT_LIMIT) : DEFAULT_MAX_LENGTH;
190
+
191
+ return options.maxLength ?? envLimit;
192
+ };
193
+
124
194
  /**
125
195
  * Renders a widget tree as an indented, HTML-like string showing each widget's
126
196
  * tag, accessible attributes, and text content.
@@ -129,20 +199,19 @@ const formatWidget = (
129
199
  * @param options Formatting options such as truncation length and highlighting.
130
200
  * @returns The formatted representation of the tree.
131
201
  */
132
- export const prettyWidget = (container: Container, options: PrettyWidgetOptions = {}): string => {
133
- const envLimit = process.env.DEBUG_PRINT_LIMIT ? Number(process.env.DEBUG_PRINT_LIMIT) : DEFAULT_MAX_LENGTH;
134
- const maxLength = options.maxLength ?? envLimit;
202
+ const prettyWidget = (container: Container, options: PrettyWidgetOptions = {}): string => {
203
+ const maxLength = resolveMaxLength(options);
135
204
 
136
205
  if (maxLength === 0) {
137
206
  return "";
138
207
  }
139
208
 
140
- const highlight = options.highlight ?? shouldHighlight();
141
- const colors = createColors(highlight);
142
-
209
+ const isHighlight = options.highlight ?? shouldHighlight();
210
+ const colors = createColors(isHighlight);
143
211
  let output = "";
212
+
144
213
  for (const root of roots(container)) {
145
- output += formatWidget(root, 0, options.getId, colors);
214
+ output += formatWidget(root, 0, { getId: options.getId, colors, maxDepth: options.maxDepth });
146
215
  }
147
216
 
148
217
  if (output.length > maxLength) {
@@ -158,9 +227,12 @@ export const prettyWidget = (container: Container, options: PrettyWidgetOptions
158
227
  * @param container A single scope or an array of scopes to format and print.
159
228
  * @param options Formatting options passed through to {@link prettyWidget}.
160
229
  */
161
- export const logWidget = (container: Container | Container[], options?: PrettyWidgetOptions): void => {
230
+ const logWidget = (container: Container | Container[], options?: PrettyWidgetOptions): void => {
162
231
  const containers: Container[] = Array.isArray(container) ? container : [container];
232
+
163
233
  for (const target of containers) {
164
234
  console.log(prettyWidget(target, options));
165
235
  }
166
236
  };
237
+
238
+ export { prettyWidget, logWidget, type PrettyWidgetOptions };