@gtkx/testing 0.21.0 → 1.0.0-rc.1

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 (216) hide show
  1. package/README.md +137 -34
  2. package/dist/act.d.ts +19 -0
  3. package/dist/act.d.ts.map +1 -0
  4. package/dist/act.js +48 -0
  5. package/dist/act.js.map +1 -0
  6. package/dist/bound-queries.d.ts +32 -0
  7. package/dist/bound-queries.d.ts.map +1 -0
  8. package/dist/bound-queries.js +2 -0
  9. package/dist/bound-queries.js.map +1 -0
  10. package/dist/build-queries.d.ts +16 -0
  11. package/dist/build-queries.d.ts.map +1 -0
  12. package/dist/build-queries.js +103 -0
  13. package/dist/build-queries.js.map +1 -0
  14. package/dist/cleanup-registry.d.ts +4 -0
  15. package/dist/cleanup-registry.d.ts.map +1 -0
  16. package/dist/cleanup-registry.js +11 -0
  17. package/dist/cleanup-registry.js.map +1 -0
  18. package/dist/config.d.ts +18 -51
  19. package/dist/config.d.ts.map +1 -1
  20. package/dist/config.js +9 -40
  21. package/dist/config.js.map +1 -1
  22. package/dist/editable.d.ts +7 -0
  23. package/dist/editable.d.ts.map +1 -0
  24. package/dist/editable.js +24 -0
  25. package/dist/editable.js.map +1 -0
  26. package/dist/errors.d.ts +29 -0
  27. package/dist/errors.d.ts.map +1 -0
  28. package/dist/errors.js +119 -0
  29. package/dist/errors.js.map +1 -0
  30. package/dist/fire-event.d.ts +7 -25
  31. package/dist/fire-event.d.ts.map +1 -1
  32. package/dist/fire-event.js +9 -29
  33. package/dist/fire-event.js.map +1 -1
  34. package/dist/frame-sync.d.ts +3 -0
  35. package/dist/frame-sync.d.ts.map +1 -0
  36. package/dist/frame-sync.js +30 -0
  37. package/dist/frame-sync.js.map +1 -0
  38. package/dist/index.d.ts +16 -11
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +10 -6
  41. package/dist/index.js.map +1 -1
  42. package/dist/matchers.d.ts +55 -0
  43. package/dist/matchers.d.ts.map +1 -0
  44. package/dist/matchers.js +103 -0
  45. package/dist/matchers.js.map +1 -0
  46. package/dist/pretty-widget.d.ts +21 -25
  47. package/dist/pretty-widget.d.ts.map +1 -1
  48. package/dist/pretty-widget.js +69 -115
  49. package/dist/pretty-widget.js.map +1 -1
  50. package/dist/queries.d.ts +130 -177
  51. package/dist/queries.d.ts.map +1 -1
  52. package/dist/queries.js +212 -325
  53. package/dist/queries.js.map +1 -1
  54. package/dist/register-test-hooks.d.ts +2 -0
  55. package/dist/register-test-hooks.d.ts.map +1 -0
  56. package/dist/register-test-hooks.js +15 -0
  57. package/dist/register-test-hooks.js.map +1 -0
  58. package/dist/render-hook.d.ts +14 -35
  59. package/dist/render-hook.d.ts.map +1 -1
  60. package/dist/render-hook.js +8 -45
  61. package/dist/render-hook.js.map +1 -1
  62. package/dist/render.d.ts +11 -41
  63. package/dist/render.d.ts.map +1 -1
  64. package/dist/render.js +129 -118
  65. package/dist/render.js.map +1 -1
  66. package/dist/role-helpers.d.ts +16 -51
  67. package/dist/role-helpers.d.ts.map +1 -1
  68. package/dist/role-helpers.js +39 -58
  69. package/dist/role-helpers.js.map +1 -1
  70. package/dist/screen.d.ts +6 -63
  71. package/dist/screen.d.ts.map +1 -1
  72. package/dist/screen.js +21 -109
  73. package/dist/screen.js.map +1 -1
  74. package/dist/screenshot.d.ts +20 -23
  75. package/dist/screenshot.d.ts.map +1 -1
  76. package/dist/screenshot.js +89 -48
  77. package/dist/screenshot.js.map +1 -1
  78. package/dist/suggestions.d.ts +22 -0
  79. package/dist/suggestions.d.ts.map +1 -0
  80. package/dist/suggestions.js +56 -0
  81. package/dist/suggestions.js.map +1 -0
  82. package/dist/traversal.d.ts +10 -8
  83. package/dist/traversal.d.ts.map +1 -1
  84. package/dist/traversal.js +28 -13
  85. package/dist/traversal.js.map +1 -1
  86. package/dist/types.d.ts +103 -172
  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 +8 -0
  90. package/dist/user-event/adjustment.d.ts.map +1 -0
  91. package/dist/user-event/adjustment.js +33 -0
  92. package/dist/user-event/adjustment.js.map +1 -0
  93. package/dist/user-event/click.d.ts +7 -0
  94. package/dist/user-event/click.d.ts.map +1 -0
  95. package/dist/user-event/click.js +65 -0
  96. package/dist/user-event/click.js.map +1 -0
  97. package/dist/user-event/controller.d.ts +7 -0
  98. package/dist/user-event/controller.d.ts.map +1 -0
  99. package/dist/user-event/controller.js +28 -0
  100. package/dist/user-event/controller.js.map +1 -0
  101. package/dist/user-event/dispatch.d.ts +7 -0
  102. package/dist/user-event/dispatch.d.ts.map +1 -0
  103. package/dist/user-event/dispatch.js +10 -0
  104. package/dist/user-event/dispatch.js.map +1 -0
  105. package/dist/user-event/event-wrapper.d.ts +3 -0
  106. package/dist/user-event/event-wrapper.d.ts.map +1 -0
  107. package/dist/user-event/event-wrapper.js +48 -0
  108. package/dist/user-event/event-wrapper.js.map +1 -0
  109. package/dist/user-event/gesture.d.ts +31 -0
  110. package/dist/user-event/gesture.d.ts.map +1 -0
  111. package/dist/user-event/gesture.js +105 -0
  112. package/dist/user-event/gesture.js.map +1 -0
  113. package/dist/user-event/index.d.ts +44 -0
  114. package/dist/user-event/index.d.ts.map +1 -0
  115. package/dist/user-event/index.js +38 -0
  116. package/dist/user-event/index.js.map +1 -0
  117. package/dist/user-event/keyboard.d.ts +9 -0
  118. package/dist/user-event/keyboard.d.ts.map +1 -0
  119. package/dist/user-event/keyboard.js +173 -0
  120. package/dist/user-event/keyboard.js.map +1 -0
  121. package/dist/user-event/pointer.d.ts +6 -0
  122. package/dist/user-event/pointer.d.ts.map +1 -0
  123. package/dist/user-event/pointer.js +27 -0
  124. package/dist/user-event/pointer.js.map +1 -0
  125. package/dist/user-event/selection.d.ts +4 -0
  126. package/dist/user-event/selection.d.ts.map +1 -0
  127. package/dist/user-event/selection.js +106 -0
  128. package/dist/user-event/selection.js.map +1 -0
  129. package/dist/user-event/state.d.ts +6 -0
  130. package/dist/user-event/state.d.ts.map +1 -0
  131. package/dist/user-event/state.js +2 -0
  132. package/dist/user-event/state.js.map +1 -0
  133. package/dist/user-event/text.d.ts +17 -0
  134. package/dist/user-event/text.d.ts.map +1 -0
  135. package/dist/user-event/text.js +107 -0
  136. package/dist/user-event/text.js.map +1 -0
  137. package/dist/wait-for.d.ts +13 -33
  138. package/dist/wait-for.d.ts.map +1 -1
  139. package/dist/wait-for.js +62 -73
  140. package/dist/wait-for.js.map +1 -1
  141. package/dist/widget-accessible-properties.d.ts +33 -0
  142. package/dist/widget-accessible-properties.d.ts.map +1 -0
  143. package/dist/widget-accessible-properties.js +215 -0
  144. package/dist/widget-accessible-properties.js.map +1 -0
  145. package/dist/within.d.ts +9 -26
  146. package/dist/within.d.ts.map +1 -1
  147. package/dist/within.js +15 -25
  148. package/dist/within.js.map +1 -1
  149. package/package.json +21 -12
  150. package/src/act.ts +68 -0
  151. package/src/bound-queries.ts +36 -0
  152. package/src/build-queries.ts +185 -0
  153. package/src/cleanup-registry.ts +14 -0
  154. package/src/config.ts +28 -59
  155. package/src/editable.ts +30 -0
  156. package/src/errors.ts +130 -0
  157. package/src/fire-event.ts +11 -38
  158. package/src/frame-sync.ts +34 -0
  159. package/src/index.ts +56 -14
  160. package/src/matchers.ts +200 -0
  161. package/src/pretty-widget.ts +99 -138
  162. package/src/queries.ts +320 -420
  163. package/src/register-test-hooks.ts +16 -0
  164. package/src/render-hook.tsx +31 -44
  165. package/src/render.tsx +161 -149
  166. package/src/role-helpers.ts +47 -67
  167. package/src/screen.ts +21 -114
  168. package/src/screenshot.ts +104 -55
  169. package/src/suggestions.ts +87 -0
  170. package/src/traversal.ts +32 -18
  171. package/src/types.ts +115 -176
  172. package/src/user-event/adjustment.ts +49 -0
  173. package/src/user-event/click.ts +70 -0
  174. package/src/user-event/controller.ts +44 -0
  175. package/src/user-event/dispatch.ts +23 -0
  176. package/src/user-event/event-wrapper.ts +54 -0
  177. package/src/user-event/gesture.ts +154 -0
  178. package/src/user-event/index.ts +74 -0
  179. package/src/user-event/keyboard.ts +204 -0
  180. package/src/user-event/pointer.ts +34 -0
  181. package/src/user-event/selection.ts +122 -0
  182. package/src/user-event/state.ts +6 -0
  183. package/src/user-event/text.ts +137 -0
  184. package/src/wait-for.ts +79 -81
  185. package/src/widget-accessible-properties.ts +244 -0
  186. package/src/within.ts +26 -27
  187. package/dist/bind-queries.d.ts +0 -14
  188. package/dist/bind-queries.d.ts.map +0 -1
  189. package/dist/bind-queries.js +0 -29
  190. package/dist/bind-queries.js.map +0 -1
  191. package/dist/error-builder.d.ts +0 -28
  192. package/dist/error-builder.d.ts.map +0 -1
  193. package/dist/error-builder.js +0 -81
  194. package/dist/error-builder.js.map +0 -1
  195. package/dist/timing.d.ts +0 -18
  196. package/dist/timing.d.ts.map +0 -1
  197. package/dist/timing.js +0 -18
  198. package/dist/timing.js.map +0 -1
  199. package/dist/user-event.d.ts +0 -138
  200. package/dist/user-event.d.ts.map +0 -1
  201. package/dist/user-event.js +0 -411
  202. package/dist/user-event.js.map +0 -1
  203. package/dist/widget-text.d.ts +0 -69
  204. package/dist/widget-text.d.ts.map +0 -1
  205. package/dist/widget-text.js +0 -177
  206. package/dist/widget-text.js.map +0 -1
  207. package/dist/widget.d.ts +0 -3
  208. package/dist/widget.d.ts.map +0 -1
  209. package/dist/widget.js +0 -13
  210. package/dist/widget.js.map +0 -1
  211. package/src/bind-queries.ts +0 -52
  212. package/src/error-builder.ts +0 -102
  213. package/src/timing.ts +0 -17
  214. package/src/user-event.ts +0 -492
  215. package/src/widget-text.ts +0 -202
  216. package/src/widget.ts +0 -15
