@gtkx/testing 0.9.3 → 0.10.0

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/README.md CHANGED
@@ -1,47 +1,43 @@
1
1
  <p align="center">
2
- <img src="https://raw.githubusercontent.com/eugeniodepalo/gtkx/HEAD/logo.svg" alt="GTKX Logo" width="128" height="128">
2
+ <img src="https://raw.githubusercontent.com/eugeniodepalo/gtkx/main/logo.svg" alt="GTKX" width="80" height="80">
3
3
  </p>
4
4
 
5
5
  <h1 align="center">GTKX</h1>
6
6
 
7
7
  <p align="center">
8
- <strong>Build native GTK4 desktop apps with React</strong>
8
+ <strong>Build native GTK4 desktop applications with React and TypeScript.</strong>
9
9
  </p>
10
10
 
11
11
  <p align="center">
12
- <a href="https://eugeniodepalo.github.io/gtkx">Documentation</a> ·
13
- <a href="#quick-start">Quick Start</a> ·
14
- <a href="#examples">Examples</a> ·
15
- <a href="#contributing">Contributing</a>
12
+ <a href="https://www.npmjs.com/package/@gtkx/react"><img src="https://img.shields.io/npm/v/@gtkx/react.svg" alt="npm version"></a>
13
+ <a href="https://github.com/eugeniodepalo/gtkx/actions"><img src="https://img.shields.io/github/actions/workflow/status/eugeniodepalo/gtkx/ci.yml" alt="CI"></a>
14
+ <a href="https://github.com/eugeniodepalo/gtkx/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MPL--2.0-blue.svg" alt="License"></a>
15
+ <a href="https://github.com/eugeniodepalo/gtkx/discussions"><img src="https://img.shields.io/badge/discussions-GitHub-blue" alt="GitHub Discussions"></a>
16
16
  </p>
17
17
 
18
18
  ---
19
19
 
20
- GTKX lets you build native Linux desktop applications using React and TypeScript. Write familiar React code that renders as native GTK4 widgets—no Electron, no web views.
21
-
22
- ## Features
23
-
24
- - **React** — Hooks, state, props, and components you already know
25
- - **HMR** — Edit code and see changes instantly via Vite
26
- - **Native** — Direct FFI bindings to GTK4 via Rust and libffi
27
- - **CLI** — `npx @gtkx/cli@latest create` scaffolds a ready-to-go project
28
- - **CSS-in-JS** — Emotion-style `css` template literals for GTK styling
29
- - **Testing** — Testing Library-style `screen`, `userEvent`, and queries
20
+ GTKX lets you write Linux desktop applications using React. Your components render as native GTK4 widgets through a Rust FFI bridge—no webviews, no Electron, just native performance with the developer experience you already know.
30
21
 
31
22
  ## Quick Start
32
23
 
33
24
  ```bash
34
- npx @gtkx/cli@latest create my-app
25
+ npx @gtkx/cli create my-app
35
26
  cd my-app
36
27
  npm run dev
37
28
  ```
38
29
 
39
- Edit your code and see changes instantly—no restart needed.
40
-
41
- ### Example
30
+ ## Example
42
31
 
