@gtkx/testing 1.1.0 → 1.2.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.
@@ -26,7 +26,7 @@ type BuiltQueries<Args extends unknown[]> = [
26
26
  * @param queryAllBy Finds every widget the family matches.
27
27
  * @param getMultipleError Builds the error thrown when a single-match variant finds more than one widget.
28
28
  * @param getMissingError Builds the error thrown when a required match is missing.
29
- * @returns The five variants, in the order `[queryBy, getAllBy, getBy, findAllBy, findBy]`.
29
+ * @returns The variants, in the order `[queryBy, getAllBy, getBy, findAllBy, findBy]`.
30
30
  */
31
31
  declare const buildQueries: <Args extends unknown[]>(queryAllBy: QueryAllBy<Args>, getMultipleError: MultipleErrorBuilder<Args>, getMissingError: MissingErrorBuilder<Args>) => BuiltQueries<Args>;
32
32
  export { buildQueries, type BuiltQueries, type MissingErrorBuilder, type MultipleErrorBuilder, type QueryAllBy, };
@@ -97,7 +97,7 @@ const requireSingle = (query, getMissingError) => (container, ...args) => {
97
97
  * @param queryAllBy Finds every widget the family matches.
98
98
  * @param getMultipleError Builds the error thrown when a single-match variant finds more than one widget.
99
99
  * @param getMissingError Builds the error thrown when a required match is missing.
100
- * @returns The five variants, in the order `[queryBy, getAllBy, getBy, findAllBy, findBy]`.
100
+ * @returns The variants, in the order `[queryBy, getAllBy, getBy, findAllBy, findBy]`.
101
101
  */
102
102
  const buildQueries = (queryAllBy, getMultipleError, getMissingError) => {
103
103
  const queryName = getQueryFamily(queryAllBy);
@@ -1 +1 @@
1
- {"version":3,"file":"build-queries.js","sourceRoot":"","sources":["../src/build-queries.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,wCAAwC,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EAAE,iBAAiB,EAAgB,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AA+BxC,MAAM,kBAAkB,GAAG,CAAC,IAAe,EAA8B,EAAE;IACvE,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAEzB,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,YAAY,MAAM,CAAC,EAAE,CAAC;QAChE,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,OAAO,SAAS,CAAC;AACrB,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,CAAC,IAAe,EAAuB,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;AACzG,MAAM,cAAc,GAAG,CAAC,UAA4B,EAAU,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;AAE5G,MAAM,oBAAoB,GAAG,CAAC,OAM7B,EAAQ,EAAE;IACP,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC;IAExE,IAAI,CAAC,CAAC,aAAa,IAAI,SAAS,EAAE,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACnD,OAAO;IACX,CAAC;IAED,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAErD,IAAI,UAAU,IAAI,UAAU,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACnD,MAAM,eAAe,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,SAAS,CAAC,CAAC;IAC5D,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CACxB,KAAsB,EACtB,SAAoB,EACpB,IAAU,EACV,QAAe,EACV,EAAE;IACP,IAAI,CAAC;QACD,KAAK,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,CAAC;IAC9B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YACzB,OAAO,KAAK,CAAC;QACjB,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AACpB,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAChB,KAAsB,EACtB,SAAoB,EACpB,IAAU,EACI,EAAE;IAChB,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,kBAAkB,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IAExE,OAAO;QACH,eAAe,EAAE,IAAI,KAAK,CAAC,qBAAqB,CAAC;QACjD,SAAS,EAAE,SAAS,IAAI,CAAC,CAAC,QAAe,EAAE,EAAE,CAAC,mBAAmB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QACpG,OAAO;QACP,QAAQ;KACX,CAAC;AACN,CAAC,CAAC;AAEF,MAAM,UAAU,GACZ,CACI,QAA0B,EAC1B,gBAA4C,EAC3B,EAAE,CACnB,CAAC,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE;IACnB,MAAM,OAAO,GAAG,QAAQ,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,CAAC;IAE7C,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,gBAAgB,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;IACxD,CAAC;IAED,OAAO,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AAC9B,CAAC,CAAC;AAEV,MAAM,UAAU,GACZ,CACI,QAA0B,EAC1B,eAA0C,EAC1B,EAAE,CAClB,CAAC,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE;IACnB,MAAM,OAAO,GAAG,QAAQ,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,CAAC;IAE7C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,eAAe,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,OAAO,CAAC;AACnB,CAAC,CAAC;AAEV,MAAM,wBAAwB,GAC1B,CAAyB,KAAwB,EAAE,SAAiB,EAAE,OAAgB,EAAqB,EAAE,CACzG,CAAC,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE;IACnB,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,CAAC;IAExC,IAAI,KAAK,EAAE,CAAC;QACR,oBAAoB,CAAC;YACjB,SAAS;YACT,KAAK;YACL,SAAS;YACT,OAAO;YACP,aAAa,EAAE,oBAAoB,CAAC,IAAI,CAAC;SAC5C,CAAC,CAAC;IACP,CAAC;IAED,OAAO,KAAK,CAAC;AACjB,CAAC,CAAC;AAEV,MAAM,qBAAqB,GACvB,CAAyB,KAAuB,EAAE,SAAiB,EAAE,OAAgB,EAAoB,EAAE,CACvG,CAAC,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE;IACnB,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,CAAC;IAC1C,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC;IAExB,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACtB,oBAAoB,CAAC;YACjB,SAAS;YACT,KAAK,EAAE,KAAK;YACZ,SAAS;YACT,OAAO;YACP,aAAa,EAAE,oBAAoB,CAAC,IAAI,CAAC;SAC5C,CAAC,CAAC;IACP,CAAC;IAED,OAAO,OAAO,CAAC;AACnB,CAAC,CAAC;AAEV,MAAM,aAAa,GACf,CAAyB,KAAwB,EAAE,eAA0C,EAAE,EAAE,CAC7F,CAAC,SAAoB,EAAE,GAAG,IAAU,EAAc,EAAE;IAChD,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,CAAC;IAExC,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACjB,MAAM,eAAe,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,KAAK,CAAC;AACjB,CAAC,CAAC;AAEV;;;;;;;;;GASG;AACH,MAAM,YAAY,GAAG,CACjB,UAA4B,EAC5B,gBAA4C,EAC5C,eAA0C,EACxB,EAAE;IACpB,MAAM,SAAS,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,UAAU,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;IACzD,MAAM,KAAK,GAAG,aAAa,CAAC,UAAU,CAAC,QAAQ,EAAE,gBAAgB,CAAC,EAAE,eAAe,CAAC,CAAC;IAErF,MAAM,qBAAqB,GAAG,wBAAwB,CAClD,UAAU,CAAC,UAAU,EAAE,gBAAgB,CAAC,EACxC,SAAS,EACT,OAAO,CACV,CAAC;IAEF,MAAM,sBAAsB,GAAG,qBAAqB,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IAEpF,MAAM,mBAAmB,GAAwD,CAAC,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE;QACpG,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,CAAC;QAExC,oBAAoB,CAAC;YACjB,SAAS;YACT,KAAK;YACL,SAAS;YACT,OAAO,EAAE,KAAK;YACd,aAAa,EAAE,oBAAoB,CAAC,IAAI,CAAC;SAC5C,CAAC,CAAC;QAEH,OAAO,KAAK,CAAC;IACjB,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,CAAC,SAAoB,EAAE,GAAG,IAAU,EAAyB,EAAE,CAC7E,OAAO,CACH,GAAG,EAAE,CAAC,wCAAwC,CAAC,GAAG,EAAE,CAAC,sBAAsB,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,CAAC,EAChG,WAAW,CAAC,sBAAsB,EAAE,SAAS,EAAE,IAAI,CAAC,CACvD,CAAC;IAEN,MAAM,MAAM,GAAG,CAAC,SAAoB,EAAE,GAAG,IAAU,EAAuB,EAAE,CACxE,OAAO,CACH,GAAG,EAAE,CAAC,wCAAwC,CAAC,GAAG,EAAE,CAAC,mBAAmB,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,CAAC,EAC7F,WAAW,CAAC,mBAAmB,EAAE,SAAS,EAAE,IAAI,CAAC,CACpD,CAAC;IAEN,OAAO,CAAC,qBAAqB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;AACnG,CAAC,CAAC;AAEF,OAAO,EACH,YAAY,GAKf,CAAC","sourcesContent":["import type * as Gtk from \"@gtkx/gi/gtk\";\nimport type { Container } from \"./traversal.js\";\nimport type { MatcherOptions, WaitForOptions } from \"./types.js\";\nimport { getConfig } from \"./config.js\";\nimport { runWithExpensiveErrorDiagnosticsDisabled, suggestionError } from \"./errors.js\";\nimport { getSuggestedQuery, type Variant } from \"./suggestions.js\";\nimport { waitFor } from \"./wait-for.js\";\n\n/**\n * The `queryAllBy` function a query family is built from, taking the scope to search followed by the\n * family's own matcher arguments. Its name determines the family name, so `queryAllByTestId` builds\n * a `TestId` family.\n */\ntype QueryAllBy<Args extends unknown[]> = (container: Container, ...args: Args) => Gtk.Widget[];\n\n/** Builds the error thrown when a single-match query finds more than one widget. */\ntype MultipleErrorBuilder<Args extends unknown[]> = (\n container: Container,\n matches: Gtk.Widget[],\n ...args: Args\n) => Error;\n\n/** Builds the error thrown when a query that requires a match finds none. */\ntype MissingErrorBuilder<Args extends unknown[]> = (container: Container, ...args: Args) => Error;\n\n/** The variants derived from one `queryAllBy` function, in the order DOM Testing Library returns them. */\ntype BuiltQueries<Args extends unknown[]> = [\n queryBy: (container: Container, ...args: Args) => Gtk.Widget | null,\n getAllBy: QueryAllBy<Args>,\n getBy: (container: Container, ...args: Args) => Gtk.Widget,\n findAllBy: (container: Container, ...args: Args) => Promise<Gtk.Widget[]>,\n findBy: (container: Container, ...args: Args) => Promise<Gtk.Widget>,\n];\n\ntype FindQuery<Args extends unknown[]> = (container: Container, ...args: Args) => unknown;\ntype SingleQuery<Args extends unknown[]> = (container: Container, ...args: Args) => Gtk.Widget | null;\n\nconst getTrailingOptions = (args: unknown[]): MatcherOptions | undefined => {\n const last = args.at(-1);\n\n if (last && typeof last === \"object\" && !(last instanceof RegExp)) {\n return last;\n }\n\n return undefined;\n};\n\nconst extractShouldSuggest = (args: unknown[]): boolean | undefined => getTrailingOptions(args)?.suggest;\nconst getQueryFamily = (queryAllBy: { name: string }): string => queryAllBy.name.replace(/^queryAllBy/, \"\");\n\nconst maybeThrowSuggestion = (options: {\n container: Container;\n match: Gtk.Widget;\n queryName: string;\n variant: Variant;\n shouldSuggest: boolean | undefined;\n}): void => {\n const { container, match, queryName, variant, shouldSuggest } = options;\n\n if (!(shouldSuggest ?? getConfig().throwSuggestions)) {\n return;\n }\n\n const suggestion = getSuggestedQuery(match, variant);\n\n if (suggestion && suggestion.queryName !== queryName) {\n throw suggestionError(suggestion.toString(), container);\n }\n};\n\nconst reRunForDiagnostics = <Args extends unknown[]>(\n query: FindQuery<Args>,\n container: Container,\n args: Args,\n fallback: Error,\n): Error => {\n try {\n query(container, ...args);\n } catch (error) {\n if (error instanceof Error) {\n return error;\n }\n }\n\n return fallback;\n};\n\nconst findOptions = <Args extends unknown[]>(\n query: FindQuery<Args>,\n container: Container,\n args: Args,\n): WaitForOptions => {\n const { timeout, interval, onTimeout } = getTrailingOptions(args) ?? {};\n\n return {\n stackTraceError: new Error(\"STACK_TRACE_MESSAGE\"),\n onTimeout: onTimeout ?? ((fallback: Error) => reRunForDiagnostics(query, container, args, fallback)),\n timeout,\n interval,\n };\n};\n\nconst singleFrom =\n <Args extends unknown[]>(\n allQuery: QueryAllBy<Args>,\n getMultipleError: MultipleErrorBuilder<Args>,\n ): SingleQuery<Args> =>\n (container, ...args) => {\n const matches = allQuery(container, ...args);\n\n if (matches.length > 1) {\n throw getMultipleError(container, matches, ...args);\n }\n\n return matches[0] ?? null;\n };\n\nconst allOrThrow =\n <Args extends unknown[]>(\n allQuery: QueryAllBy<Args>,\n getMissingError: MissingErrorBuilder<Args>,\n ): QueryAllBy<Args> =>\n (container, ...args) => {\n const matches = allQuery(container, ...args);\n\n if (matches.length === 0) {\n throw getMissingError(container, ...args);\n }\n\n return matches;\n };\n\nconst wrapSingleWithSuggestion =\n <Args extends unknown[]>(query: SingleQuery<Args>, queryName: string, variant: Variant): SingleQuery<Args> =>\n (container, ...args) => {\n const match = query(container, ...args);\n\n if (match) {\n maybeThrowSuggestion({\n container,\n match,\n queryName,\n variant,\n shouldSuggest: extractShouldSuggest(args),\n });\n }\n\n return match;\n };\n\nconst wrapAllWithSuggestion =\n <Args extends unknown[]>(query: QueryAllBy<Args>, queryName: string, variant: Variant): QueryAllBy<Args> =>\n (container, ...args) => {\n const matches = query(container, ...args);\n const [first] = matches;\n\n if (first !== undefined) {\n maybeThrowSuggestion({\n container,\n match: first,\n queryName,\n variant,\n shouldSuggest: extractShouldSuggest(args),\n });\n }\n\n return matches;\n };\n\nconst requireSingle =\n <Args extends unknown[]>(query: SingleQuery<Args>, getMissingError: MissingErrorBuilder<Args>) =>\n (container: Container, ...args: Args): Gtk.Widget => {\n const match = query(container, ...args);\n\n if (match === null) {\n throw getMissingError(container, ...args);\n }\n\n return match;\n };\n\n/**\n * Derives the `queryBy`, `getAllBy`, `getBy`, `findAllBy`, and `findBy` variants of a query family\n * from the family's `queryAllBy` function, mirroring DOM Testing Library's `buildQueries`. The family\n * name used when suggesting a better query comes from `queryAllBy.name`.\n *\n * @param queryAllBy Finds every widget the family matches.\n * @param getMultipleError Builds the error thrown when a single-match variant finds more than one widget.\n * @param getMissingError Builds the error thrown when a required match is missing.\n * @returns The five variants, in the order `[queryBy, getAllBy, getBy, findAllBy, findBy]`.\n */\nconst buildQueries = <Args extends unknown[]>(\n queryAllBy: QueryAllBy<Args>,\n getMultipleError: MultipleErrorBuilder<Args>,\n getMissingError: MissingErrorBuilder<Args>,\n): BuiltQueries<Args> => {\n const queryName = getQueryFamily(queryAllBy);\n const getAllBy = allOrThrow(queryAllBy, getMissingError);\n const getBy = requireSingle(singleFrom(getAllBy, getMultipleError), getMissingError);\n\n const queryByWithSuggestion = wrapSingleWithSuggestion(\n singleFrom(queryAllBy, getMultipleError),\n queryName,\n \"query\",\n );\n\n const getAllByWithSuggestion = wrapAllWithSuggestion(getAllBy, queryName, \"getAll\");\n\n const getByWithSuggestion: (container: Container, ...args: Args) => Gtk.Widget = (container, ...args) => {\n const match = getBy(container, ...args);\n\n maybeThrowSuggestion({\n container,\n match,\n queryName,\n variant: \"get\",\n shouldSuggest: extractShouldSuggest(args),\n });\n\n return match;\n };\n\n const findAllBy = (container: Container, ...args: Args): Promise<Gtk.Widget[]> =>\n waitFor(\n () => runWithExpensiveErrorDiagnosticsDisabled(() => getAllByWithSuggestion(container, ...args)),\n findOptions(getAllByWithSuggestion, container, args),\n );\n\n const findBy = (container: Container, ...args: Args): Promise<Gtk.Widget> =>\n waitFor(\n () => runWithExpensiveErrorDiagnosticsDisabled(() => getByWithSuggestion(container, ...args)),\n findOptions(getByWithSuggestion, container, args),\n );\n\n return [queryByWithSuggestion, getAllByWithSuggestion, getByWithSuggestion, findAllBy, findBy];\n};\n\nexport {\n buildQueries,\n type BuiltQueries,\n type MissingErrorBuilder,\n type MultipleErrorBuilder,\n type QueryAllBy,\n};\n"]}
1
+ {"version":3,"file":"build-queries.js","sourceRoot":"","sources":["../src/build-queries.ts"],"names":[],"mappings":"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","sourcesContent":["import type * as Gtk from \"@gtkx/gi/gtk\";\nimport type { Container } from \"./traversal.js\";\nimport type { MatcherOptions, WaitForOptions } from \"./types.js\";\nimport { getConfig } from \"./config.js\";\nimport { runWithExpensiveErrorDiagnosticsDisabled, suggestionError } from \"./errors.js\";\nimport { getSuggestedQuery, type Variant } from \"./suggestions.js\";\nimport { waitFor } from \"./wait-for.js\";\n\n/**\n * The `queryAllBy` function a query family is built from, taking the scope to search followed by the\n * family's own matcher arguments. Its name determines the family name, so `queryAllByTestId` builds\n * a `TestId` family.\n */\ntype QueryAllBy<Args extends unknown[]> = (container: Container, ...args: Args) => Gtk.Widget[];\n\n/** Builds the error thrown when a single-match query finds more than one widget. */\ntype MultipleErrorBuilder<Args extends unknown[]> = (\n container: Container,\n matches: Gtk.Widget[],\n ...args: Args\n) => Error;\n\n/** Builds the error thrown when a query that requires a match finds none. */\ntype MissingErrorBuilder<Args extends unknown[]> = (container: Container, ...args: Args) => Error;\n\n/** The variants derived from one `queryAllBy` function, in the order DOM Testing Library returns them. */\ntype BuiltQueries<Args extends unknown[]> = [\n queryBy: (container: Container, ...args: Args) => Gtk.Widget | null,\n getAllBy: QueryAllBy<Args>,\n getBy: (container: Container, ...args: Args) => Gtk.Widget,\n findAllBy: (container: Container, ...args: Args) => Promise<Gtk.Widget[]>,\n findBy: (container: Container, ...args: Args) => Promise<Gtk.Widget>,\n];\n\ntype FindQuery<Args extends unknown[]> = (container: Container, ...args: Args) => unknown;\ntype SingleQuery<Args extends unknown[]> = (container: Container, ...args: Args) => Gtk.Widget | null;\n\nconst getTrailingOptions = (args: unknown[]): MatcherOptions | undefined => {\n const last = args.at(-1);\n\n if (last && typeof last === \"object\" && !(last instanceof RegExp)) {\n return last;\n }\n\n return undefined;\n};\n\nconst extractShouldSuggest = (args: unknown[]): boolean | undefined => getTrailingOptions(args)?.suggest;\nconst getQueryFamily = (queryAllBy: { name: string }): string => queryAllBy.name.replace(/^queryAllBy/, \"\");\n\nconst maybeThrowSuggestion = (options: {\n container: Container;\n match: Gtk.Widget;\n queryName: string;\n variant: Variant;\n shouldSuggest: boolean | undefined;\n}): void => {\n const { container, match, queryName, variant, shouldSuggest } = options;\n\n if (!(shouldSuggest ?? getConfig().throwSuggestions)) {\n return;\n }\n\n const suggestion = getSuggestedQuery(match, variant);\n\n if (suggestion && suggestion.queryName !== queryName) {\n throw suggestionError(suggestion.toString(), container);\n }\n};\n\nconst reRunForDiagnostics = <Args extends unknown[]>(\n query: FindQuery<Args>,\n container: Container,\n args: Args,\n fallback: Error,\n): Error => {\n try {\n query(container, ...args);\n } catch (error) {\n if (error instanceof Error) {\n return error;\n }\n }\n\n return fallback;\n};\n\nconst findOptions = <Args extends unknown[]>(\n query: FindQuery<Args>,\n container: Container,\n args: Args,\n): WaitForOptions => {\n const { timeout, interval, onTimeout } = getTrailingOptions(args) ?? {};\n\n return {\n stackTraceError: new Error(\"STACK_TRACE_MESSAGE\"),\n onTimeout: onTimeout ?? ((fallback: Error) => reRunForDiagnostics(query, container, args, fallback)),\n timeout,\n interval,\n };\n};\n\nconst singleFrom =\n <Args extends unknown[]>(\n allQuery: QueryAllBy<Args>,\n getMultipleError: MultipleErrorBuilder<Args>,\n ): SingleQuery<Args> =>\n (container, ...args) => {\n const matches = allQuery(container, ...args);\n\n if (matches.length > 1) {\n throw getMultipleError(container, matches, ...args);\n }\n\n return matches[0] ?? null;\n };\n\nconst allOrThrow =\n <Args extends unknown[]>(\n allQuery: QueryAllBy<Args>,\n getMissingError: MissingErrorBuilder<Args>,\n ): QueryAllBy<Args> =>\n (container, ...args) => {\n const matches = allQuery(container, ...args);\n\n if (matches.length === 0) {\n throw getMissingError(container, ...args);\n }\n\n return matches;\n };\n\nconst wrapSingleWithSuggestion =\n <Args extends unknown[]>(query: SingleQuery<Args>, queryName: string, variant: Variant): SingleQuery<Args> =>\n (container, ...args) => {\n const match = query(container, ...args);\n\n if (match) {\n maybeThrowSuggestion({\n container,\n match,\n queryName,\n variant,\n shouldSuggest: extractShouldSuggest(args),\n });\n }\n\n return match;\n };\n\nconst wrapAllWithSuggestion =\n <Args extends unknown[]>(query: QueryAllBy<Args>, queryName: string, variant: Variant): QueryAllBy<Args> =>\n (container, ...args) => {\n const matches = query(container, ...args);\n const [first] = matches;\n\n if (first !== undefined) {\n maybeThrowSuggestion({\n container,\n match: first,\n queryName,\n variant,\n shouldSuggest: extractShouldSuggest(args),\n });\n }\n\n return matches;\n };\n\nconst requireSingle =\n <Args extends unknown[]>(query: SingleQuery<Args>, getMissingError: MissingErrorBuilder<Args>) =>\n (container: Container, ...args: Args): Gtk.Widget => {\n const match = query(container, ...args);\n\n if (match === null) {\n throw getMissingError(container, ...args);\n }\n\n return match;\n };\n\n/**\n * Derives the `queryBy`, `getAllBy`, `getBy`, `findAllBy`, and `findBy` variants of a query family\n * from the family's `queryAllBy` function, mirroring DOM Testing Library's `buildQueries`. The family\n * name used when suggesting a better query comes from `queryAllBy.name`.\n *\n * @param queryAllBy Finds every widget the family matches.\n * @param getMultipleError Builds the error thrown when a single-match variant finds more than one widget.\n * @param getMissingError Builds the error thrown when a required match is missing.\n * @returns The variants, in the order `[queryBy, getAllBy, getBy, findAllBy, findBy]`.\n */\nconst buildQueries = <Args extends unknown[]>(\n queryAllBy: QueryAllBy<Args>,\n getMultipleError: MultipleErrorBuilder<Args>,\n getMissingError: MissingErrorBuilder<Args>,\n): BuiltQueries<Args> => {\n const queryName = getQueryFamily(queryAllBy);\n const getAllBy = allOrThrow(queryAllBy, getMissingError);\n const getBy = requireSingle(singleFrom(getAllBy, getMultipleError), getMissingError);\n\n const queryByWithSuggestion = wrapSingleWithSuggestion(\n singleFrom(queryAllBy, getMultipleError),\n queryName,\n \"query\",\n );\n\n const getAllByWithSuggestion = wrapAllWithSuggestion(getAllBy, queryName, \"getAll\");\n\n const getByWithSuggestion: (container: Container, ...args: Args) => Gtk.Widget = (container, ...args) => {\n const match = getBy(container, ...args);\n\n maybeThrowSuggestion({\n container,\n match,\n queryName,\n variant: \"get\",\n shouldSuggest: extractShouldSuggest(args),\n });\n\n return match;\n };\n\n const findAllBy = (container: Container, ...args: Args): Promise<Gtk.Widget[]> =>\n waitFor(\n () => runWithExpensiveErrorDiagnosticsDisabled(() => getAllByWithSuggestion(container, ...args)),\n findOptions(getAllByWithSuggestion, container, args),\n );\n\n const findBy = (container: Container, ...args: Args): Promise<Gtk.Widget> =>\n waitFor(\n () => runWithExpensiveErrorDiagnosticsDisabled(() => getByWithSuggestion(container, ...args)),\n findOptions(getByWithSuggestion, container, args),\n );\n\n return [queryByWithSuggestion, getAllByWithSuggestion, getByWithSuggestion, findAllBy, findBy];\n};\n\nexport {\n buildQueries,\n type BuiltQueries,\n type MissingErrorBuilder,\n type MultipleErrorBuilder,\n type QueryAllBy,\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../src/screenshot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AACpC,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAC;AAC9C,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AACpC,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAsBpE,MAAM,2BAA2B,GAAG,EAAE,CAAC;AACvC,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAElC,MAAM,sBAAsB,GACxB,iGAAiG;IACjG,oGAAoG;IACpG,6CAA6C,CAAC;AAElD,MAAM,iBAAiB,GACnB,qGAAqG,CAAC;AAE1G,MAAM,kBAAkB,GACpB,4FAA4F,CAAC;AAEjG,MAAM,yBAAyB,GAAG,+DAA+D,CAAC;AAElG,MAAM,aAAa,GAAG,CAAC,KAAe,EAAU,EAAE;IAC9C,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACjD,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,MAAkB,EAAU,EAAE,CACvD,YAAY,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,WAAW,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,GAAG;IAChF,WAAW,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC;AAE7C,MAAM,iBAAiB,GAAG,CAAC,MAAkB,EAAiB,EAAE;IAC5D,MAAM,QAAQ,GAAkB,EAAE,CAAC;IAEnC,KAAK,MAAM,UAAU,IAAI,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3C,IAAI,UAAU,YAAY,GAAG,CAAC,OAAO,IAAI,UAAU,CAAC,SAAS,EAAE,EAAE,CAAC;YAC9D,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC9B,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AACpB,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,CAAC,QAAsB,EAAE,MAAkB,EAAE,OAAoB,EAAQ,EAAE;IAC7F,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAC1D,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,SAAS,CAAC,iBAAiB,EAAE,CAAC;IAC5C,MAAM,MAAM,GAAG,SAAS,CAAC,kBAAkB,EAAE,CAAC;IAE9C,IAAI,CAAC,SAAS,IAAI,KAAK,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;QAC1C,OAAO;IACX,CAAC;IAED,QAAQ,CAAC,IAAI,EAAE,CAAC;IAChB,QAAQ,CAAC,SAAS,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACnF,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAC5C,QAAQ,CAAC,OAAO,EAAE,CAAC;AACvB,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,CAAC,QAAsB,EAAE,MAAkB,EAAQ,EAAE;IACxE,KAAK,MAAM,OAAO,IAAI,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC;QAC9C,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,MAAkB,EAAsB,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,UAAU,EAAE,IAAI,IAAI,CAAC;AACxG,MAAM,iBAAiB,GAAG,CAAC,MAAkB,EAAW,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,IAAI,KAAK,CAAC;AAEpG,MAAM,aAAa,GAAG,CAAC,MAAkB,EAAyB,EAAE,CAChE,MAAM,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;AAEhE,MAAM,eAAe,GAAG,CAAC,MAAkB,EAAiB,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,eAAe,EAAE,IAAI,IAAI,CAAC;AAEhH,MAAM,oBAAoB,GAAG,CAAC,MAAkB,EAAU,EAAE,CACxD,GAAG,mBAAmB,CAAC,MAAM,CAAC,kBAAkB,MAAM,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC,GAAG;IACpF,gBAAgB,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;AAEtD,MAAM,YAAY,GAAG,CAAC,MAAkB,EAAQ,EAAE;IAC9C,aAAa,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC,GAAG,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;AACpE,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,MAAkB,EAAc,EAAE;IACvD,YAAY,CAAC,MAAM,CAAC,CAAC;IAErB,OAAO,EAAE,OAAO,EAAE,eAAe,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,CAAC;AAClE,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,CAAC,MAAkB,EAAE,KAAiB,EAAQ,EAAE;IACrE,YAAY,CAAC,MAAM,CAAC,CAAC;IAErB,IAAI,KAAK,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;QACzB,OAAO;IACX,CAAC;IAED,MAAM,OAAO,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAExC,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACnB,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC;QACxB,KAAK,CAAC,SAAS,GAAG,GAAG,EAAE,CAAC;IAC5B,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,CAAC,MAAkB,EAAE,KAAiB,EAAW,EAAE;IACxE,MAAM,OAAO,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAExC,OAAO,OAAO,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;AACjF,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,MAAkB,EAAE,KAAiB,EAAW,EAAE,CACpE,iBAAiB,CAAC,MAAM,CAAC,IAAI,gBAAgB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAEjE,MAAM,qBAAqB,GAAG,CAAC,MAAkB,EAAE,KAAiB,EAAW,EAAE,CAC7E,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,IAAI,qBAAqB,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAErF,MAAM,YAAY,GAAG,CAAC,MAAkB,EAAQ,EAAE;IAC9C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;IAE9B,IAAI,CAAC,IAAI,EAAE,CAAC;QACR,OAAO;IACX,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;IAEhC,IAAI,KAAK,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IAC3C,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,KAAiB,EAAW,EAAE,CACvD,KAAK,CAAC,SAAS,EAAE,IAAI,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,YAAY,GAAG,CAAC,OAAO,CAAC,CAAC;AAEjF,MAAM,gBAAgB,GAAG,CAAC,MAAkB,EAAE,KAAa,EAAE,KAAa,EAAE,MAAc,EAAyB,EAAE;IACjH,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;IACpC,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC7B,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAC5C,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAEjC,OAAO,QAAQ,CAAC,MAAM,EAAE,CAAC;AAC7B,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,MAAkB,EAAE,KAAa,EAAyB,EAAE;IACjF,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;IACpC,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAE7B,KAAK,IAAI,KAAK,GAAG,MAAM,CAAC,aAAa,EAAE,EAAE,KAAK,KAAK,IAAI,EAAE,KAAK,GAAG,KAAK,CAAC,cAAc,EAAE,EAAE,CAAC;QACtF,IAAI,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7B,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAC1C,CAAC;IACL,CAAC;IAED,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAEjC,OAAO,QAAQ,CAAC,MAAM,EAAE,CAAC;AAC7B,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,CAAC,MAAkB,EAAE,KAAa,EAAE,KAAa,EAAE,MAAc,EAAyB,EAAE;IAC9G,MAAM,SAAS,GAAG,gBAAgB,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAEjE,IAAI,SAAS,EAAE,CAAC;QACZ,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,YAAY,CAAC,MAAM,CAAC,CAAC;IAErB,OAAO,gBAAgB,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,eAAe,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAC5F,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,MAAkB,EAAE,IAAoB,EAAE,KAAa,EAAE,MAAc,EAAoB,EAAE;IAC9G,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,aAAa,EAAE,CAAC;IACzC,QAAQ,CAAC,iBAAiB,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;IAEhD,IAAI,CAAC;QACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QACjE,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACvD,MAAM,IAAI,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,OAAO,EAAE,CAAC;QAEhD,IAAI,CAAC,IAAI,EAAE,CAAC;YACR,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAC7D,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,aAAa,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAC/E,CAAC;YAAS,CAAC;QACP,QAAQ,CAAC,SAAS,EAAE,CAAC;IACzB,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,MAAkB,EAAE,KAAa,EAAiB,EAAE;IACzE,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IACtD,MAAM,KAAK,GAAG,SAAS,CAAC,iBAAiB,EAAE,CAAC;IAC5C,MAAM,MAAM,GAAG,SAAS,CAAC,kBAAkB,EAAE,CAAC;IAE9C,IAAI,KAAK,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;IACpD,CAAC;IAED,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAE/D,IAAI,CAAC,UAAU,EAAE,CAAC;QACd,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;IACvD,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC;IAC9C,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC;IAEhD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,CAAC,EAAE,CAAC;AACtG,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,CAAC,MAAkB,EAAE,OAAuB,EAAU,EAAE,CAC3E,OAAO,KAAK,SAAS;IACjB,CAAC,CAAC,0DAA0D,mBAAmB,CAAC,MAAM,CAAC,GAAG;IAC1F,CAAC,CAAC,sCAAsC,mBAAmB,CAAC,MAAM,CAAC,GAAG,CAAC;AAE/E,MAAM,oBAAoB,GAAG,CAAC,MAAkB,EAAU,EAAE,CACxD,GAAG,sBAAsB,KAAK,oBAAoB,CAAC,MAAM,CAAC,GAAG,CAAC;AAElE,MAAM,cAAc,GAAG,CAAC,MAAkB,EAAE,OAAuB,EAAU,EAAE,CAC3E,GAAG,oBAAoB,CAAC,MAAM,CAAC,OAAO,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;AAE5E,MAAM,cAAc,GAAG,CAAC,OAA8B,EAAU,EAAE,CAC9D,OAAO,KAAK,YAAY,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,kBAAkB,CAAC;AAEtE,MAAM,WAAW,GAAG,CAAC,MAAkB,EAAE,KAAmB,EAAU,EAAE,CACpE,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAErG,MAAM,cAAc,GAAG,CAAC,KAAY,EAAE,MAAkB,EAAE,KAAmB,EAAS,EAAE,CACpF,SAAS,EAAE,CAAC,eAAe,CAAC,GAAG,KAAK,CAAC,OAAO,OAAO,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;AAErF,MAAM,cAAc,GAAG,CAAC,MAAkB,EAAE,KAAa,EAAE,KAAmB,EAAkB,EAAE;IAC9F,MAAM,OAAO,GAAG,eAAe,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAE/C,IAAI,OAAO,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QAChC,OAAO,OAAO,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAChC,gBAAgB,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAEtC,IAAI,qBAAqB,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7C,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3D,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;AAC7D,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,MAAwB,EAAE,IAAY,EAAQ,EAAE;IACrE,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;AAC5D,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAC1B,MAAkB,EAClB,KAAa,EACb,OAAsC,EACf,EAAE;IACzB,MAAM,KAAK,GAAiB,EAAE,KAAK,EAAE,eAAe,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAE9E,OAAO,OAAO,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE;QACvD,OAAO,EAAE,OAAO,EAAE,OAAO;QACzB,QAAQ,EAAE,OAAO,EAAE,QAAQ,IAAI,2BAA2B;QAC1D,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC;KAC7D,CAAC,CAAC;AACP,CAAC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,GAAG,KAAK,EAAE,MAAkB,EAAE,OAA2B,EAA6B,EAAE;IACpG,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,IAAI,CAAC,CAAC;IAElC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,mDAAmD,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACxF,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,qBAAqB,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IAEpE,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,IAAI,OAAO,EAAE,IAAI,EAAE,CAAC;QAChB,eAAe,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,CAAC;IAED,OAAO,OAAO,CAAC,MAAM,CAAC;AAC1B,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,GAAe,EAAE;IAClC,MAAM,MAAM,GAAG,cAAc,EAAE,IAAI,eAAe,EAAE,CAAC,CAAC,CAAC,CAAC;IAExD,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC/C,CAAC;IAED,OAAO,MAAM,CAAC;AAClB,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,KAAK,EAAE,OAA2B,EAA6B,EAAE,CACnF,UAAU,CAAC,YAAY,EAAE,EAAE,OAAO,CAAC,CAAC;AAExC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC","sourcesContent":["import * as Gdk from \"@gtkx/gi/gdk\";\nimport * as Graphene from \"@gtkx/gi/graphene\";\nimport * as Gsk from \"@gtkx/gi/gsk\";\nimport * as Gtk from \"@gtkx/gi/gtk\";\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport type { ScreenshotOptions, ScreenshotResult } from \"./types.js\";\nimport { getConfig } from \"./config.js\";\nimport { now } from \"./timers.js\";\nimport { descendants } from \"./traversal.js\";\nimport { waitFor } from \"./wait-for.js\";\nimport { activeToplevel, mappedToplevels } from \"./window-state.js\";\n\ntype FrameProbe = {\n counter: bigint | null;\n startedAt: number;\n};\n\ntype CaptureFailure = \"no-size\" | \"no-content\";\n\ntype CaptureState = {\n probe: FrameProbe;\n failure: CaptureFailure | null;\n};\n\ntype CaptureResult =\n { status: \"captured\"; result: ScreenshotResult } |\n { status: \"failed\"; failure: CaptureFailure };\n\ntype CaptureOutcome =\n { status: \"captured\"; result: ScreenshotResult } |\n { status: \"stalled\"; failure: CaptureFailure };\n\nconst DEFAULT_SCREENSHOT_INTERVAL = 10;\nconst PRESENTATION_PROBE_MS = 250;\n\nconst NOT_PRESENTING_MESSAGE =\n \"Screenshot failed: the display is not presenting frames to this window, so GTK has no rendered \" +\n \"content to capture. The window is hidden, minimized, or its compositor is not presenting it; this \" +\n \"is a display problem, not a widget problem.\";\n\nconst EMPTY_WIDGET_HINT =\n \"The display is presenting frames to this window, so the widget itself is empty: it painted nothing.\";\n\nconst OTHER_FAILURE_HINT =\n \"The display is presenting frames to this window, so the capture failed for another reason.\";\n\nconst NOTHING_ON_SCREEN_MESSAGE = \"Nothing is on screen to capture: no toplevel window is mapped\";\n\nconst bytesToBase64 = (bytes: number[]): string => {\n return Buffer.from(bytes).toString(\"base64\");\n};\n\nconst describeWidgetState = (widget: Gtk.Widget): string =>\n `realized=${String(widget.getRealized())} mapped=${String(widget.getMapped())} ` +\n `visible=${String(widget.getVisible())}`;\n\nconst getMappedPopovers = (widget: Gtk.Widget): Gtk.Popover[] => {\n const popovers: Gtk.Popover[] = [];\n\n for (const descendant of descendants(widget)) {\n if (descendant instanceof Gtk.Popover && descendant.getMapped()) {\n popovers.push(descendant);\n }\n }\n\n return popovers;\n};\n\nconst appendPopover = (snapshot: Gtk.Snapshot, target: Gtk.Widget, popover: Gtk.Popover): void => {\n const [hasBounds, bounds] = popover.computeBounds(target);\n const paintable = new Gtk.WidgetPaintable({ widget: popover });\n const width = paintable.getIntrinsicWidth();\n const height = paintable.getIntrinsicHeight();\n\n if (!hasBounds || width <= 0 || height <= 0) {\n return;\n }\n\n snapshot.save();\n snapshot.translate(new Graphene.Point({ x: bounds.origin.x, y: bounds.origin.y }));\n paintable.snapshot(snapshot, width, height);\n snapshot.restore();\n};\n\nconst appendPopovers = (snapshot: Gtk.Snapshot, target: Gtk.Widget): void => {\n for (const popover of getMappedPopovers(target)) {\n appendPopover(snapshot, target, popover);\n }\n};\n\nconst getSurface = (widget: Gtk.Widget): Gdk.Surface | null => widget.getNative()?.getSurface() ?? null;\nconst isSurfaceOnScreen = (widget: Gtk.Widget): boolean => getSurface(widget)?.getMapped() ?? false;\n\nconst getFrameClock = (widget: Gtk.Widget): Gdk.FrameClock | null =>\n widget.getRoot()?.getFrameClock() ?? widget.getFrameClock();\n\nconst getFrameCounter = (widget: Gtk.Widget): bigint | null => getFrameClock(widget)?.getFrameCounter() ?? null;\n\nconst describePresentation = (widget: Gtk.Widget): string =>\n `${describeWidgetState(widget)} surfaceMapped=${String(isSurfaceOnScreen(widget))} ` +\n `frameCounter=${String(getFrameCounter(widget))}`;\n\nconst requestFrame = (widget: Gtk.Widget): void => {\n getFrameClock(widget)?.requestPhase(Gdk.FrameClockPhase.UPDATE);\n};\n\nconst startFrameProbe = (widget: Gtk.Widget): FrameProbe => {\n requestFrame(widget);\n\n return { counter: getFrameCounter(widget), startedAt: now() };\n};\n\nconst updateFrameProbe = (widget: Gtk.Widget, probe: FrameProbe): void => {\n requestFrame(widget);\n\n if (probe.counter !== null) {\n return;\n }\n\n const counter = getFrameCounter(widget);\n\n if (counter !== null) {\n probe.counter = counter;\n probe.startedAt = now();\n }\n};\n\nconst hasFrameAdvanced = (widget: Gtk.Widget, probe: FrameProbe): boolean => {\n const counter = getFrameCounter(widget);\n\n return counter !== null && probe.counter !== null && counter > probe.counter;\n};\n\nconst isPresenting = (widget: Gtk.Widget, probe: FrameProbe): boolean =>\n isSurfaceOnScreen(widget) && hasFrameAdvanced(widget, probe);\n\nconst isPresentationStalled = (widget: Gtk.Widget, probe: FrameProbe): boolean =>\n now() - probe.startedAt >= PRESENTATION_PROBE_MS && !isPresenting(widget, probe);\n\nconst allocateRoot = (widget: Gtk.Widget): void => {\n const root = widget.getRoot();\n\n if (!root) {\n return;\n }\n\n const width = root.getWidth();\n const height = root.getHeight();\n\n if (width > 0 && height > 0) {\n root.allocate(width, height, -1, null);\n }\n};\n\nconst isDirectlyPaintable = (child: Gtk.Widget): boolean =>\n child.getMapped() && child.getWidth() > 0 && !(child instanceof Gtk.Popover);\n\nconst getPaintableNode = (widget: Gtk.Widget, scale: number, width: number, height: number): Gsk.RenderNode | null => {\n const paintable = new Gtk.WidgetPaintable({ widget });\n const snapshot = new Gtk.Snapshot();\n snapshot.scale(scale, scale);\n paintable.snapshot(snapshot, width, height);\n appendPopovers(snapshot, widget);\n\n return snapshot.toNode();\n};\n\nconst getChildrenNode = (widget: Gtk.Widget, scale: number): Gsk.RenderNode | null => {\n const snapshot = new Gtk.Snapshot();\n snapshot.scale(scale, scale);\n\n for (let child = widget.getFirstChild(); child !== null; child = child.getNextSibling()) {\n if (isDirectlyPaintable(child)) {\n widget.snapshotChild(child, snapshot);\n }\n }\n\n appendPopovers(snapshot, widget);\n\n return snapshot.toNode();\n};\n\nconst getRenderNode = (widget: Gtk.Widget, scale: number, width: number, height: number): Gsk.RenderNode | null => {\n const presented = getPaintableNode(widget, scale, width, height);\n\n if (presented) {\n return presented;\n }\n\n allocateRoot(widget);\n\n return getPaintableNode(widget, scale, width, height) ?? getChildrenNode(widget, scale);\n};\n\nconst renderToPng = (widget: Gtk.Widget, node: Gsk.RenderNode, width: number, height: number): ScreenshotResult => {\n const renderer = new Gsk.CairoRenderer();\n renderer.realizeForDisplay(widget.getDisplay());\n\n try {\n const viewport = Graphene.Rect.alloc().init(0, 0, width, height);\n const texture = renderer.renderTexture(node, viewport);\n const data = texture.saveToPngBytes().getData();\n\n if (!data) {\n throw new Error(\"Failed to serialize screenshot to PNG\");\n }\n\n return { data: bytesToBase64(data), mimeType: \"image/png\", width, height };\n } finally {\n renderer.unrealize();\n }\n};\n\nconst captureSnapshot = (widget: Gtk.Widget, scale: number): CaptureResult => {\n const paintable = new Gtk.WidgetPaintable({ widget });\n const width = paintable.getIntrinsicWidth();\n const height = paintable.getIntrinsicHeight();\n\n if (width <= 0 || height <= 0) {\n return { status: \"failed\", failure: \"no-size\" };\n }\n\n const renderNode = getRenderNode(widget, scale, width, height);\n\n if (!renderNode) {\n return { status: \"failed\", failure: \"no-content\" };\n }\n\n const scaledWidth = Math.round(width * scale);\n const scaledHeight = Math.round(height * scale);\n\n return { status: \"captured\", result: renderToPng(widget, renderNode, scaledWidth, scaledHeight) };\n};\n\nconst failureMessage = (widget: Gtk.Widget, failure: CaptureFailure): string =>\n failure === \"no-size\"\n ? `Widget has no size: ensure it is realized and visible (${describeWidgetState(widget)})`\n : `Widget produced no render content (${describeWidgetState(widget)})`;\n\nconst notPresentingMessage = (widget: Gtk.Widget): string =>\n `${NOT_PRESENTING_MESSAGE} (${describePresentation(widget)})`;\n\nconst stalledMessage = (widget: Gtk.Widget, failure: CaptureFailure): string =>\n `${notPresentingMessage(widget)}\\n\\n${failureMessage(widget, failure)}`;\n\nconst presentingHint = (failure: CaptureFailure | null): string =>\n failure === \"no-content\" ? EMPTY_WIDGET_HINT : OTHER_FAILURE_HINT;\n\nconst timeoutHint = (widget: Gtk.Widget, state: CaptureState): string =>\n isPresenting(widget, state.probe) ? presentingHint(state.failure) : notPresentingMessage(widget);\n\nconst explainTimeout = (error: Error, widget: Gtk.Widget, state: CaptureState): Error =>\n getConfig().getElementError(`${error.message}\\n\\n${timeoutHint(widget, state)}`);\n\nconst attemptCapture = (widget: Gtk.Widget, scale: number, state: CaptureState): CaptureOutcome => {\n const attempt = captureSnapshot(widget, scale);\n\n if (attempt.status === \"captured\") {\n return attempt;\n }\n\n state.failure = attempt.failure;\n updateFrameProbe(widget, state.probe);\n\n if (isPresentationStalled(widget, state.probe)) {\n return { status: \"stalled\", failure: attempt.failure };\n }\n\n throw new Error(failureMessage(widget, attempt.failure));\n};\n\nconst writeScreenshot = (result: ScreenshotResult, path: string): void => {\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, Buffer.from(result.data, \"base64\"));\n};\n\nconst captureUntilPaintable = (\n widget: Gtk.Widget,\n scale: number,\n options: ScreenshotOptions | undefined,\n): Promise<CaptureOutcome> => {\n const state: CaptureState = { probe: startFrameProbe(widget), failure: null };\n\n return waitFor(() => attemptCapture(widget, scale, state), {\n timeout: options?.timeout,\n interval: options?.interval ?? DEFAULT_SCREENSHOT_INTERVAL,\n onTimeout: (error) => explainTimeout(error, widget, state),\n });\n};\n\n/**\n * Captures a PNG snapshot of a widget, retrying until it has a paintable size,\n * and writes the image to `options.path` when one is given, creating any\n * missing parent directories. Popovers open inside the widget render on their\n * own surfaces, so they are composited into the image at their on-screen\n * positions. A display that never presents a frame leaves GTK without a cached\n * render node, so the widget's contents are then snapshotted directly; when\n * even that yields nothing, the failure names the display instead of blaming\n * the widget.\n *\n * @param widget The widget to render to an image.\n * @param options Optional scale, timeout, retry interval, and output path.\n * @returns The base64-encoded PNG data along with its mime type and dimensions.\n */\nconst screenshot = async (widget: Gtk.Widget, options?: ScreenshotOptions): Promise<ScreenshotResult> => {\n const scale = options?.scale ?? 1;\n\n if (!Number.isFinite(scale) || scale <= 0) {\n throw new Error(`Screenshot scale must be a positive number, got ${String(scale)}`);\n }\n\n const outcome = await captureUntilPaintable(widget, scale, options);\n\n if (outcome.status === \"stalled\") {\n throw new Error(stalledMessage(widget, outcome.failure));\n }\n\n if (options?.path) {\n writeScreenshot(outcome.result, options.path);\n }\n\n return outcome.result;\n};\n\nconst screenTarget = (): Gtk.Window => {\n const target = activeToplevel() ?? mappedToplevels()[0];\n\n if (!target) {\n throw new Error(NOTHING_ON_SCREEN_MESSAGE);\n }\n\n return target;\n};\n\nconst captureScreen = async (options?: ScreenshotOptions): Promise<ScreenshotResult> =>\n screenshot(screenTarget(), options);\n\nexport { captureScreen, screenshot };\n"]}
1
+ {"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../src/screenshot.ts"],"names":[],"mappings":"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","sourcesContent":["import * as Gdk from \"@gtkx/gi/gdk\";\nimport * as Graphene from \"@gtkx/gi/graphene\";\nimport * as Gsk from \"@gtkx/gi/gsk\";\nimport * as Gtk from \"@gtkx/gi/gtk\";\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport type { ScreenshotOptions, ScreenshotResult } from \"./types.js\";\nimport { getConfig } from \"./config.js\";\nimport { now } from \"./timers.js\";\nimport { descendants } from \"./traversal.js\";\nimport { waitFor } from \"./wait-for.js\";\nimport { activeToplevel, mappedToplevels } from \"./window-state.js\";\n\ntype FrameProbe = {\n counter: bigint | null;\n startedAt: number;\n};\n\ntype CaptureFailure = \"no-size\" | \"no-content\";\n\ntype CaptureState = {\n probe: FrameProbe;\n failure: CaptureFailure | null;\n};\n\ntype CaptureResult =\n { status: \"captured\"; result: ScreenshotResult } |\n { status: \"failed\"; failure: CaptureFailure };\n\ntype CaptureOutcome =\n { status: \"captured\"; result: ScreenshotResult } |\n { status: \"stalled\"; failure: CaptureFailure };\n\nconst DEFAULT_SCREENSHOT_INTERVAL = 10;\nconst PRESENTATION_PROBE_MS = 250;\n\nconst NOT_PRESENTING_MESSAGE =\n \"Screenshot failed: the display is not presenting frames to this window, so GTK has no rendered \" +\n \"content to capture. The window is hidden, minimized, or its compositor is not presenting it; this \" +\n \"is a display problem, not a widget problem.\";\n\nconst EMPTY_WIDGET_HINT =\n \"The display is presenting frames to this window, so the widget itself is empty: it painted nothing.\";\n\nconst OTHER_FAILURE_HINT =\n \"The display is presenting frames to this window, so the capture failed for another reason.\";\n\nconst NOTHING_ON_SCREEN_MESSAGE = \"Nothing is on screen to capture: no toplevel window is mapped\";\n\nconst bytesToBase64 = (bytes: Uint8Array | number[]): string => {\n return Buffer.from(bytes).toString(\"base64\");\n};\n\nconst describeWidgetState = (widget: Gtk.Widget): string =>\n `realized=${String(widget.getRealized())} mapped=${String(widget.getMapped())} ` +\n `visible=${String(widget.getVisible())}`;\n\nconst getMappedPopovers = (widget: Gtk.Widget): Gtk.Popover[] => {\n const popovers: Gtk.Popover[] = [];\n\n for (const descendant of descendants(widget)) {\n if (descendant instanceof Gtk.Popover && descendant.getMapped()) {\n popovers.push(descendant);\n }\n }\n\n return popovers;\n};\n\nconst appendPopover = (snapshot: Gtk.Snapshot, target: Gtk.Widget, popover: Gtk.Popover): void => {\n const [hasBounds, bounds] = popover.computeBounds(target);\n const paintable = new Gtk.WidgetPaintable({ widget: popover });\n const width = paintable.getIntrinsicWidth();\n const height = paintable.getIntrinsicHeight();\n\n if (!hasBounds || width <= 0 || height <= 0) {\n return;\n }\n\n snapshot.save();\n snapshot.translate(new Graphene.Point({ x: bounds.origin.x, y: bounds.origin.y }));\n paintable.snapshot(snapshot, width, height);\n snapshot.restore();\n};\n\nconst appendPopovers = (snapshot: Gtk.Snapshot, target: Gtk.Widget): void => {\n for (const popover of getMappedPopovers(target)) {\n appendPopover(snapshot, target, popover);\n }\n};\n\nconst getSurface = (widget: Gtk.Widget): Gdk.Surface | null => widget.getNative()?.getSurface() ?? null;\nconst isSurfaceOnScreen = (widget: Gtk.Widget): boolean => getSurface(widget)?.getMapped() ?? false;\n\nconst getFrameClock = (widget: Gtk.Widget): Gdk.FrameClock | null =>\n widget.getRoot()?.getFrameClock() ?? widget.getFrameClock();\n\nconst getFrameCounter = (widget: Gtk.Widget): bigint | null => getFrameClock(widget)?.getFrameCounter() ?? null;\n\nconst describePresentation = (widget: Gtk.Widget): string =>\n `${describeWidgetState(widget)} surfaceMapped=${String(isSurfaceOnScreen(widget))} ` +\n `frameCounter=${String(getFrameCounter(widget))}`;\n\nconst requestFrame = (widget: Gtk.Widget): void => {\n getFrameClock(widget)?.requestPhase(Gdk.FrameClockPhase.UPDATE);\n};\n\nconst startFrameProbe = (widget: Gtk.Widget): FrameProbe => {\n requestFrame(widget);\n\n return { counter: getFrameCounter(widget), startedAt: now() };\n};\n\nconst updateFrameProbe = (widget: Gtk.Widget, probe: FrameProbe): void => {\n requestFrame(widget);\n\n if (probe.counter !== null) {\n return;\n }\n\n const counter = getFrameCounter(widget);\n\n if (counter !== null) {\n probe.counter = counter;\n probe.startedAt = now();\n }\n};\n\nconst hasFrameAdvanced = (widget: Gtk.Widget, probe: FrameProbe): boolean => {\n const counter = getFrameCounter(widget);\n\n return counter !== null && probe.counter !== null && counter > probe.counter;\n};\n\nconst isPresenting = (widget: Gtk.Widget, probe: FrameProbe): boolean =>\n isSurfaceOnScreen(widget) && hasFrameAdvanced(widget, probe);\n\nconst isPresentationStalled = (widget: Gtk.Widget, probe: FrameProbe): boolean =>\n now() - probe.startedAt >= PRESENTATION_PROBE_MS && !isPresenting(widget, probe);\n\nconst allocateRoot = (widget: Gtk.Widget): void => {\n const root = widget.getRoot();\n\n if (!root) {\n return;\n }\n\n const width = root.getWidth();\n const height = root.getHeight();\n\n if (width > 0 && height > 0) {\n root.allocate(width, height, -1, null);\n }\n};\n\nconst isDirectlyPaintable = (child: Gtk.Widget): boolean =>\n child.getMapped() && child.getWidth() > 0 && !(child instanceof Gtk.Popover);\n\nconst getPaintableNode = (widget: Gtk.Widget, scale: number, width: number, height: number): Gsk.RenderNode | null => {\n const paintable = new Gtk.WidgetPaintable({ widget });\n const snapshot = new Gtk.Snapshot();\n snapshot.scale(scale, scale);\n paintable.snapshot(snapshot, width, height);\n appendPopovers(snapshot, widget);\n\n return snapshot.toNode();\n};\n\nconst getChildrenNode = (widget: Gtk.Widget, scale: number): Gsk.RenderNode | null => {\n const snapshot = new Gtk.Snapshot();\n snapshot.scale(scale, scale);\n\n for (let child = widget.getFirstChild(); child !== null; child = child.getNextSibling()) {\n if (isDirectlyPaintable(child)) {\n widget.snapshotChild(child, snapshot);\n }\n }\n\n appendPopovers(snapshot, widget);\n\n return snapshot.toNode();\n};\n\nconst getRenderNode = (widget: Gtk.Widget, scale: number, width: number, height: number): Gsk.RenderNode | null => {\n const presented = getPaintableNode(widget, scale, width, height);\n\n if (presented) {\n return presented;\n }\n\n allocateRoot(widget);\n\n return getPaintableNode(widget, scale, width, height) ?? getChildrenNode(widget, scale);\n};\n\nconst renderToPng = (widget: Gtk.Widget, node: Gsk.RenderNode, width: number, height: number): ScreenshotResult => {\n const renderer = new Gsk.CairoRenderer();\n renderer.realizeForDisplay(widget.getDisplay());\n\n try {\n const viewport = Graphene.Rect.alloc().init(0, 0, width, height);\n const texture = renderer.renderTexture(node, viewport);\n const data = texture.saveToPngBytes().getData();\n\n if (!data) {\n throw new Error(\"Failed to serialize screenshot to PNG\");\n }\n\n return { data: bytesToBase64(data), mimeType: \"image/png\", width, height };\n } finally {\n renderer.unrealize();\n }\n};\n\nconst captureSnapshot = (widget: Gtk.Widget, scale: number): CaptureResult => {\n const paintable = new Gtk.WidgetPaintable({ widget });\n const width = paintable.getIntrinsicWidth();\n const height = paintable.getIntrinsicHeight();\n\n if (width <= 0 || height <= 0) {\n return { status: \"failed\", failure: \"no-size\" };\n }\n\n const renderNode = getRenderNode(widget, scale, width, height);\n\n if (!renderNode) {\n return { status: \"failed\", failure: \"no-content\" };\n }\n\n const scaledWidth = Math.round(width * scale);\n const scaledHeight = Math.round(height * scale);\n\n return { status: \"captured\", result: renderToPng(widget, renderNode, scaledWidth, scaledHeight) };\n};\n\nconst failureMessage = (widget: Gtk.Widget, failure: CaptureFailure): string =>\n failure === \"no-size\"\n ? `Widget has no size: ensure it is realized and visible (${describeWidgetState(widget)})`\n : `Widget produced no render content (${describeWidgetState(widget)})`;\n\nconst notPresentingMessage = (widget: Gtk.Widget): string =>\n `${NOT_PRESENTING_MESSAGE} (${describePresentation(widget)})`;\n\nconst stalledMessage = (widget: Gtk.Widget, failure: CaptureFailure): string =>\n `${notPresentingMessage(widget)}\\n\\n${failureMessage(widget, failure)}`;\n\nconst presentingHint = (failure: CaptureFailure | null): string =>\n failure === \"no-content\" ? EMPTY_WIDGET_HINT : OTHER_FAILURE_HINT;\n\nconst timeoutHint = (widget: Gtk.Widget, state: CaptureState): string =>\n isPresenting(widget, state.probe) ? presentingHint(state.failure) : notPresentingMessage(widget);\n\nconst explainTimeout = (error: Error, widget: Gtk.Widget, state: CaptureState): Error =>\n getConfig().getElementError(`${error.message}\\n\\n${timeoutHint(widget, state)}`);\n\nconst attemptCapture = (widget: Gtk.Widget, scale: number, state: CaptureState): CaptureOutcome => {\n const attempt = captureSnapshot(widget, scale);\n\n if (attempt.status === \"captured\") {\n return attempt;\n }\n\n state.failure = attempt.failure;\n updateFrameProbe(widget, state.probe);\n\n if (isPresentationStalled(widget, state.probe)) {\n return { status: \"stalled\", failure: attempt.failure };\n }\n\n throw new Error(failureMessage(widget, attempt.failure));\n};\n\nconst writeScreenshot = (result: ScreenshotResult, path: string): void => {\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, Buffer.from(result.data, \"base64\"));\n};\n\nconst captureUntilPaintable = (\n widget: Gtk.Widget,\n scale: number,\n options: ScreenshotOptions | undefined,\n): Promise<CaptureOutcome> => {\n const state: CaptureState = { probe: startFrameProbe(widget), failure: null };\n\n return waitFor(() => attemptCapture(widget, scale, state), {\n timeout: options?.timeout,\n interval: options?.interval ?? DEFAULT_SCREENSHOT_INTERVAL,\n onTimeout: (error) => explainTimeout(error, widget, state),\n });\n};\n\n/**\n * Captures a PNG snapshot of a widget, retrying until it has a paintable size,\n * and writes the image to `options.path` when one is given, creating any\n * missing parent directories. Popovers open inside the widget render on their\n * own surfaces, so they are composited into the image at their on-screen\n * positions. A display that never presents a frame leaves GTK without a cached\n * render node, so the widget's contents are then snapshotted directly; when\n * even that yields nothing, the failure names the display instead of blaming\n * the widget.\n *\n * @param widget The widget to render to an image.\n * @param options Optional scale, timeout, retry interval, and output path.\n * @returns The base64-encoded PNG data along with its mime type and dimensions.\n */\nconst screenshot = async (widget: Gtk.Widget, options?: ScreenshotOptions): Promise<ScreenshotResult> => {\n const scale = options?.scale ?? 1;\n\n if (!Number.isFinite(scale) || scale <= 0) {\n throw new Error(`Screenshot scale must be a positive number, got ${String(scale)}`);\n }\n\n const outcome = await captureUntilPaintable(widget, scale, options);\n\n if (outcome.status === \"stalled\") {\n throw new Error(stalledMessage(widget, outcome.failure));\n }\n\n if (options?.path) {\n writeScreenshot(outcome.result, options.path);\n }\n\n return outcome.result;\n};\n\nconst screenTarget = (): Gtk.Window => {\n const target = activeToplevel() ?? mappedToplevels()[0];\n\n if (!target) {\n throw new Error(NOTHING_ON_SCREEN_MESSAGE);\n }\n\n return target;\n};\n\nconst captureScreen = async (options?: ScreenshotOptions): Promise<ScreenshotResult> =>\n screenshot(screenTarget(), options);\n\nexport { captureScreen, screenshot };\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gtkx/testing",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Testing Library-style queries, user events, and screenshots for GTK4 widget trees rendered by GTKX",
5
5
  "keywords": [
6
6
  "gtkx",
@@ -60,9 +60,9 @@
60
60
  "dependencies": {
61
61
  "@vitest/expect": "^4.1.10",
62
62
  "@vitest/pretty-format": "^4.1.10",
63
- "@gtkx/runtime": "1.1.0",
64
- "@gtkx/react": "1.1.0",
65
- "@gtkx/utils": "1.1.0"
63
+ "@gtkx/runtime": "1.2.0",
64
+ "@gtkx/react": "1.2.0",
65
+ "@gtkx/utils": "1.2.0"
66
66
  },
67
67
  "peerDependencies": {
68
68
  "@types/react": "^19.2",
@@ -70,7 +70,7 @@
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/react": "^19.2.18",
73
- "@gtkx/config": "1.1.0"
73
+ "@gtkx/config": "1.2.0"
74
74
  },
75
75
  "scripts": {
76
76
  "release": "tsx ../../scripts/release-package.ts"
@@ -187,7 +187,7 @@ const requireSingle =
187
187
  * @param queryAllBy Finds every widget the family matches.
188
188
  * @param getMultipleError Builds the error thrown when a single-match variant finds more than one widget.
189
189
  * @param getMissingError Builds the error thrown when a required match is missing.
190
- * @returns The five variants, in the order `[queryBy, getAllBy, getBy, findAllBy, findBy]`.
190
+ * @returns The variants, in the order `[queryBy, getAllBy, getBy, findAllBy, findBy]`.
191
191
  */
192
192
  const buildQueries = <Args extends unknown[]>(
193
193
  queryAllBy: QueryAllBy<Args>,
package/src/screenshot.ts CHANGED
@@ -47,7 +47,7 @@ const OTHER_FAILURE_HINT =
47
47
 
48
48
  const NOTHING_ON_SCREEN_MESSAGE = "Nothing is on screen to capture: no toplevel window is mapped";
49
49
 
50
- const bytesToBase64 = (bytes: number[]): string => {
50
+ const bytesToBase64 = (bytes: Uint8Array | number[]): string => {
51
51
  return Buffer.from(bytes).toString("base64");
52
52
  };
53
53