@@ -1 +1 @@
1
- {"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as Gtk from \"@gtkx/gi/gtk\";\nimport type { RootElement } from \"@gtkx/react\";\nimport {\n createReconcilerRoot,\n isRootElement,\n type ReconcilerRoot,\n setReconcilerErrorHandler,\n} from \"@gtkx/react/internal\";\nimport { type ErrorInfo, type ReactNode, StrictMode } from \"react\";\nimport { runInAct } from \"./act.js\";\nimport type { RenderResult } from \"./bound-queries.js\";\nimport { addToCleanupQueue, runCleanup } from \"./cleanup-registry.js\";\nimport { scheduleAfterLayout } from \"./frame-sync.js\";\nimport { logWidget, type PrettyWidgetOptions } from \"./pretty-widget.js\";\nimport { logRoles } from \"./role-helpers.js\";\nimport { clearScreen, setScreen } from \"./screen.js\";\nimport { captureAndSaveScreenshot } from \"./screenshot.js\";\nimport { type Container, TOPLEVELS, traverse } from \"./traversal.js\";\nimport type { QueryMap, RenderOptions, ScreenshotOptions, WindowSelector } from \"./types.js\";\nimport { resetClipboard } from \"./user-event/index.js\";\nimport { within } from \"./within.js\";\n\nlet lastRenderError: Error | null = null;\nlet errorHandlerInstalled = false;\n\ntype ActiveRender = {\n root: ReconcilerRoot;\n window: Gtk.Window | null;\n};\n\nconst activeRenders = new Set<ActiveRender>();\n\nconst HARNESS_WINDOW_WIDTH = 800;\nconst HARNESS_WINDOW_HEIGHT = 600;\n\nconst flushLayout = (window: Gtk.Window | null): Promise<void> =>\n new Promise((resolve) => {\n scheduleAfterLayout(window, resolve);\n });\n\nconst update = async (element: ReactNode, root: ReconcilerRoot): Promise<void> => {\n await runInAct(() => {\n root.update(element);\n });\n\n if (lastRenderError) {\n const captured = lastRenderError;\n lastRenderError = null;\n throw captured;\n }\n};\n\nconst disposeActiveRender = async (active: ActiveRender): Promise<void> => {\n if (!activeRenders.delete(active)) return;\n await active.root.unmount(async (root) => {\n await update(null, root);\n active.window?.destroy();\n });\n};\n\nconst disposeAllActiveRenders = async (): Promise<void> => {\n for (const active of [...activeRenders]) {\n await disposeActiveRender(active);\n }\n};\n\nconst handleError = (error: unknown): void => {\n lastRenderError = error instanceof Error ? error : new Error(String(error));\n};\n\nconst installErrorHandler = (): void => {\n if (errorHandlerInstalled) return;\n setReconcilerErrorHandler(handleError);\n errorHandlerInstalled = true;\n};\n\ntype ResolvedContainer = {\n containerInfo: Gtk.Widget | RootElement;\n window: Gtk.Window | null;\n};\n\nconst resolveContainer = (container: RenderOptions[\"container\"]): ResolvedContainer => {\n if (isRootElement(container)) {\n return { containerInfo: container, window: null };\n }\n if (container instanceof Gtk.Widget) {\n return { containerInfo: container, window: null };\n }\n const window = new Gtk.Window({ defaultWidth: HARNESS_WINDOW_WIDTH, defaultHeight: HARNESS_WINDOW_HEIGHT });\n window.setTitlebar(new Gtk.HeaderBar({ showTitleButtons: false }));\n return { containerInfo: window, window };\n};\n\nconst firstToplevelWidget = (baseElement: Container): Gtk.Widget => {\n if (baseElement instanceof Gtk.Widget) return baseElement;\n const [first] = traverse(baseElement);\n if (first) return first;\n throw new Error(\"render() produced no widgets: ensure the element renders visible content\");\n};\n\nconst resolveResultContainer = (\n resolved: ResolvedContainer,\n container: RenderOptions[\"container\"],\n baseElement: Container,\n): Gtk.Widget => {\n if (resolved.window) return resolved.window;\n if (container instanceof Gtk.Widget) return container;\n return firstToplevelWidget(baseElement);\n};\n\nconst renderErrorHandlers = <Q extends QueryMap>(options: RenderOptions<Q> | undefined) => ({\n onUncaughtError: handleError,\n onCaughtError: (error: unknown, errorInfo: ErrorInfo): void => {\n handleError(error);\n options?.onCaughtError?.(error, errorInfo);\n },\n onRecoverableError: (error: unknown, errorInfo: ErrorInfo): void => {\n options?.onRecoverableError?.(error, errorInfo);\n },\n});\n\nconst applyEnableAnimations = (enabled: boolean): void => {\n const settings = Gtk.Settings.getDefault();\n if (settings) {\n settings.gtkEnableAnimations = enabled;\n }\n};\n\n/**\n * Renders a React element into a GTK4 widget tree and returns queries\n * scoped to it along with controls for rerendering and unmounting. When no\n * container is supplied, a harness window is created and presented.\n *\n * @param element The React element to render.\n * @param options Optional container, wrapper, custom queries, and other render settings.\n * @returns A render result with bound queries, debug helpers, and lifecycle controls.\n */\nexport const render = async <Q extends QueryMap = Record<never, never>>(\n element: ReactNode,\n options?: RenderOptions<Q>,\n): Promise<RenderResult<Q>> => {\n installErrorHandler();\n\n applyEnableAnimations(options?.animations === true);\n\n const baseElement: Container = options?.baseElement ?? TOPLEVELS;\n const Wrapper = options?.wrapper;\n\n const resolved = resolveContainer(options?.container);\n const root = createReconcilerRoot({\n containerInfo: resolved.containerInfo,\n ...renderErrorHandlers(options),\n });\n const active: ActiveRender = { root, window: resolved.window };\n activeRenders.add(active);\n\n addToCleanupQueue(disposeAllActiveRenders);\n addToCleanupQueue(clearScreen);\n addToCleanupQueue(resetClipboard);\n\n const wrap = (node: ReactNode): ReactNode => {\n const wrapped = Wrapper ? <Wrapper>{node}</Wrapper> : node;\n return options?.reactStrictMode ? <StrictMode>{wrapped}</StrictMode> : wrapped;\n };\n\n await update(wrap(element), root);\n resolved.window?.present();\n await flushLayout(resolved.window);\n\n const container = resolveResultContainer(resolved, options?.container, baseElement);\n\n const result: RenderResult<Q> = {\n ...within(baseElement, options?.queries),\n container,\n baseElement,\n unmount: async () => {\n await disposeActiveRender(active);\n },\n rerender: async (newElement: ReactNode) => {\n await update(wrap(newElement), root);\n await flushLayout(resolved.window);\n },\n debug: (element: Container | Container[] = baseElement, debugOptions?: PrettyWidgetOptions) => {\n logWidget(element, debugOptions);\n },\n logRoles: () => {\n logRoles(baseElement);\n },\n screenshot: (selector?: WindowSelector, screenshotOptions?: ScreenshotOptions) =>\n captureAndSaveScreenshot(selector, screenshotOptions),\n };\n\n setScreen(result);\n\n return result;\n};\n\n/**\n * Unmounts every active render and runs all registered cleanup callbacks,\n * resetting the screen and clipboard. Called automatically after each test.\n */\nexport const cleanup = async (): Promise<void> => {\n await runCleanup();\n};\n"]}
@@ -1,67 +1,32 @@
1
- import * as Gtk from "@gtkx/ffi/gtk";
1
+ import * as Gtk from "@gtkx/gi/gtk";
2
2
  import { type Container } from "./traversal.js";