43
32
  ```tsx
44
- import { render, ApplicationWindow, Box, Button, quit } from "@gtkx/react";
33
+ import {
34
+ GtkApplicationWindow,
35
+ GtkBox,
36
+ GtkButton,
37
+ GtkLabel,
38
+ quit,
39
+ render,
40
+ } from "@gtkx/react";
45
41
  import * as Gtk from "@gtkx/ffi/gtk";
46
42
  import { useState } from "react";
47
43
 
@@ -49,67 +45,59 @@ const App = () => {
49
45
  const [count, setCount] = useState(0);
50
46
 
51
47
  return (
52
- <ApplicationWindow title="Counter" onCloseRequest={quit}>
53
- <Box orientation={Gtk.Orientation.VERTICAL} spacing={12}>
54
- {`Count: ${count}`}
55
- <Button label="Increment" onClicked={() => setCount((c) => c + 1)} />
56
- </Box>
57
- </ApplicationWindow>
48
+ <GtkApplicationWindow
49
+ title="Counter"
50
+ defaultWidth={300}
51
+ defaultHeight={200}
52
+ onCloseRequest={quit}
53
+ >
54
+ <GtkBox
55
+ orientation={Gtk.Orientation.VERTICAL}
56
+ spacing={20}
57
+ valign={Gtk.Align.CENTER}
58
+ >
59
+ <GtkLabel label={`Count: ${count}`} cssClasses={["title-1"]} />
60
+ <GtkButton label="Increment" onClicked={() => setCount((c) => c + 1)} />
61
+ </GtkBox>
62
+ </GtkApplicationWindow>
58
63
  );
59
64
  };
60
65
 
61
- render(<App />, "org.example.Counter");
66
+ render(<App />, "com.example.counter");
62
67
  ```
63
68
 