3
3
  /**
4
- * Information about a widget and its accessible name.
5
- */
6
- export type RoleInfo = {
7
- widget: Gtk.Widget;
8
- name: string | null;
9
- };
10
- /**
11
- * Formats a GTK accessible role to a lowercase string.
4
+ * Converts an accessible role enum value into its lowercase name, falling back
5
+ * to the numeric value when the role is unknown.
12
6
  *
13
- * @param role - The GTK accessible role
14
- * @returns Lowercase role name (e.g., "button", "checkbox")
7
+ * @param role The accessible role to format.
15
8
  */
16
- export declare const formatRole: (role: Gtk.AccessibleRole | undefined) => string;
9
+ export declare const formatRole: (role: Gtk.AccessibleRole) => string;
10
+ export declare const formatRoleList: (roles: Iterable<Gtk.AccessibleRole>) => string;
17
11
  /**
18
- * Collects all accessible roles and their widgets from a container.
19
- *
20
- * Returns a Map where keys are role names (lowercase) and values are
21
- * arrays of widgets with that role, including their accessible names.
22
- *
23
- * @param container - The container to scan for roles
24
- * @returns Map of role names to arrays of RoleInfo
12
+ * Groups every widget in a container's tree by its accessible role name.
25
13
  *
26
- * @example
27
- * ```tsx
28
- * import { getRoles } from "@gtkx/testing";
29
- *
30
- * const roles = getRoles(container);
31
- * // Map {
32
- * // "button" => [{ widget: ..., name: "Submit" }, { widget: ..., name: "Cancel" }],
33
- * // "checkbox" => [{ widget: ..., name: "Remember me" }]
34
- * // }
35
- * ```
14
+ * @param container The scope to traverse.
15
+ * @returns A map from role name to the widgets that have that role.
36
16
  */
37
- export declare const getRoles: (container: Container) => Map<string, RoleInfo[]>;
17
+ export declare const getRoles: (container: Container) => Map<string, Gtk.Widget[]>;
38
18
  /**
39
- * Formats roles into a readable string for error messages.
19
+ * Formats the accessible roles in a container's tree as a readable string,
20
+ * listing each role together with its widgets and their accessible names.
40
21
  *
41
- * @param container - The container to format roles for
42
- * @returns Formatted string showing all roles and their accessible names
22
+ * @param container The scope to inspect.
43
23
  */
44
24
  export declare const prettyRoles: (container: Container) => string;
45
25
  /**
46
- * Logs all accessible roles in a container to the console.
47
- *
48
- * Useful for debugging test failures and discovering available roles.
49
- *
50
- * @param container - The container to log roles for
51
- *
52
- * @example
53
- * ```tsx
54
- * import { render, logRoles } from "@gtkx/testing";
26
+ * Prints the accessible roles in a container's tree to the console using
27
+ * {@link prettyRoles}.
55
28
  *
56
- * const { container } = await render(<MyComponent />);
57
- * logRoles(container);
58
- * // Console output:
59
- * // button:
60
- * // Name "Submit": <GtkButton role="button">Submit</GtkButton>
61
- * // Name "Cancel": <GtkButton role="button">Cancel</GtkButton>
62
- * // checkbox:
63
- * // Name "Remember me": <GtkCheckButton role="checkbox">Remember me</GtkCheckButton>
64
- * ```
29
+ * @param container The scope to inspect.
65
30
  */
66
31
  export declare const logRoles: (container: Container) => void;
67
32
  //# sourceMappingURL=role-helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"role-helpers.d.ts","sourceRoot":"","sources":["../src/role-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,KAAK,SAAS,EAAY,MAAM,gBAAgB,CAAC;AAG1D;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG;IACnB,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,UAAU,GAAI,MAAM,GAAG,CAAC,cAAc,GAAG,SAAS,KAAG,MAKjE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,QAAQ,GAAI,WAAW,SAAS,KAAG,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,CAoBrE,CAAC;AASF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,WAAW,SAAS,KAAG,MAoBlD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,QAAQ,GAAI,WAAW,SAAS,KAAG,IAE/C,CAAC"}