64
- ## Styling
65
-
66
- ```tsx
67
- import { css } from "@gtkx/css";
68
- import { Button } from "@gtkx/react";
69
-
70
- const primary = css`
71
- padding: 16px 32px;
72
- border-radius: 24px;
73
- background: linear-gradient(135deg, #3584e4, #9141ac);
74
- color: white;
75
- `;
76
-
77
- <Button label="Click me" cssClasses={[primary]} />;
78
- ```
79
-
80
- ## Testing
81
-
82
- ```tsx
83
- import { cleanup, render, screen, userEvent } from "@gtkx/testing";
84
- import * as Gtk from "@gtkx/ffi/gtk";
85
-
86
- afterEach(() => cleanup());
69
+ ## Features
87
70
 
88
- test("increments count", async () => {
89
- await render(<App />);
71
+ - **React 19** — Hooks, concurrent features, and the component model you know
72
+ - **Native GTK4 widgets** — Real native controls, not web components in a webview
73
+ - **Adwaita support** — Modern GNOME styling with Libadwaita components
74
+ - **Hot Module Replacement** — Fast refresh during development
75
+ - **TypeScript first** — Full type safety with auto-generated bindings
76
+ - **CSS-in-JS styling** — Familiar styling patterns adapted for GTK
77
+ - **Testing utilities** — Component testing similar to Testing Library
90
78
 
91
- const button = await screen.findByRole(Gtk.AccessibleRole.BUTTON, {
92
- name: "Increment",
93
- });
79
+ ## Examples
94
80
 
95
- await userEvent.click(button);
81
+ Explore complete applications in the [`examples/`](./examples) directory:
96
82
 
97
- await screen.findByText("Count: 1");
98
- });
99
- ```
83
+ - **[gtk-demo](./examples/gtk-demo)** — Full replica of the official GTK demo app
84
+ - **[hello-world](./examples/hello-world)** — Minimal application showing a counter
85
+ - **[todo](./examples/todo)** — Full-featured todo application with Adwaita styling and testing
86
+ - **[deploying](./examples/deploying)** — Example of packaging and distributing a GTKX app
100
87
 
101
- ## Requirements
88
+ ## Documentation
102
89
 
103
- - Node.js 20+ (Deno support experimental)
104
- - GTK4 Runtime (`gtk4` on Fedora, `libgtk-4-1` on Ubuntu)
90
+ Visit [https://eugeniodepalo.github.io/gtkx](https://eugeniodepalo.github.io/gtkx/) for the full documentation.
105
91
 
106
92
  ## Contributing
107
93
 
108
- We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
94
+ Contributions are welcome! Please see the [contributing guidelines](./CONTRIBUTING.md) and check out the [good first issues](https://github.com/eugeniodepalo/gtkx/labels/good%20first%20issue).
95
+
96
+ ## Community
109
97
 
110
- - [Report a bug](https://github.com/eugeniodepalo/gtkx/issues/new?template=bug_report.md)
111
- - [Request a feature](https://github.com/eugeniodepalo/gtkx/issues/new?template=feature_request.md)
98
+ - [GitHub Discussions](https://github.com/eugeniodepalo/gtkx/discussions) — Questions, ideas, and general discussion
99
+ - [Issue Tracker](https://github.com/eugeniodepalo/gtkx/issues) — Bug reports and feature requests
112
100
 
113
101
  ## License
114
102
 
115
- [MPL-2.0](LICENSE)
103
+ [MPL-2.0](./LICENSE)
@@ -1,17 +1,23 @@
1
1
  import type * as Gtk from "@gtkx/ffi/gtk";
2
2
  import type { Arg } from "@gtkx/native";
3
3
  /**
4
- * Low-level utility to emit GTK signals on widgets. For common interactions
5
- * like clicking or typing, use `userEvent` instead.
4
+ * Emits a GTK signal on a widget.
6
5
  *
7
- * @param element - The GTK widget to emit the signal on
8
- * @param signalName - The name of the signal to emit
9
- * @param args - Additional arguments to pass to the signal handlers
6
+ * Low-level utility for triggering signals directly. Prefer {@link userEvent}
7
+ * for common interactions like clicking and typing.
10
8
  *
11
- * @example
12
- * await fireEvent(button, "clicked")
9
+ * @param element - The widget to emit the signal on
10
+ * @param signalName - GTK signal name (e.g., "clicked", "activate")
11
+ * @param args - Additional signal arguments
13
12
  *
14
13
  * @example
15
- * await fireEvent(widget, "custom-signal", { type: { type: "int", size: 32 }, value: 42 })
14
+ * ```tsx
15
+ * import { fireEvent } from "@gtkx/testing";
16
+ *
17
+ * // Emit custom signal
18
+ * await fireEvent(widget, "my-custom-signal");
19
+ * ```
20
+ *
21
+ * @see {@link userEvent} for high-level user interactions
16
22
  */
17
23
  export declare const fireEvent: (element: Gtk.Widget, signalName: string, ...args: Arg[]) => Promise<void>;
@@ -1,18 +1,24 @@
1
1
  import { call } from "@gtkx/native";
2
2
  import { tick } from "./timing.js";
3
3
  /**
4
- * Low-level utility to emit GTK signals on widgets. For common interactions
5
- * like clicking or typing, use `userEvent` instead.
4
+ * Emits a GTK signal on a widget.
6
5
  *
7
- * @param element - The GTK widget to emit the signal on
8
- * @param signalName - The name of the signal to emit
9
- * @param args - Additional arguments to pass to the signal handlers
6
+ * Low-level utility for triggering signals directly. Prefer {@link userEvent}
7
+ * for common interactions like clicking and typing.
10
8
  *
11
- * @example
12
- * await fireEvent(button, "clicked")
9
+ * @param element - The widget to emit the signal on
10
+ * @param signalName - GTK signal name (e.g., "clicked", "activate")
11
+ * @param args - Additional signal arguments
13
12
  *
14
13
  * @example
15
- * await fireEvent(widget, "custom-signal", { type: { type: "int", size: 32 }, value: 42 })
14
+ * ```tsx
15
+ * import { fireEvent } from "@gtkx/testing";
16
+ *
17
+ * // Emit custom signal
18
+ * await fireEvent(widget, "my-custom-signal");
19
+ * ```
20
+ *
21
+ * @see {@link userEvent} for high-level user interactions
16
22
  */
17
23
  export const fireEvent = async (element, signalName, ...args) => {
18
24
  call("libgobject-2.0.so.0", "g_signal_emit_by_name", [{ type: { type: "gobject" }, value: element.id }, { type: { type: "string" }, value: signalName }, ...args], { type: "undefined" });
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  export { fireEvent } from "./fire-event.js";
2
2
  export { findAllByLabelText, findAllByRole, findAllByTestId, findAllByText, findByLabelText, findByRole, findByTestId, findByText, } from "./queries.js";
3
- export { cleanup, render, teardown } from "./render.js";
3
+ export { cleanup, render } from "./render.js";
4
4
  export { screen } from "./screen.js";
5
+ export { tick } from "./timing.js";
5
6
  export type { BoundQueries, ByRoleOptions, NormalizerOptions, RenderOptions, RenderResult, TextMatch, TextMatchFunction, TextMatchOptions, WaitForOptions, } from "./types.js";
6
7
  export type { TabOptions } from "./user-event.js";
7
8
  export { userEvent } from "./user-event.js";
package/dist/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  export { fireEvent } from "./fire-event.js";
2
2
  export { findAllByLabelText, findAllByRole, findAllByTestId, findAllByText, findByLabelText, findByRole, findByTestId, findByText, } from "./queries.js";
3
- export { cleanup, render, teardown } from "./render.js";
3
+ export { cleanup, render } from "./render.js";
4
4
  export { screen } from "./screen.js";
5
+ export { tick } from "./timing.js";
5
6
  export { userEvent } from "./user-event.js";
6
7
  export { waitFor, waitForElementToBeRemoved } from "./wait-for.js";
7
8
  export { within } from "./within.js";
package/dist/queries.d.ts CHANGED
@@ -2,66 +2,101 @@ import * as Gtk from "@gtkx/ffi/gtk";
2
2
  import type { ByRoleOptions, TextMatch, TextMatchOptions } from "./types.js";
3
3
  type Container = Gtk.Application | Gtk.Widget;
4
4
  /**
5
- * Waits for and finds a single widget matching the specified accessible role.
5
+ * Finds a single element by accessible role.
6
+ *
7
+ * Waits for the element to appear, throwing if not found within timeout.
8
+ *
6
9
  * @param container - The container to search within
7
- * @param role - The accessible role to match
8
- * @param options - Additional filtering options (name, checked, expanded)
10
+ * @param role - The GTK accessible role to match
11
+ * @param options - Query options including name, state filters, and timeout
9
12
  * @returns Promise resolving to the matching widget
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * const button = await findByRole(container, Gtk.AccessibleRole.BUTTON, { name: "Submit" });
17
+ * ```
10
18
  */
11
19
  export declare const findByRole: (container: Container, role: Gtk.AccessibleRole, options?: ByRoleOptions) => Promise<Gtk.Widget>;
12
20
  /**
13
- * Waits for and finds all widgets matching the specified accessible role.
21
+ * Finds all elements matching an accessible role.
22
+ *
14
23
  * @param container - The container to search within
15
- * @param role - The accessible role to match
16
- * @param options - Additional filtering options (name, checked, expanded)
24
+ * @param role - The GTK accessible role to match
25
+ * @param options - Query options including name, state filters, and timeout
17
26
  * @returns Promise resolving to array of matching widgets
18
27
  */
19
28
  export declare const findAllByRole: (container: Container, role: Gtk.AccessibleRole, options?: ByRoleOptions) => Promise<Gtk.Widget[]>;
20
29
  /**
21
- * Waits for and finds a single widget matching the specified label text.
30
+ * Finds a single element by its label or text content.
31
+ *
32
+ * Matches button labels, input placeholders, window titles, and other
33
+ * accessible text content.
34
+ *
22
35
  * @param container - The container to search within
23
- * @param text - The text, pattern, or matcher function
24
- * @param options - Text matching options (exact, normalizer, timeout)
36
+ * @param text - Text to match (string, RegExp, or custom matcher)
37
+ * @param options - Query options including normalization and timeout
25
38
  * @returns Promise resolving to the matching widget
39
+ *
40
+ * @example
41
+ * ```tsx
42
+ * const button = await findByLabelText(container, "Click me");
43
+ * const input = await findByLabelText(container, /search/i);
44
+ * ```
26
45
  */
27
46
  export declare const findByLabelText: (container: Container, text: TextMatch, options?: TextMatchOptions) => Promise<Gtk.Widget>;
28
47
  /**
29
- * Waits for and finds all widgets matching the specified label text.
48
+ * Finds all elements matching label or text content.
49
+ *
30
50
  * @param container - The container to search within
31
- * @param text - The text, pattern, or matcher function
32
- * @param options - Text matching options (exact, normalizer, timeout)
51
+ * @param text - Text to match (string, RegExp, or custom matcher)
52
+ * @param options - Query options including normalization and timeout
33
53
  * @returns Promise resolving to array of matching widgets
34
54
  */
35
55
  export declare const findAllByLabelText: (container: Container, text: TextMatch, options?: TextMatchOptions) => Promise<Gtk.Widget[]>;
36
56
  /**
37
- * Waits for and finds a single widget matching the specified text content.
57
+ * Finds a single element by visible text content.
58
+ *
59
+ * Similar to {@link findByLabelText} but focuses on directly visible text.
60
+ *
38
61
  * @param container - The container to search within
39
- * @param text - The text, pattern, or matcher function
40
- * @param options - Text matching options (exact, normalizer, timeout)
62
+ * @param text - Text to match (string, RegExp, or custom matcher)
63
+ * @param options - Query options including normalization and timeout
41
64
  * @returns Promise resolving to the matching widget
42
65
  */
43
66
  export declare const findByText: (container: Container, text: TextMatch, options?: TextMatchOptions) => Promise<Gtk.Widget>;
44
67
  /**
45
- * Waits for and finds all widgets matching the specified text content.
68
+ * Finds all elements matching visible text content.
69
+ *
46
70
  * @param container - The container to search within
47
- * @param text - The text, pattern, or matcher function
48
- * @param options - Text matching options (exact, normalizer, timeout)
71
+ * @param text - Text to match (string, RegExp, or custom matcher)
72
+ * @param options - Query options including normalization and timeout
49
73
  * @returns Promise resolving to array of matching widgets
50
74
  */
51
75
  export declare const findAllByText: (container: Container, text: TextMatch, options?: TextMatchOptions) => Promise<Gtk.Widget[]>;
52
76
  /**
53
- * Waits for and finds a single widget matching the specified test ID.
77
+ * Finds a single element by test ID (widget name).
78
+ *
79
+ * Uses the widget's `name` property as a test identifier.
80
+ * Set via the `name` prop on GTKX components.
81
+ *
54
82
  * @param container - The container to search within
55
- * @param testId - The test ID, pattern, or matcher function
56
- * @param options - Text matching options (exact, normalizer, timeout)
83
+ * @param testId - Test ID to match (string, RegExp, or custom matcher)
84
+ * @param options - Query options including normalization and timeout
57
85
  * @returns Promise resolving to the matching widget
86
+ *
87
+ * @example
88
+ * ```tsx
89
+ * // In component: <GtkButton name="submit-btn" />
90
+ * const button = await findByTestId(container, "submit-btn");
91
+ * ```
58
92
  */
59
93
  export declare const findByTestId: (container: Container, testId: TextMatch, options?: TextMatchOptions) => Promise<Gtk.Widget>;
60
94
  /**
61
- * Waits for and finds all widgets matching the specified test ID.
95
+ * Finds all elements matching a test ID pattern.
96
+ *
62
97
  * @param container - The container to search within
63
- * @param testId - The test ID, pattern, or matcher function
64
- * @param options - Text matching options (exact, normalizer, timeout)
98
+ * @param testId - Test ID to match (string, RegExp, or custom matcher)
99
+ * @param options - Query options including normalization and timeout
65
100
  * @returns Promise resolving to array of matching widgets
66
101
  */
67
102
  export declare const findAllByTestId: (container: Container, testId: TextMatch, options?: TextMatchOptions) => Promise<Gtk.Widget[]>;
package/dist/queries.js CHANGED
@@ -148,7 +148,6 @@ const getWidgetCheckedState = (widget) => {
148
148
  case Gtk.AccessibleRole.SWITCH:
149
149
  return widget.getActive();
150
150
  default:
151
- return undefined;
152
151
  }
153
152
  };
154
153
  const getWidgetExpandedState = (widget) => {
@@ -162,7 +161,6 @@ const getWidgetExpandedState = (widget) => {
162
161
  return undefined;
163
162
  return parent.getExpanded?.();
164
163
  }
165
- return undefined;
166
164
  };
167
165
  const matchByRoleOptions = (widget, options) => {
168
166
  if (!options)
@@ -186,9 +184,9 @@ const matchByRoleOptions = (widget, options) => {
186
184
  };
187
185
  const formatRole = (role) => Gtk.AccessibleRole[role] ?? String(role);
188
186
  const formatByRoleError = (role, options) => {
189
- const parts = [`role "${formatRole(role)}"`];
187
+ const parts = [`role '${formatRole(role)}'`];
190
188
  if (options?.name)
191
- parts.push(`name "${options.name}"`);
189
+ parts.push(`name '${options.name}'`);
192
190
  if (options?.checked !== undefined)
193
191
  parts.push(`checked=${options.checked}`);
194
192
  if (options?.pressed !== undefined)
@@ -216,7 +214,7 @@ const getAllByRole = (container, role, options) => {
216
214
  const getByRole = (container, role, options) => {
217
215
  const matches = getAllByRole(container, role, options);
218
216
  if (matches.length > 1) {
219
- throw new Error(`Found ${matches.length} elements with ${formatByRoleError(role, options)}`);
217
+ throw new Error(`Expected 1 element with ${formatByRoleError(role, options)}, found ${matches.length}`);
220
218
  }
221
219
  const [first] = matches;
222
220
  if (!first)
@@ -229,18 +227,18 @@ const getAllByLabelText = (container, text, options) => {
229
227
  return matchText(widgetText, text, node, options);
230
228
  });
231
229
  if (matches.length === 0) {
232
- throw new Error(`Unable to find any elements with label text "${text}"`);
230
+ throw new Error(`Unable to find any elements with label text '${text}'`);
233
231
  }
234
232
  return matches;
235
233
  };
236
234
  const getByLabelText = (container, text, options) => {
237
235
  const matches = getAllByLabelText(container, text, options);
238
236
  if (matches.length > 1) {
239
- throw new Error(`Found ${matches.length} elements with label text "${text}"`);
237
+ throw new Error(`Expected 1 element with label text '${text}', found ${matches.length}`);
240
238
  }
241
239
  const [first] = matches;
242
240
  if (!first)
243
- throw new Error(`Unable to find element with label text "${text}"`);
241
+ throw new Error(`Unable to find element with label text '${text}'`);
244
242
  return first;
245
243
  };
246
244
  const getAllByText = (container, text, options) => {
@@ -249,18 +247,18 @@ const getAllByText = (container, text, options) => {
249
247
  return matchText(widgetText, text, node, options);
250
248
  });
251
249
  if (matches.length === 0) {
252
- throw new Error(`Unable to find any elements with text "${text}"`);
250
+ throw new Error(`Unable to find any elements with text '${text}'`);
253
251
  }
254
252
  return matches;
255
253
  };
256
254
  const getByText = (container, text, options) => {
257
255
  const matches = getAllByText(container, text, options);
258
256
  if (matches.length > 1) {
259
- throw new Error(`Found ${matches.length} elements with text "${text}"`);
257
+ throw new Error(`Expected 1 element with text '${text}', found ${matches.length}`);
260
258
  }
261
259
  const [first] = matches;
262
260
  if (!first)
263
- throw new Error(`Unable to find element with text "${text}"`);
261
+ throw new Error(`Unable to find element with text '${text}'`);
264
262
  return first;
265
263
  };
266
264
  const getAllByTestId = (container, testId, options) => {
@@ -269,95 +267,130 @@ const getAllByTestId = (container, testId, options) => {
269
267
  return matchText(widgetTestId, testId, node, options);
270
268
  });
271
269
  if (matches.length === 0) {
272
- throw new Error(`Unable to find any elements with test id "${testId}"`);
270
+ throw new Error(`Unable to find any elements with test id '${testId}'`);
273
271
  }
274
272
  return matches;
275
273
  };
276
274
  const getByTestId = (container, testId, options) => {
277
275
  const matches = getAllByTestId(container, testId, options);
278
276
  if (matches.length > 1) {
279
- throw new Error(`Found ${matches.length} elements with test id "${testId}"`);
277
+ throw new Error(`Expected 1 element with test id '${testId}', found ${matches.length}`);
280
278
  }
281
279
  const [first] = matches;
282
280
  if (!first)
283
- throw new Error(`Unable to find element with test id "${testId}"`);
281
+ throw new Error(`Unable to find element with test id '${testId}'`);
284
282
  return first;
285
283
  };
286
284
  /**
287
- * Waits for and finds a single widget matching the specified accessible role.
285
+ * Finds a single element by accessible role.
286
+ *
287
+ * Waits for the element to appear, throwing if not found within timeout.
288
+ *
288
289
  * @param container - The container to search within
289
- * @param role - The accessible role to match
290
- * @param options - Additional filtering options (name, checked, expanded)
290
+ * @param role - The GTK accessible role to match
291
+ * @param options - Query options including name, state filters, and timeout
291
292
  * @returns Promise resolving to the matching widget
293
+ *
294
+ * @example
295
+ * ```tsx
296
+ * const button = await findByRole(container, Gtk.AccessibleRole.BUTTON, { name: "Submit" });
297
+ * ```
292
298
  */
293
299
  export const findByRole = async (container, role, options) => waitFor(() => getByRole(container, role, options), {
294
300
  timeout: options?.timeout,
295
301
  });
296
302
  /**
297
- * Waits for and finds all widgets matching the specified accessible role.
303
+ * Finds all elements matching an accessible role.
304
+ *
298
305
  * @param container - The container to search within
299
- * @param role - The accessible role to match
300
- * @param options - Additional filtering options (name, checked, expanded)
306
+ * @param role - The GTK accessible role to match
307
+ * @param options - Query options including name, state filters, and timeout
301
308
  * @returns Promise resolving to array of matching widgets
302
309
  */
303
310
  export const findAllByRole = async (container, role, options) => waitFor(() => getAllByRole(container, role, options), {
304
311
  timeout: options?.timeout,
305
312
  });
306
313
  /**
307
- * Waits for and finds a single widget matching the specified label text.
314
+ * Finds a single element by its label or text content.
315
+ *
316
+ * Matches button labels, input placeholders, window titles, and other
317
+ * accessible text content.
318
+ *
308
319
  * @param container - The container to search within
309
- * @param text - The text, pattern, or matcher function
310
- * @param options - Text matching options (exact, normalizer, timeout)
320
+ * @param text - Text to match (string, RegExp, or custom matcher)
321
+ * @param options - Query options including normalization and timeout
311
322
  * @returns Promise resolving to the matching widget
323
+ *
324
+ * @example
325
+ * ```tsx
326
+ * const button = await findByLabelText(container, "Click me");
327
+ * const input = await findByLabelText(container, /search/i);
328
+ * ```
312
329
  */
313
330
  export const findByLabelText = async (container, text, options) => waitFor(() => getByLabelText(container, text, options), {
314
331
  timeout: options?.timeout,
315
332
  });
316
333
  /**
317
- * Waits for and finds all widgets matching the specified label text.
334
+ * Finds all elements matching label or text content.
335
+ *
318
336
  * @param container - The container to search within
319
- * @param text - The text, pattern, or matcher function
320
- * @param options - Text matching options (exact, normalizer, timeout)
337
+ * @param text - Text to match (string, RegExp, or custom matcher)
338
+ * @param options - Query options including normalization and timeout
321
339
  * @returns Promise resolving to array of matching widgets
322
340
  */
323
341
  export const findAllByLabelText = async (container, text, options) => waitFor(() => getAllByLabelText(container, text, options), {
324
342
  timeout: options?.timeout,
325
343
  });
326
344
  /**
327
- * Waits for and finds a single widget matching the specified text content.
345
+ * Finds a single element by visible text content.
346
+ *
347
+ * Similar to {@link findByLabelText} but focuses on directly visible text.
348
+ *
328
349
  * @param container - The container to search within
329
- * @param text - The text, pattern, or matcher function
330
- * @param options - Text matching options (exact, normalizer, timeout)
350
+ * @param text - Text to match (string, RegExp, or custom matcher)
351
+ * @param options - Query options including normalization and timeout
331
352
  * @returns Promise resolving to the matching widget
332
353
  */
333
354
  export const findByText = async (container, text, options) => waitFor(() => getByText(container, text, options), {
334
355
  timeout: options?.timeout,
335
356
  });
336
357
  /**
337
- * Waits for and finds all widgets matching the specified text content.
358
+ * Finds all elements matching visible text content.
359
+ *
338
360
  * @param container - The container to search within
339
- * @param text - The text, pattern, or matcher function
340
- * @param options - Text matching options (exact, normalizer, timeout)
361
+ * @param text - Text to match (string, RegExp, or custom matcher)
362
+ * @param options - Query options including normalization and timeout
341
363
  * @returns Promise resolving to array of matching widgets
342
364
  */
343
365
  export const findAllByText = async (container, text, options) => waitFor(() => getAllByText(container, text, options), {
344
366
  timeout: options?.timeout,
345
367
  });
346
368
  /**
347
- * Waits for and finds a single widget matching the specified test ID.
369
+ * Finds a single element by test ID (widget name).
370
+ *
371
+ * Uses the widget's `name` property as a test identifier.
372
+ * Set via the `name` prop on GTKX components.
373
+ *
348
374
  * @param container - The container to search within
349
- * @param testId - The test ID, pattern, or matcher function
350
- * @param options - Text matching options (exact, normalizer, timeout)
375
+ * @param testId - Test ID to match (string, RegExp, or custom matcher)
376
+ * @param options - Query options including normalization and timeout
351
377
  * @returns Promise resolving to the matching widget
378
+ *
379
+ * @example
380
+ * ```tsx
381
+ * // In component: <GtkButton name="submit-btn" />
382
+ * const button = await findByTestId(container, "submit-btn");
383
+ * ```
352
384
  */
353
385
  export const findByTestId = async (container, testId, options) => waitFor(() => getByTestId(container, testId, options), {
354
386
  timeout: options?.timeout,
355
387
  });
356
388
  /**
357
- * Waits for and finds all widgets matching the specified test ID.
389
+ * Finds all elements matching a test ID pattern.
390
+ *
358
391
  * @param container - The container to search within
359
- * @param testId - The test ID, pattern, or matcher function
360
- * @param options - Text matching options (exact, normalizer, timeout)
392
+ * @param testId - Test ID to match (string, RegExp, or custom matcher)
393
+ * @param options - Query options including normalization and timeout
361
394
  * @returns Promise resolving to array of matching widgets
362
395
  */
363
396
  export const findAllByTestId = async (container, testId, options) => waitFor(() => getAllByTestId(container, testId, options), {