1
+ {"version":3,"file":"role-helpers.d.ts","sourceRoot":"","sources":["../src/role-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AAEpC,OAAO,EAAE,KAAK,SAAS,EAAY,MAAM,gBAAgB,CAAC;AAY1D;;;;;GAKG;AACH,eAAO,MAAM,UAAU,SAAU,GAAG,CAAC,cAAc,KAAG,MAIrD,CAAC;AAEF,eAAO,MAAM,cAAc,UAAW,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,KAAG,MAWpE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,cAAe,SAAS,KAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAevE,CAAC;AASF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,cAAe,SAAS,KAAG,MAoBlD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,cAAe,SAAS,KAAG,IAE/C,CAAC"}
@@ -1,70 +1,66 @@
1
- import * as Gtk from "@gtkx/ffi/gtk";
1
+ import * as Gtk from "@gtkx/gi/gtk";
2
+ import { sortStringsBy } from "@gtkx/utils";
2
3
  import { traverse } from "./traversal.js";
3
- import { getWidgetAccessibleName } from "./widget-text.js";
4
+ import { getWidgetAccessibleName } from "./widget-accessible-properties.js";
5
+ const enumNamesByValue = (enumObject) => new Map(Object.entries(enumObject)
6
+ .filter((entry) => typeof entry[1] === "number")
7
+ .map(([name, value]) => [value, name]));
8
+ const ROLE_NAMES_BY_VALUE = enumNamesByValue(Gtk.AccessibleRole);
4
9
  /**
5
- * Formats a GTK accessible role to a lowercase string.
10
+ * Converts an accessible role enum value into its lowercase name, falling back
11
+ * to the numeric value when the role is unknown.
6
12
  *
7
- * @param role - The GTK accessible role
8
- * @returns Lowercase role name (e.g., "button", "checkbox")
13
+ * @param role The accessible role to format.
9
14
  */
10
15
  export const formatRole = (role) => {
11
- if (role === undefined)
12
- return "unknown";
13
- const name = Gtk.AccessibleRole[role];
16
+ const name = ROLE_NAMES_BY_VALUE.get(role);
14
17
  if (!name)
15
18
  return String(role);
16
19
  return name.toLowerCase();
17
20
  };
21
+ export const formatRoleList = (roles) => {
22
+ const names = [...roles].map((role) => formatRole(role).toUpperCase());
23
+ if (names.length <= 1) {
24
+ return names.join("");
25
+ }
26
+ if (names.length === 2) {
27
+ return `${names[0]} or ${names[1]}`;
28
+ }
29
+ const head = names.slice(0, -1);
30
+ const last = names[names.length - 1];
31
+ return `${head.join(", ")}, or ${last}`;
32
+ };
18
33
  /**
19
- * Collects all accessible roles and their widgets from a container.
20
- *
21
- * Returns a Map where keys are role names (lowercase) and values are
22
- * arrays of widgets with that role, including their accessible names.
23
- *
24
- * @param container - The container to scan for roles
25
- * @returns Map of role names to arrays of RoleInfo
34
+ * Groups every widget in a container's tree by its accessible role name.
26
35
  *
27
- * @example
28
- * ```tsx
29
- * import { getRoles } from "@gtkx/testing";
30
- *
31
- * const roles = getRoles(container);
32
- * // Map {
33
- * // "button" => [{ widget: ..., name: "Submit" }, { widget: ..., name: "Cancel" }],
34
- * // "checkbox" => [{ widget: ..., name: "Remember me" }]
35
- * // }
36
- * ```
36
+ * @param container The scope to traverse.
37
+ * @returns A map from role name to the widgets that have that role.
37
38
  */
38
39
  export const getRoles = (container) => {
39
40
  const roles = new Map();
40
41
  for (const widget of traverse(container)) {
41
- const role = widget.getAccessibleRole?.();
42
- if (role === undefined)
43
- continue;
44
- const roleName = formatRole(role);
45
- const name = getWidgetAccessibleName(widget);
46
- const info = { widget, name };
42
+ const roleName = formatRole(widget.getAccessibleRole());
47
43
  const existing = roles.get(roleName);
48
44
  if (existing) {
49
- existing.push(info);
45
+ existing.push(widget);
50
46
  }
51
47
  else {
52
- roles.set(roleName, [info]);
48
+ roles.set(roleName, [widget]);
53
49
  }
54
50
  }
55
51
  return roles;
56
52
  };
57
53
  const formatWidgetPreview = (widget, name) => {
58
54
  const tagName = widget.constructor.name;
59
- const roleAttr = formatRole(widget.getAccessibleRole?.());
55
+ const roleAttr = formatRole(widget.getAccessibleRole());
60
56
  const nameDisplay = name ? `Name "${name}"` : 'Name ""';
61
57
  return `${nameDisplay}: <${tagName} role="${roleAttr}">${name ?? ""}</${tagName}>`;
62
58
  };
63
59
  /**
64
- * Formats roles into a readable string for error messages.
60
+ * Formats the accessible roles in a container's tree as a readable string,
61
+ * listing each role together with its widgets and their accessible names.
65
62
  *
66
- * @param container - The container to format roles for
67
- * @returns Formatted string showing all roles and their accessible names
63
+ * @param container The scope to inspect.
68
64
  */
69
65
  export const prettyRoles = (container) => {
70
66
  const roles = getRoles(container);
@@ -72,36 +68,21 @@ export const prettyRoles = (container) => {
72
68
  return "No accessible roles found in the widget tree.";
73
69
  }
74
70
  const lines = [];
75
- const sortedRoles = [...roles.entries()].sort(([a], [b]) => a.localeCompare(b));
71
+ const sortedRoles = sortStringsBy([...roles.entries()], ([roleName]) => roleName);
76
72
  for (const [roleName, widgets] of sortedRoles) {
77
73
  lines.push(`${roleName}:`);
78
- for (const { widget, name } of widgets) {
79
- lines.push(` ${formatWidgetPreview(widget, name)}`);
74
+ for (const widget of widgets) {
75
+ lines.push(` ${formatWidgetPreview(widget, getWidgetAccessibleName(widget))}`);
80
76
  }
81
77
  lines.push("");
82
78
  }
83
79
  return lines.join("\n").trimEnd();
84
80
  };
85
81
  /**
86
- * Logs all accessible roles in a container to the console.
87
- *
88
- * Useful for debugging test failures and discovering available roles.
89
- *
90
- * @param container - The container to log roles for
91
- *
92
- * @example
93
- * ```tsx
94
- * import { render, logRoles } from "@gtkx/testing";
82
+ * Prints the accessible roles in a container's tree to the console using
83
+ * {@link prettyRoles}.
95
84
  *
96
- * const { container } = await render(<MyComponent />);
97
- * logRoles(container);
98
- * // Console output:
99
- * // button:
100
- * // Name "Submit": <GtkButton role="button">Submit</GtkButton>
101
- * // Name "Cancel": <GtkButton role="button">Cancel</GtkButton>
102
- * // checkbox:
103
- * // Name "Remember me": <GtkCheckButton role="checkbox">Remember me</GtkCheckButton>
104
- * ```
85
+ * @param container The scope to inspect.
105
86
  */
106
87
  export const logRoles = (container) => {
107
88
  console.log(prettyRoles(container));
@@ -1 +1 @@
1
- {"version":3,"file":"role-helpers.js","sourceRoot":"","sources":["../src/role-helpers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"role-helpers.js","sourceRoot":"","sources":["../src/role-helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import * as Gtk from \"@gtkx/gi/gtk\";\nimport { sortStringsBy } from \"@gtkx/utils\";\nimport { type Container, traverse } from \"./traversal.js\";\nimport { getWidgetAccessibleName } from \"./widget-accessible-properties.js\";\n\nconst enumNamesByValue = (enumObject: Record<string, string | number>): Map<number, string> =>\n new Map<number, string>(\n Object.entries(enumObject)\n .filter((entry): entry is [string, number] => typeof entry[1] === \"number\")\n .map(([name, value]) => [value, name]),\n );\n\nconst ROLE_NAMES_BY_VALUE = enumNamesByValue(Gtk.AccessibleRole);\n\n/**\n * Converts an accessible role enum value into its lowercase name, falling back\n * to the numeric value when the role is unknown.\n *\n * @param role The accessible role to format.\n */\nexport const formatRole = (role: Gtk.AccessibleRole): string => {\n const name = ROLE_NAMES_BY_VALUE.get(role);\n if (!name) return String(role);\n return name.toLowerCase();\n};\n\nexport const formatRoleList = (roles: Iterable<Gtk.AccessibleRole>): string => {\n const names = [...roles].map((role) => formatRole(role).toUpperCase());\n if (names.length <= 1) {\n return names.join(\"\");\n }\n if (names.length === 2) {\n return `${names[0]} or ${names[1]}`;\n }\n const head = names.slice(0, -1);\n const last = names[names.length - 1];\n return `${head.join(\", \")}, or ${last}`;\n};\n\n/**\n * Groups every widget in a container's tree by its accessible role name.\n *\n * @param container The scope to traverse.\n * @returns A map from role name to the widgets that have that role.\n */\nexport const getRoles = (container: Container): Map<string, Gtk.Widget[]> => {\n const roles = new Map<string, Gtk.Widget[]>();\n\n for (const widget of traverse(container)) {\n const roleName = formatRole(widget.getAccessibleRole());\n\n const existing = roles.get(roleName);\n if (existing) {\n existing.push(widget);\n } else {\n roles.set(roleName, [widget]);\n }\n }\n\n return roles;\n};\n\nconst formatWidgetPreview = (widget: Gtk.Widget, name: string | null): string => {\n const tagName = widget.constructor.name;\n const roleAttr = formatRole(widget.getAccessibleRole());\n const nameDisplay = name ? `Name \"${name}\"` : 'Name \"\"';\n return `${nameDisplay}: <${tagName} role=\"${roleAttr}\">${name ?? \"\"}</${tagName}>`;\n};\n\n/**\n * Formats the accessible roles in a container's tree as a readable string,\n * listing each role together with its widgets and their accessible names.\n *\n * @param container The scope to inspect.\n */\nexport const prettyRoles = (container: Container): string => {\n const roles = getRoles(container);\n\n if (roles.size === 0) {\n return \"No accessible roles found in the widget tree.\";\n }\n\n const lines: string[] = [];\n\n const sortedRoles = sortStringsBy([...roles.entries()], ([roleName]) => roleName);\n\n for (const [roleName, widgets] of sortedRoles) {\n lines.push(`${roleName}:`);\n for (const widget of widgets) {\n lines.push(` ${formatWidgetPreview(widget, getWidgetAccessibleName(widget))}`);\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\").trimEnd();\n};\n\n/**\n * Prints the accessible roles in a container's tree to the console using\n * {@link prettyRoles}.\n *\n * @param container The scope to inspect.\n */\nexport const logRoles = (container: Container): void => {\n console.log(prettyRoles(container));\n};\n"]}
package/dist/screen.d.ts CHANGED
@@ -1,66 +1,9 @@
1
- import * as Gtk from "@gtkx/ffi/gtk";
2
- import { type ScreenshotOptions } from "./screenshot.js";
3
- import type { ScreenshotResult } from "./types.js";
4
- /** @internal */
5
- export declare const setScreenRoot: (root: Gtk.Application | null) => void;
1
+ import type { RenderResult, Screen } from "./bound-queries.js";
6
2
  /**
7
- * Global query object for accessing rendered components.
8
- *
9
- * Provides the same query methods as render result, but automatically
10
- * uses the most recently rendered application as the container.
11
- *
12
- * @example
13
- * ```tsx
14
- * import { render, screen } from "@gtkx/testing";
15
- *
16
- * test("finds button", async () => {
17
- * await render(<MyComponent />);
18
- * const button = await screen.findByRole(Gtk.AccessibleRole.BUTTON);
19
- * expect(button).toBeDefined();
20
- * });
21
- * ```
22
- *
23
- * @see {@link render} for rendering components
24
- * @see {@link within} for scoped queries
3
+ * Queries and debug utilities bound to the most recent render, scoped to the
4
+ * current toplevel windows. Accessing it before any render throws.
25
5
  */
26
- export declare const screen: {
27
- /** Print the widget tree to console for debugging */
28
- debug: () => void;
29
- /** Log all accessible roles to console for debugging */
30
- logRoles: () => void;
31
- /**
32
- * Capture a screenshot of the application window, saving it to a temporary file and logging the file path.
33
- *
34
- * @param selector - Window selector: index (number), title substring (string), or title pattern (RegExp).
35
- * If omitted, captures the first window.
36
- * @param options - Optional timeout and interval configuration for waiting on widget rendering.
37
- * @returns Screenshot result containing base64-encoded PNG data
38
- * @throws Error if no windows are available or no matching window is found
39
- *
40
- * @example
41
- * ```tsx
42
- * await screen.screenshot(); // First window
43
- * await screen.screenshot(0); // Window at index 0
44
- * await screen.screenshot("Settings"); // Window with title containing "Settings"
45
- * await screen.screenshot(/^My App/); // Window with title matching regex
46
- * ```
47
- */
48
- screenshot: (selector?: number | string | RegExp, options?: ScreenshotOptions) => Promise<ScreenshotResult>;
49
- queryByRole: (role: Gtk.AccessibleRole, options?: import("./types.js").ByRoleOptions) => Gtk.Widget | null;
50
- queryByLabelText: (text: import("./types.js").TextMatch, options?: import("./types.js").TextMatchOptions) => Gtk.Widget | null;
51
- queryByText: (text: import("./types.js").TextMatch, options?: import("./types.js").TextMatchOptions) => Gtk.Widget | null;
52
- queryByName: (name: import("./types.js").TextMatch, options?: import("./types.js").TextMatchOptions) => Gtk.Widget | null;
53
- queryAllByRole: (role: Gtk.AccessibleRole, options?: import("./types.js").ByRoleOptions) => Gtk.Widget[];
54
- queryAllByLabelText: (text: import("./types.js").TextMatch, options?: import("./types.js").TextMatchOptions) => Gtk.Widget[];
55
- queryAllByText: (text: import("./types.js").TextMatch, options?: import("./types.js").TextMatchOptions) => Gtk.Widget[];
56
- queryAllByName: (name: import("./types.js").TextMatch, options?: import("./types.js").TextMatchOptions) => Gtk.Widget[];
57
- findByRole: (role: Gtk.AccessibleRole, options?: import("./types.js").ByRoleOptions) => Promise<Gtk.Widget>;
58
- findByLabelText: (text: import("./types.js").TextMatch, options?: import("./types.js").TextMatchOptions) => Promise<Gtk.Widget>;
59
- findByText: (text: import("./types.js").TextMatch, options?: import("./types.js").TextMatchOptions) => Promise<Gtk.Widget>;
60
- findByName: (name: import("./types.js").TextMatch, options?: import("./types.js").TextMatchOptions) => Promise<Gtk.Widget>;
61
- findAllByRole: (role: Gtk.AccessibleRole, options?: import("./types.js").ByRoleOptions) => Promise<Gtk.Widget[]>;
62
- findAllByLabelText: (text: import("./types.js").TextMatch, options?: import("./types.js").TextMatchOptions) => Promise<Gtk.Widget[]>;
63
- findAllByText: (text: import("./types.js").TextMatch, options?: import("./types.js").TextMatchOptions) => Promise<Gtk.Widget[]>;
64
- findAllByName: (name: import("./types.js").TextMatch, options?: import("./types.js").TextMatchOptions) => Promise<Gtk.Widget[]>;
65
- };
6
+ export declare const screen: Screen;
7
+ export declare const setScreen: (result: RenderResult) => void;
8
+ export declare const clearScreen: () => void;
66
9
  //# sourceMappingURL=screen.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"screen.d.ts","sourceRoot":"","sources":["../src/screen.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,GAAG,MAAM,eAAe,CAAC;AAIrC,OAAO,EAAE,KAAK,iBAAiB,EAAkC,MAAM,iBAAiB,CAAC;AACzF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAqBnD,gBAAgB;AAChB,eAAO,MAAM,aAAa,GAAI,MAAM,GAAG,CAAC,WAAW,GAAG,IAAI,KAAG,IAE5D,CAAC;AAYF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,MAAM;IAEf,qDAAqD;;IAIrD,wDAAwD;;IAIxD;;;;;;;;;;;;;;;;OAgBG;4BAC2B,MAAM,GAAG,MAAM,GAAG,MAAM,YAAY,iBAAiB,KAAG,OAAO,CAAC,gBAAgB,CAAC;mDAS3G,CAAA;oEAG0B,CAAC;+DAI3B,CAAL;+DAGqC,CAAC;sDAIV,CAAC;uEAGpB,CAAJ;kEAQF,CAAC;kEAAmK,CAAC;kDAAyK,CAAC;mEAA4K,CAAC;8DAAoK,CAAC;8DAAmK,CAAC;qDAAkL,CAAC;sEAAgL,CAAC;iEAAwK,CAAC;iEAAuK,CAAC;CAD//C,CAAC"}
1
+ {"version":3,"file":"screen.d.ts","sourceRoot":"","sources":["../src/screen.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAiB/D;;;GAGG;AACH,eAAO,MAAM,MAAM,EAAE,MAEnB,CAAC;AAEH,eAAO,MAAM,SAAS,WAAY,YAAY,KAAG,IAEhD,CAAC;AAEF,eAAO,MAAM,WAAW,QAAO,IAE9B,CAAC"}
package/dist/screen.js CHANGED
@@ -1,114 +1,26 @@
1
- import { existsSync, mkdirSync, writeFileSync } from "node:fs";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
- import * as Gtk from "@gtkx/ffi/gtk";
5
- import { bindQueries } from "./bind-queries.js";
6
- import { prettyWidget } from "./pretty-widget.js";
7
- import { logRoles } from "./role-helpers.js";
8
- import { screenshot as screenshotWidget } from "./screenshot.js";
9
- const getScreenshotDir = () => {
10
- const dir = join(tmpdir(), "gtkx-screenshots");
11
- if (!existsSync(dir)) {
12
- mkdirSync(dir, { recursive: true });
13
- }
14
- return dir;
1
+ const NO_RENDER_MESSAGE = "No render has been performed: call render() before using screen queries";
2
+ const throwNoRender = () => {
3
+ throw new Error(NO_RENDER_MESSAGE);
15
4
  };
16
- const saveAndLogScreenshot = (result) => {
17
- const dir = getScreenshotDir();
18
- const filename = `${Date.now()}-screenshot.png`;
19
- const filepath = join(dir, filename);
20
- const buffer = Buffer.from(result.data, "base64");
21
- writeFileSync(filepath, buffer);
22
- console.log(`Screenshot saved: file://${filepath}`);
23
- };
24
- let currentRoot = null;
25
- /** @internal */
26
- export const setScreenRoot = (root) => {
27
- currentRoot = root;
28
- };
29
- const getRoot = () => {
30
- if (!currentRoot) {
31
- throw new Error("No render has been performed: call render() before using screen queries");
32
- }
33
- return currentRoot;
34
- };
35
- const boundQueries = bindQueries(getRoot);
5
+ const defaultScreen = new Proxy({}, {
6
+ get: (_target, property) => {
7
+ if (property === "baseElement" || property === "container")
8
+ return throwNoRender();
9
+ return throwNoRender;
10
+ },
11
+ });
12
+ let activeScreen = defaultScreen;
36
13
  /**
37
- * Global query object for accessing rendered components.
38
- *
39
- * Provides the same query methods as render result, but automatically
40
- * uses the most recently rendered application as the container.
41
- *
42
- * @example
43
- * ```tsx
44
- * import { render, screen } from "@gtkx/testing";
45
- *
46
- * test("finds button", async () => {
47
- * await render(<MyComponent />);
48
- * const button = await screen.findByRole(Gtk.AccessibleRole.BUTTON);
49
- * expect(button).toBeDefined();
50
- * });
51
- * ```
52
- *
53
- * @see {@link render} for rendering components
54
- * @see {@link within} for scoped queries
14
+ * Queries and debug utilities bound to the most recent render, scoped to the
15
+ * current toplevel windows. Accessing it before any render throws.
55
16
  */
56
- export const screen = {
57
- ...boundQueries,
58
- /** Print the widget tree to console for debugging */
59
- debug: () => {
60
- console.log(prettyWidget(getRoot()));
61
- },
62
- /** Log all accessible roles to console for debugging */
63
- logRoles: () => {
64
- logRoles(getRoot());
65
- },
66
- /**
67
- * Capture a screenshot of the application window, saving it to a temporary file and logging the file path.
68
- *
69
- * @param selector - Window selector: index (number), title substring (string), or title pattern (RegExp).
70
- * If omitted, captures the first window.
71
- * @param options - Optional timeout and interval configuration for waiting on widget rendering.
72
- * @returns Screenshot result containing base64-encoded PNG data
73
- * @throws Error if no windows are available or no matching window is found
74
- *
75
- * @example
76
- * ```tsx
77
- * await screen.screenshot(); // First window
78
- * await screen.screenshot(0); // Window at index 0
79
- * await screen.screenshot("Settings"); // Window with title containing "Settings"
80
- * await screen.screenshot(/^My App/); // Window with title matching regex
81
- * ```
82
- */
83
- screenshot: async (selector, options) => {
84
- const windows = Gtk.Window.listToplevels();
85
- if (windows.length === 0) {
86
- throw new Error("No windows available for screenshot");
87
- }
88
- let targetWindow;
89
- if (selector === undefined) {
90
- targetWindow = windows[0];
91
- }
92
- else if (typeof selector === "number") {
93
- targetWindow = windows[selector];
94
- if (!targetWindow) {
95
- throw new Error(`Window at index ${selector} not found`);
96
- }
97
- }
98
- else {
99
- const isRegex = selector instanceof RegExp;
100
- targetWindow = windows.find((w) => {
101
- const title = w.getTitle() ?? "";
102
- return isRegex ? selector.test(title) : title.includes(selector);
103
- });
104
- if (!targetWindow) {
105
- const pattern = isRegex ? selector.toString() : `"${selector}"`;
106
- throw new Error(`No window found with title matching ${pattern}`);
107
- }
108
- }
109
- const result = await screenshotWidget(targetWindow, options);
110
- saveAndLogScreenshot(result);
111
- return result;
112
- },
17
+ export const screen = new Proxy({}, {
18
+ get: (_target, property) => Reflect.get(activeScreen, property),
19
+ });
20
+ export const setScreen = (result) => {
21
+ activeScreen = result;
22
+ };
23
+ export const clearScreen = () => {
24
+ activeScreen = defaultScreen;
113
25
  };
114
26
  //# sourceMappingURL=screen.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"screen.js","sourceRoot":"","sources":["../src/screen.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"screen.js","sourceRoot":"","sources":["../src/screen.ts"],"names":[],"mappings":"AAEA,MAAM,iBAAiB,GAAG,yEAAyE,CAAC;AAEpG,MAAM,aAAa,GAAG,GAAU,EAAE;IAC9B,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;AACvC,CAAC,CAAC;AAEF,MAAM,aAAa,GAAiB,IAAI,KAAK,CAAC,EAAkB,EAAE;IAC9D,GAAG,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE;QACvB,IAAI,QAAQ,KAAK,aAAa,IAAI,QAAQ,KAAK,WAAW;YAAE,OAAO,aAAa,EAAE,CAAC;QACnF,OAAO,aAAa,CAAC;IACzB,CAAC;CACJ,CAAC,CAAC;AAEH,IAAI,YAAY,GAAiB,aAAa,CAAC;AAE/C;;;GAGG;AACH,MAAM,CAAC,MAAM,MAAM,GAAW,IAAI,KAAK,CAAC,EAAY,EAAE;IAClD,GAAG,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,QAAQ,CAAC;CAClE,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,MAAoB,EAAQ,EAAE;IACpD,YAAY,GAAG,MAAM,CAAC;AAC1B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,GAAS,EAAE;IAClC,YAAY,GAAG,aAAa,CAAC;AACjC,CAAC,CAAC","sourcesContent":["import type { RenderResult, Screen } from \"./bound-queries.js\";\n\nconst NO_RENDER_MESSAGE = \"No render has been performed: call render() before using screen queries\";\n\nconst throwNoRender = (): never => {\n throw new Error(NO_RENDER_MESSAGE);\n};\n\nconst defaultScreen: RenderResult = new Proxy({} as RenderResult, {\n get: (_target, property) => {\n if (property === \"baseElement\" || property === \"container\") return throwNoRender();\n return throwNoRender;\n },\n});\n\nlet activeScreen: RenderResult = defaultScreen;\n\n/**\n * Queries and debug utilities bound to the most recent render, scoped to the\n * current toplevel windows. Accessing it before any render throws.\n */\nexport const screen: Screen = new Proxy({} as Screen, {\n get: (_target, property) => Reflect.get(activeScreen, property),\n});\n\nexport const setScreen = (result: RenderResult): void => {\n activeScreen = result;\n};\n\nexport const clearScreen = (): void => {\n activeScreen = defaultScreen;\n};\n"]}
@@ -1,30 +1,27 @@
1
- import * as Gtk from "@gtkx/ffi/gtk";
2
- import type { ScreenshotResult, WaitForOptions } from "./types.js";
1
+ import * as Gtk from "@gtkx/gi/gtk";
2
+ import type { ScreenshotOptions, ScreenshotResult, WindowSelector } from "./types.js";
3
3
  /**
4
- * Options for capturing widget screenshots.
4
+ * Captures a PNG snapshot of a widget, retrying until it has a paintable size.
5
+ *
6
+ * @param widget The widget to render to an image.
7
+ * @param options Optional scale, timeout, and retry interval.
8
+ * @returns The base64-encoded PNG data along with its mime type and dimensions.
5
9
  */
6
- export type ScreenshotOptions = Pick<WaitForOptions, "timeout" | "interval">;
10
+ export declare const screenshot: (widget: Gtk.Widget, options?: ScreenshotOptions) => Promise<ScreenshotResult>;
7
11
  /**
8
- * Captures a screenshot of a GTK widget as a PNG image.
9
- *
10
- * This function will retry multiple times if the widget hasn't finished
11
- * rendering, waiting for GTK to complete its paint cycle.
12
- *
13
- * @param widget - The widget to capture (typically a Window)
14
- * @param options - Optional timeout and interval configuration
15
- * @returns Screenshot result containing base64-encoded PNG data and dimensions
16
- * @throws Error if widget has no size, is not realized, or rendering fails after timeout
12
+ * Prints a clickable file URL for a saved screenshot to the console.
17
13
  *
18
- * @example
19
- * ```tsx
20
- * import { render, screenshot } from "@gtkx/testing";
21
- * import * as Gtk from "@gtkx/ffi/gtk";
14
+ * @param filepath Absolute path of the saved screenshot file.
15
+ */
16
+ export declare const logScreenshotPath: (filepath: string) => void;
17
+ /**
18
+ * Captures a screenshot of a toplevel window, writes it to a temporary file,
19
+ * logs its path, and returns the image data.
22
20
  *
23
- * const { container } = await render(<MyApp />);
24
- * const window = container.getWindows()[0];
25
- * const result = await screenshot(window);
26
- * console.log(result.mimeType); // "image/png"
27
- * ```
21
+ * @param selector Chooses the window by index, title substring, or regular
22
+ * expression; defaults to the first toplevel.
23
+ * @param options Optional scale, timeout, and retry interval.
24
+ * @returns The base64-encoded PNG data along with its mime type and dimensions.
28
25
  */
29
- export declare const screenshot: (widget: Gtk.Widget, options?: ScreenshotOptions) => Promise<ScreenshotResult>;
26
+ export declare const captureAndSaveScreenshot: (selector?: WindowSelector, options?: ScreenshotOptions) => Promise<ScreenshotResult>;
30
27
  //# sourceMappingURL=screenshot.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../src/screenshot.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,GAAG,MAAM,eAAe,CAAC;AAErC,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAwDnE;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,cAAc,EAAE,SAAS,GAAG,UAAU,CAAC,CAAC;AAE7E;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,UAAU,GAAU,QAAQ,GAAG,CAAC,MAAM,EAAE,UAAU,iBAAiB,KAAG,OAAO,CAAC,gBAAgB,CAiB1G,CAAC"}
1
+ {"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../src/screenshot.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AACpC,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAuDtF;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,WAAkB,GAAG,CAAC,MAAM,YAAY,iBAAiB,KAAG,OAAO,CAAC,gBAAgB,CAW1G,CAAC;AAiDF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,aAAc,MAAM,KAAG,IAEpD,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,cACtB,cAAc,YACf,iBAAiB,KAC5B,OAAO,CAAC,gBAAgB,CAK1B,CAAC"}