@gtkx/testing 1.0.0-rc.3 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -9
- package/dist/accessible-native.d.ts +16 -0
- package/dist/accessible-native.d.ts.map +1 -0
- package/dist/accessible-native.js +206 -0
- package/dist/accessible-native.js.map +1 -0
- package/dist/act.d.ts +2 -0
- package/dist/act.d.ts.map +1 -1
- package/dist/act.js.map +1 -1
- package/dist/build-queries.d.ts +27 -10
- package/dist/build-queries.d.ts.map +1 -1
- package/dist/build-queries.js +39 -30
- package/dist/build-queries.js.map +1 -1
- package/dist/cleanup-registry.d.ts +1 -1
- package/dist/cleanup-registry.d.ts.map +1 -1
- package/dist/cleanup-registry.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -3
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +10 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +12 -3
- package/dist/errors.js.map +1 -1
- package/dist/fire-event.d.ts +35 -6
- package/dist/fire-event.d.ts.map +1 -1
- package/dist/fire-event.js +23 -7
- package/dist/fire-event.js.map +1 -1
- package/dist/frame-sync.d.ts +2 -1
- package/dist/frame-sync.d.ts.map +1 -1
- package/dist/frame-sync.js +15 -5
- package/dist/frame-sync.js.map +1 -1
- package/dist/harness-window.d.ts +4 -0
- package/dist/harness-window.d.ts.map +1 -0
- package/dist/harness-window.js +6 -0
- package/dist/harness-window.js.map +1 -0
- package/dist/index.d.ts +14 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -5
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +4 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +4 -0
- package/dist/internal.js.map +1 -0
- package/dist/matchers.d.ts +125 -39
- package/dist/matchers.d.ts.map +1 -1
- package/dist/matchers.js +156 -18
- package/dist/matchers.js.map +1 -1
- package/dist/pretty-format.d.ts +2 -0
- package/dist/pretty-format.d.ts.map +1 -0
- package/dist/pretty-format.js +2 -0
- package/dist/pretty-format.js.map +1 -0
- package/dist/pretty-widget.d.ts +7 -3
- package/dist/pretty-widget.d.ts.map +1 -1
- package/dist/pretty-widget.js +74 -57
- package/dist/pretty-widget.js.map +1 -1
- package/dist/production.d.ts +8 -0
- package/dist/production.d.ts.map +1 -0
- package/dist/production.js +34 -0
- package/dist/production.js.map +1 -0
- package/dist/queries.d.ts +99 -56
- package/dist/queries.d.ts.map +1 -1
- package/dist/queries.js +123 -83
- package/dist/queries.js.map +1 -1
- package/dist/query-helpers.d.ts +44 -0
- package/dist/query-helpers.d.ts.map +1 -0
- package/dist/query-helpers.js +57 -0
- package/dist/query-helpers.js.map +1 -0
- package/dist/render-children.d.ts +9 -0
- package/dist/render-children.d.ts.map +1 -0
- package/dist/render-children.js +11 -0
- package/dist/render-children.js.map +1 -0
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +13 -11
- package/dist/render.js.map +1 -1
- package/dist/role-helpers.d.ts +12 -3
- package/dist/role-helpers.d.ts.map +1 -1
- package/dist/role-helpers.js +13 -4
- package/dist/role-helpers.js.map +1 -1
- package/dist/role-naming.d.ts +5 -0
- package/dist/role-naming.d.ts.map +1 -0
- package/dist/role-naming.js +96 -0
- package/dist/role-naming.js.map +1 -0
- package/dist/screenshot.d.ts +12 -20
- package/dist/screenshot.d.ts.map +1 -1
- package/dist/screenshot.js +183 -91
- package/dist/screenshot.js.map +1 -1
- package/dist/suggestions.d.ts +3 -0
- package/dist/suggestions.d.ts.map +1 -1
- package/dist/suggestions.js.map +1 -1
- package/dist/traversal.d.ts +9 -1
- package/dist/traversal.d.ts.map +1 -1
- package/dist/traversal.js +26 -6
- package/dist/traversal.js.map +1 -1
- package/dist/types.d.ts +67 -17
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/user-event/adjustment.d.ts +16 -0
- package/dist/user-event/adjustment.d.ts.map +1 -1
- package/dist/user-event/adjustment.js +34 -2
- package/dist/user-event/adjustment.js.map +1 -1
- package/dist/user-event/click.d.ts +45 -3
- package/dist/user-event/click.d.ts.map +1 -1
- package/dist/user-event/click.js +177 -39
- package/dist/user-event/click.js.map +1 -1
- package/dist/user-event/column-header-click.d.ts +4 -0
- package/dist/user-event/column-header-click.d.ts.map +1 -0
- package/dist/user-event/column-header-click.js +65 -0
- package/dist/user-event/column-header-click.js.map +1 -0
- package/dist/user-event/controller.d.ts +29 -0
- package/dist/user-event/controller.d.ts.map +1 -1
- package/dist/user-event/controller.js +28 -0
- package/dist/user-event/controller.js.map +1 -1
- package/dist/user-event/event-wrapper.d.ts.map +1 -1
- package/dist/user-event/event-wrapper.js +2 -1
- package/dist/user-event/event-wrapper.js.map +1 -1
- package/dist/user-event/gesture.d.ts +51 -0
- package/dist/user-event/gesture.d.ts.map +1 -1
- package/dist/user-event/gesture.js +47 -4
- package/dist/user-event/gesture.js.map +1 -1
- package/dist/user-event/index.d.ts +70 -2
- package/dist/user-event/index.d.ts.map +1 -1
- package/dist/user-event/index.js +43 -26
- package/dist/user-event/index.js.map +1 -1
- package/dist/user-event/indexed-children.d.ts +10 -0
- package/dist/user-event/indexed-children.d.ts.map +1 -0
- package/dist/user-event/indexed-children.js +50 -0
- package/dist/user-event/indexed-children.js.map +1 -0
- package/dist/user-event/keyboard.d.ts +4 -2
- package/dist/user-event/keyboard.d.ts.map +1 -1
- package/dist/user-event/keyboard.js +46 -16
- package/dist/user-event/keyboard.js.map +1 -1
- package/dist/user-event/list-row-click.d.ts +4 -0
- package/dist/user-event/list-row-click.d.ts.map +1 -0
- package/dist/user-event/list-row-click.js +39 -0
- package/dist/user-event/list-row-click.js.map +1 -0
- package/dist/user-event/native-click.d.ts +6 -0
- package/dist/user-event/native-click.d.ts.map +1 -0
- package/dist/user-event/native-click.js +32 -0
- package/dist/user-event/native-click.js.map +1 -0
- package/dist/user-event/pointer.d.ts +1 -1
- package/dist/user-event/pointer.d.ts.map +1 -1
- package/dist/user-event/pointer.js +37 -13
- package/dist/user-event/pointer.js.map +1 -1
- package/dist/user-event/selection.d.ts +18 -0
- package/dist/user-event/selection.d.ts.map +1 -1
- package/dist/user-event/selection.js +56 -30
- package/dist/user-event/selection.js.map +1 -1
- package/dist/user-event/state.d.ts +1 -1
- package/dist/user-event/state.d.ts.map +1 -1
- package/dist/user-event/state.js +1 -1
- package/dist/user-event/state.js.map +1 -1
- package/dist/user-event/text.d.ts +34 -3
- package/dist/user-event/text.d.ts.map +1 -1
- package/dist/user-event/text.js +94 -17
- package/dist/user-event/text.js.map +1 -1
- package/dist/wait-for.d.ts +2 -0
- package/dist/wait-for.d.ts.map +1 -1
- package/dist/wait-for.js.map +1 -1
- package/dist/widget-accessible-properties.d.ts +14 -10
- package/dist/widget-accessible-properties.d.ts.map +1 -1
- package/dist/widget-accessible-properties.js +135 -173
- package/dist/widget-accessible-properties.js.map +1 -1
- package/dist/widget-getters.d.ts +8 -0
- package/dist/widget-getters.d.ts.map +1 -0
- package/dist/widget-getters.js +19 -0
- package/dist/widget-getters.js.map +1 -0
- package/dist/within.d.ts +3 -2
- package/dist/within.d.ts.map +1 -1
- package/dist/within.js +3 -2
- package/dist/within.js.map +1 -1
- package/package.json +13 -8
- package/src/accessible-native.ts +333 -0
- package/src/act.ts +2 -0
- package/src/build-queries.ts +66 -48
- package/src/cleanup-registry.ts +1 -1
- package/src/config.ts +4 -3
- package/src/errors.ts +14 -3
- package/src/fire-event.ts +61 -8
- package/src/frame-sync.ts +21 -5
- package/src/harness-window.ts +9 -0
- package/src/index.ts +18 -11
- package/src/internal.ts +11 -0
- package/src/matchers.ts +466 -64
- package/src/pretty-format.ts +1 -0
- package/src/pretty-widget.ts +100 -72
- package/src/production.ts +52 -0
- package/src/queries.ts +128 -89
- package/src/query-helpers.ts +97 -0
- package/src/render-children.ts +25 -0
- package/src/render.tsx +18 -13
- package/src/role-helpers.ts +14 -4
- package/src/role-naming.ts +99 -0
- package/src/screenshot.ts +272 -103
- package/src/suggestions.ts +3 -0
- package/src/traversal.ts +49 -6
- package/src/types.ts +69 -19
- package/src/user-event/adjustment.ts +42 -2
- package/src/user-event/click.ts +248 -46
- package/src/user-event/column-header-click.ts +90 -0
- package/src/user-event/controller.ts +29 -0
- package/src/user-event/event-wrapper.ts +3 -1
- package/src/user-event/gesture.ts +57 -6
- package/src/user-event/index.ts +119 -29
- package/src/user-event/indexed-children.ts +75 -0
- package/src/user-event/keyboard.ts +70 -20
- package/src/user-event/list-row-click.ts +57 -0
- package/src/user-event/native-click.ts +46 -0
- package/src/user-event/pointer.ts +52 -13
- package/src/user-event/selection.ts +74 -33
- package/src/user-event/state.ts +2 -2
- package/src/user-event/text.ts +121 -23
- package/src/wait-for.ts +2 -0
- package/src/widget-accessible-properties.ts +183 -214
- package/src/widget-getters.ts +32 -0
- package/src/within.ts +3 -2
package/src/build-queries.ts
CHANGED
|
@@ -3,63 +3,61 @@ import type { Container } from "./traversal.js";
|
|
|
3
3
|
import type { MatcherOptions, WaitForOptions } from "./types.js";
|
|
4
4
|
import { getConfig } from "./config.js";
|
|
5
5
|
import { runWithExpensiveErrorDiagnosticsDisabled, suggestionError } from "./errors.js";
|
|
6
|
-
import { getSuggestedQuery, type
|
|
6
|
+
import { getSuggestedQuery, type Variant } from "./suggestions.js";
|
|
7
7
|
import { waitFor } from "./wait-for.js";
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* The `queryAllBy` function a query family is built from, taking the scope to search followed by the
|
|
11
|
+
* family's own matcher arguments. Its name determines the family name, so `queryAllByTestId` builds
|
|
12
|
+
* a `TestId` family.
|
|
13
|
+
*/
|
|
9
14
|
type QueryAllBy<Args extends unknown[]> = (container: Container, ...args: Args) => Gtk.Widget[];
|
|
10
15
|
|
|
16
|
+
/** Builds the error thrown when a single-match query finds more than one widget. */
|
|
11
17
|
type MultipleErrorBuilder<Args extends unknown[]> = (
|
|
12
18
|
container: Container,
|
|
13
19
|
matches: Gtk.Widget[],
|
|
14
20
|
...args: Args
|
|
15
21
|
) => Error;
|
|
16
22
|
|
|
23
|
+
/** Builds the error thrown when a query that requires a match finds none. */
|
|
17
24
|
type MissingErrorBuilder<Args extends unknown[]> = (container: Container, ...args: Args) => Error;
|
|
18
25
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
/** The variants derived from one `queryAllBy` function, in the order DOM Testing Library returns them. */
|
|
27
|
+
type BuiltQueries<Args extends unknown[]> = [
|
|
28
|
+
queryBy: (container: Container, ...args: Args) => Gtk.Widget | null,
|
|
29
|
+
getAllBy: QueryAllBy<Args>,
|
|
30
|
+
getBy: (container: Container, ...args: Args) => Gtk.Widget,
|
|
31
|
+
findAllBy: (container: Container, ...args: Args) => Promise<Gtk.Widget[]>,
|
|
32
|
+
findBy: (container: Container, ...args: Args) => Promise<Gtk.Widget>,
|
|
33
|
+
];
|
|
26
34
|
|
|
27
35
|
type FindQuery<Args extends unknown[]> = (container: Container, ...args: Args) => unknown;
|
|
28
36
|
type SingleQuery<Args extends unknown[]> = (container: Container, ...args: Args) => Gtk.Widget | null;
|
|
29
37
|
|
|
30
|
-
const
|
|
31
|
-
const last = args.at(-1);
|
|
32
|
-
|
|
33
|
-
if (last && typeof last === "object" && !(last instanceof RegExp)) {
|
|
34
|
-
const { timeout, interval, onTimeout } = last as WaitForOptions;
|
|
35
|
-
|
|
36
|
-
return { timeout, interval, onTimeout };
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return {};
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const extractSuggestOption = (args: unknown[]): boolean | undefined => {
|
|
38
|
+
const getTrailingOptions = (args: unknown[]): MatcherOptions | undefined => {
|
|
43
39
|
const last = args.at(-1);
|
|
44
40
|
|
|
45
41
|
if (last && typeof last === "object" && !(last instanceof RegExp)) {
|
|
46
|
-
return
|
|
42
|
+
return last;
|
|
47
43
|
}
|
|
48
44
|
|
|
49
45
|
return undefined;
|
|
50
46
|
};
|
|
51
47
|
|
|
48
|
+
const extractShouldSuggest = (args: unknown[]): boolean | undefined => getTrailingOptions(args)?.suggest;
|
|
49
|
+
const getQueryFamily = (queryAllBy: { name: string }): string => queryAllBy.name.replace(/^queryAllBy/, "");
|
|
50
|
+
|
|
52
51
|
const maybeThrowSuggestion = (options: {
|
|
53
52
|
container: Container;
|
|
54
53
|
match: Gtk.Widget;
|
|
55
|
-
queryName:
|
|
54
|
+
queryName: string;
|
|
56
55
|
variant: Variant;
|
|
57
|
-
|
|
56
|
+
shouldSuggest: boolean | undefined;
|
|
58
57
|
}): void => {
|
|
59
|
-
const { container, match, queryName, variant,
|
|
60
|
-
const shouldSuggest = suggest ?? getConfig().throwSuggestions;
|
|
58
|
+
const { container, match, queryName, variant, shouldSuggest } = options;
|
|
61
59
|
|
|
62
|
-
if (!shouldSuggest) {
|
|
60
|
+
if (!(shouldSuggest ?? getConfig().throwSuggestions)) {
|
|
63
61
|
return;
|
|
64
62
|
}
|
|
65
63
|
|
|
@@ -92,16 +90,13 @@ const findOptions = <Args extends unknown[]>(
|
|
|
92
90
|
container: Container,
|
|
93
91
|
args: Args,
|
|
94
92
|
): WaitForOptions => {
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
const onTimeout =
|
|
98
|
-
userOptions.onTimeout ?? ((fallback: Error) => reRunForDiagnostics(query, container, args, fallback));
|
|
93
|
+
const { timeout, interval, onTimeout } = getTrailingOptions(args) ?? {};
|
|
99
94
|
|
|
100
95
|
return {
|
|
101
96
|
stackTraceError: new Error("STACK_TRACE_MESSAGE"),
|
|
102
|
-
onTimeout,
|
|
103
|
-
timeout
|
|
104
|
-
interval
|
|
97
|
+
onTimeout: onTimeout ?? ((fallback: Error) => reRunForDiagnostics(query, container, args, fallback)),
|
|
98
|
+
timeout,
|
|
99
|
+
interval,
|
|
105
100
|
};
|
|
106
101
|
};
|
|
107
102
|
|
|
@@ -136,19 +131,25 @@ const allOrThrow =
|
|
|
136
131
|
};
|
|
137
132
|
|
|
138
133
|
const wrapSingleWithSuggestion =
|
|
139
|
-
<Args extends unknown[]>(query: SingleQuery<Args>, queryName:
|
|
134
|
+
<Args extends unknown[]>(query: SingleQuery<Args>, queryName: string, variant: Variant): SingleQuery<Args> =>
|
|
140
135
|
(container, ...args) => {
|
|
141
136
|
const match = query(container, ...args);
|
|
142
137
|
|
|
143
138
|
if (match) {
|
|
144
|
-
maybeThrowSuggestion({
|
|
139
|
+
maybeThrowSuggestion({
|
|
140
|
+
container,
|
|
141
|
+
match,
|
|
142
|
+
queryName,
|
|
143
|
+
variant,
|
|
144
|
+
shouldSuggest: extractShouldSuggest(args),
|
|
145
|
+
});
|
|
145
146
|
}
|
|
146
147
|
|
|
147
148
|
return match;
|
|
148
149
|
};
|
|
149
150
|
|
|
150
151
|
const wrapAllWithSuggestion =
|
|
151
|
-
<Args extends unknown[]>(query: QueryAllBy<Args>, queryName:
|
|
152
|
+
<Args extends unknown[]>(query: QueryAllBy<Args>, queryName: string, variant: Variant): QueryAllBy<Args> =>
|
|
152
153
|
(container, ...args) => {
|
|
153
154
|
const matches = query(container, ...args);
|
|
154
155
|
const [first] = matches;
|
|
@@ -159,7 +160,7 @@ const wrapAllWithSuggestion =
|
|
|
159
160
|
match: first,
|
|
160
161
|
queryName,
|
|
161
162
|
variant,
|
|
162
|
-
|
|
163
|
+
shouldSuggest: extractShouldSuggest(args),
|
|
163
164
|
});
|
|
164
165
|
}
|
|
165
166
|
|
|
@@ -178,12 +179,22 @@ const requireSingle =
|
|
|
178
179
|
return match;
|
|
179
180
|
};
|
|
180
181
|
|
|
182
|
+
/**
|
|
183
|
+
* Derives the `queryBy`, `getAllBy`, `getBy`, `findAllBy`, and `findBy` variants of a query family
|
|
184
|
+
* from the family's `queryAllBy` function, mirroring DOM Testing Library's `buildQueries`. The family
|
|
185
|
+
* name used when suggesting a better query comes from `queryAllBy.name`.
|
|
186
|
+
*
|
|
187
|
+
* @param queryAllBy Finds every widget the family matches.
|
|
188
|
+
* @param getMultipleError Builds the error thrown when a single-match variant finds more than one widget.
|
|
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]`.
|
|
191
|
+
*/
|
|
181
192
|
const buildQueries = <Args extends unknown[]>(
|
|
182
|
-
queryName: Method,
|
|
183
193
|
queryAllBy: QueryAllBy<Args>,
|
|
184
194
|
getMultipleError: MultipleErrorBuilder<Args>,
|
|
185
195
|
getMissingError: MissingErrorBuilder<Args>,
|
|
186
196
|
): BuiltQueries<Args> => {
|
|
197
|
+
const queryName = getQueryFamily(queryAllBy);
|
|
187
198
|
const getAllBy = allOrThrow(queryAllBy, getMissingError);
|
|
188
199
|
const getBy = requireSingle(singleFrom(getAllBy, getMultipleError), getMissingError);
|
|
189
200
|
|
|
@@ -197,7 +208,14 @@ const buildQueries = <Args extends unknown[]>(
|
|
|
197
208
|
|
|
198
209
|
const getByWithSuggestion: (container: Container, ...args: Args) => Gtk.Widget = (container, ...args) => {
|
|
199
210
|
const match = getBy(container, ...args);
|
|
200
|
-
|
|
211
|
+
|
|
212
|
+
maybeThrowSuggestion({
|
|
213
|
+
container,
|
|
214
|
+
match,
|
|
215
|
+
queryName,
|
|
216
|
+
variant: "get",
|
|
217
|
+
shouldSuggest: extractShouldSuggest(args),
|
|
218
|
+
});
|
|
201
219
|
|
|
202
220
|
return match;
|
|
203
221
|
};
|
|
@@ -214,13 +232,13 @@ const buildQueries = <Args extends unknown[]>(
|
|
|
214
232
|
findOptions(getByWithSuggestion, container, args),
|
|
215
233
|
);
|
|
216
234
|
|
|
217
|
-
return
|
|
218
|
-
queryBy: queryByWithSuggestion,
|
|
219
|
-
getAllBy: getAllByWithSuggestion,
|
|
220
|
-
getBy: getByWithSuggestion,
|
|
221
|
-
findAllBy,
|
|
222
|
-
findBy,
|
|
223
|
-
};
|
|
235
|
+
return [queryByWithSuggestion, getAllByWithSuggestion, getByWithSuggestion, findAllBy, findBy];
|
|
224
236
|
};
|
|
225
237
|
|
|
226
|
-
export {
|
|
238
|
+
export {
|
|
239
|
+
buildQueries,
|
|
240
|
+
type BuiltQueries,
|
|
241
|
+
type MissingErrorBuilder,
|
|
242
|
+
type MultipleErrorBuilder,
|
|
243
|
+
type QueryAllBy,
|
|
244
|
+
};
|
package/src/cleanup-registry.ts
CHANGED
package/src/config.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { Container } from "./traversal.js";
|
|
|
6
6
|
* checks.
|
|
7
7
|
*/
|
|
8
8
|
type Config = {
|
|
9
|
+
/** Whether a successful query throws instead, naming a better query, when one is available. */
|
|
9
10
|
throwSuggestions: boolean;
|
|
10
11
|
|
|
11
12
|
/** Builds the error thrown when a query fails, given a message and optional container. */
|
|
@@ -34,7 +35,7 @@ const defaultConfig: Config = {
|
|
|
34
35
|
const currentConfig: Config = { ...defaultConfig };
|
|
35
36
|
|
|
36
37
|
function defaultGetElementError(message: string): Error {
|
|
37
|
-
return new
|
|
38
|
+
return new ElementError(message);
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
/**
|
|
@@ -55,8 +56,8 @@ const configure = (newConfig: Partial<Config> | ConfigFn): void => {
|
|
|
55
56
|
Object.assign(currentConfig, updates);
|
|
56
57
|
};
|
|
57
58
|
|
|
58
|
-
class
|
|
59
|
-
override name = "
|
|
59
|
+
class ElementError extends Error {
|
|
60
|
+
override name = "ElementError";
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
export { getConfig, configure, type Config, type ConfigFn };
|
package/src/errors.ts
CHANGED
|
@@ -125,11 +125,22 @@ const buildElementError = (container: Container, headLines: string[]): Error =>
|
|
|
125
125
|
|
|
126
126
|
const lines = expensiveErrorDiagnostics.isDisabled
|
|
127
127
|
? headLines
|
|
128
|
-
: [...headLines, "", prettyWidget(container, {
|
|
128
|
+
: [...headLines, "", prettyWidget(container, { shouldHighlight: false })];
|
|
129
129
|
|
|
130
130
|
return config.getElementError(lines.join("\n"), container);
|
|
131
131
|
};
|
|
132
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Builds the error a failing query throws, appending the container's widget tree to the message the
|
|
135
|
+
* way the built-in queries do.
|
|
136
|
+
*
|
|
137
|
+
* @param message The failure message.
|
|
138
|
+
* @param container The scope whose widget tree is appended; omitted, only the message is used.
|
|
139
|
+
* @returns The error produced by the configured `getElementError`.
|
|
140
|
+
*/
|
|
141
|
+
const getElementError = (message: string, container?: Container): Error =>
|
|
142
|
+
container === undefined ? getConfig().getElementError(message) : buildElementError(container, [message]);
|
|
143
|
+
|
|
133
144
|
const notFoundError = (container: Container, descriptor: QueryDescriptor): Error => {
|
|
134
145
|
const description = formatQueryDescription(descriptor);
|
|
135
146
|
const headLines = [`Unable to find an element with ${description}`];
|
|
@@ -160,7 +171,7 @@ const multipleFoundError = (container: Container, descriptor: QueryDescriptor, m
|
|
|
160
171
|
];
|
|
161
172
|
|
|
162
173
|
if (!expensiveErrorDiagnostics.isDisabled) {
|
|
163
|
-
const renderedMatches = matches.map((widget) => prettyWidget(widget, {
|
|
174
|
+
const renderedMatches = matches.map((widget) => prettyWidget(widget, { shouldHighlight: false }));
|
|
164
175
|
headLines.push("", "Here are the matching elements:", "", ...renderedMatches);
|
|
165
176
|
}
|
|
166
177
|
|
|
@@ -183,9 +194,9 @@ const timeoutError = (timeout: number, lastError: Error | null): Error => {
|
|
|
183
194
|
|
|
184
195
|
export {
|
|
185
196
|
runWithExpensiveErrorDiagnosticsDisabled,
|
|
197
|
+
getElementError,
|
|
186
198
|
notFoundError,
|
|
187
199
|
multipleFoundError,
|
|
188
200
|
suggestionError,
|
|
189
201
|
timeoutError,
|
|
190
|
-
type QueryDescriptor,
|
|
191
202
|
};
|
package/src/fire-event.ts
CHANGED
|
@@ -1,18 +1,71 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as GObject from "@gtkx/gi/gobject";
|
|
2
2
|
import { runInAct } from "./act.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* A signal emission built but not yet delivered. GObject has no event object to construct, so this
|
|
6
|
+
* records the target, signal, and arguments {@link fireEvent} will emit.
|
|
7
|
+
*/
|
|
8
|
+
type WidgetEvent = {
|
|
9
|
+
/** The GObject instance the signal is emitted on. */
|
|
10
|
+
target: GObject.Object;
|
|
11
|
+
/** Name of the signal to emit. */
|
|
12
|
+
signalName: string;
|
|
13
|
+
/** Arguments passed to the signal handlers. */
|
|
14
|
+
args: unknown[];
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Records a signal emission without delivering it, so it can be inspected or held and passed to
|
|
19
|
+
* {@link fireEvent} later.
|
|
7
20
|
*
|
|
8
|
-
* @param
|
|
21
|
+
* @param target The GObject instance the signal would be emitted on.
|
|
9
22
|
* @param signalName Name of the signal to emit.
|
|
10
|
-
* @param args Arguments
|
|
23
|
+
* @param args Arguments to pass to the signal handlers.
|
|
24
|
+
* @returns The recorded emission.
|
|
11
25
|
*/
|
|
12
|
-
const
|
|
26
|
+
const createEvent = (target: GObject.Object, signalName: string, ...args: unknown[]): WidgetEvent => ({
|
|
27
|
+
target,
|
|
28
|
+
signalName,
|
|
29
|
+
args,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const dispatchEvent = async (event: WidgetEvent): Promise<void> => {
|
|
13
33
|
await runInAct(() => {
|
|
14
|
-
|
|
34
|
+
event.target.emit(event.signalName, ...event.args);
|
|
15
35
|
});
|
|
16
36
|
};
|
|
17
37
|
|
|
18
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Emits a recorded signal emission inside React's act environment, so any resulting state updates are
|
|
40
|
+
* flushed before the promise resolves.
|
|
41
|
+
*
|
|
42
|
+
* @param event An emission built by {@link createEvent}.
|
|
43
|
+
*/
|
|
44
|
+
function fireEvent(event: WidgetEvent): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Emits a GObject signal on a widget or object inside React's act environment, so any resulting state
|
|
47
|
+
* updates are flushed before the promise resolves.
|
|
48
|
+
*
|
|
49
|
+
* @param target The GObject instance to emit the signal on.
|
|
50
|
+
* @param signalName Name of the signal to emit.
|
|
51
|
+
* @param args Arguments passed to the signal handlers.
|
|
52
|
+
*/
|
|
53
|
+
function fireEvent(target: GObject.Object, signalName: string, ...args: unknown[]): Promise<void>;
|
|
54
|
+
|
|
55
|
+
function fireEvent(
|
|
56
|
+
eventOrTarget: WidgetEvent | GObject.Object,
|
|
57
|
+
signalName?: string,
|
|
58
|
+
...args: unknown[]
|
|
59
|
+
): Promise<void> {
|
|
60
|
+
if (!(eventOrTarget instanceof GObject.Object)) {
|
|
61
|
+
return dispatchEvent(eventOrTarget);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (signalName === undefined) {
|
|
65
|
+
throw new Error("Unable to fire an event: pass a signal name, or an event built by createEvent.");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return dispatchEvent(createEvent(eventOrTarget, signalName, ...args));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export { createEvent, fireEvent, type WidgetEvent };
|
package/src/frame-sync.ts
CHANGED
|
@@ -16,7 +16,10 @@ const once = (callback: () => void): (() => void) => {
|
|
|
16
16
|
};
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
-
const
|
|
19
|
+
const hasFrameClock = (widget: Gtk.Widget | null): widget is Gtk.Widget => widget?.getFrameClock() != null;
|
|
20
|
+
const isSized = (widget: Gtk.Widget): boolean => widget.getWidth() > 0;
|
|
21
|
+
|
|
22
|
+
const runUntilReady = (widget: Gtk.Widget, isReady: () => boolean, finish: () => void): void => {
|
|
20
23
|
let tickId = 0;
|
|
21
24
|
|
|
22
25
|
const fallback = setTimeout(() => {
|
|
@@ -25,7 +28,7 @@ const runWhenSized = (widget: Gtk.Widget, finish: () => void): void => {
|
|
|
25
28
|
}, CLOCK_STALL_FALLBACK_MS);
|
|
26
29
|
|
|
27
30
|
tickId = widget.addTickCallback(() => {
|
|
28
|
-
if (
|
|
31
|
+
if (!isReady()) {
|
|
29
32
|
return GLib.SOURCE_CONTINUE;
|
|
30
33
|
}
|
|
31
34
|
|
|
@@ -36,16 +39,29 @@ const runWhenSized = (widget: Gtk.Widget, finish: () => void): void => {
|
|
|
36
39
|
});
|
|
37
40
|
};
|
|
38
41
|
|
|
42
|
+
const scheduleNextFrame = (widget: Gtk.Widget): Promise<void> =>
|
|
43
|
+
new Promise((resolve) => {
|
|
44
|
+
const finish = once(resolve);
|
|
45
|
+
|
|
46
|
+
if (!hasFrameClock(widget)) {
|
|
47
|
+
queueMicrotask(finish);
|
|
48
|
+
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
runUntilReady(widget, () => true, finish);
|
|
53
|
+
});
|
|
54
|
+
|
|
39
55
|
const scheduleAfterLayout = (widget: Gtk.Widget | null, callback: () => void): void => {
|
|
40
56
|
const finish = once(callback);
|
|
41
57
|
|
|
42
|
-
if (widget
|
|
58
|
+
if (!hasFrameClock(widget) || isSized(widget)) {
|
|
43
59
|
queueMicrotask(finish);
|
|
44
60
|
|
|
45
61
|
return;
|
|
46
62
|
}
|
|
47
63
|
|
|
48
|
-
|
|
64
|
+
runUntilReady(widget, () => isSized(widget), finish);
|
|
49
65
|
};
|
|
50
66
|
|
|
51
|
-
export { scheduleAfterLayout };
|
|
67
|
+
export { scheduleAfterLayout, scheduleNextFrame };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as Gtk from "@gtkx/gi/gtk";
|
|
2
|
+
|
|
3
|
+
const HARNESS_WINDOW_WIDTH = 800;
|
|
4
|
+
const HARNESS_WINDOW_HEIGHT = 600;
|
|
5
|
+
|
|
6
|
+
const createHarnessWindow = (): Gtk.Window =>
|
|
7
|
+
new Gtk.Window({ defaultWidth: HARNESS_WINDOW_WIDTH, defaultHeight: HARNESS_WINDOW_HEIGHT });
|
|
8
|
+
|
|
9
|
+
export { createHarnessWindow };
|
package/src/index.ts
CHANGED
|
@@ -2,12 +2,22 @@ import "./register-test-hooks.js";
|
|
|
2
2
|
|
|
3
3
|
export { act } from "./act.js";
|
|
4
4
|
export type { BoundQueries, RenderResult, Screen } from "./bound-queries.js";
|
|
5
|
+
export type {
|
|
6
|
+
BuiltQueries,
|
|
7
|
+
MissingErrorBuilder,
|
|
8
|
+
MultipleErrorBuilder,
|
|
9
|
+
QueryAllBy,
|
|
10
|
+
} from "./build-queries.js";
|
|
11
|
+
export { buildQueries } from "./build-queries.js";
|
|
5
12
|
export type { Config, ConfigFn } from "./config.js";
|
|
6
13
|
export { configure, getConfig } from "./config.js";
|
|
7
|
-
export {
|
|
14
|
+
export { getElementError } from "./errors.js";
|
|
15
|
+
export type { WidgetEvent } from "./fire-event.js";
|
|
16
|
+
export { createEvent, fireEvent } from "./fire-event.js";
|
|
8
17
|
export type { ClassExpectation, TextContentOptions, TextExpectation } from "./matchers.js";
|
|
9
18
|
export { matchers, registerMatchers } from "./matchers.js";
|
|
10
19
|
export { getDefaultNormalizer } from "./normalize.js";
|
|
20
|
+
export { prettyFormat } from "./pretty-format.js";
|
|
11
21
|
export type { PrettyWidgetOptions } from "./pretty-widget.js";
|
|
12
22
|
export { logWidget, prettyWidget } from "./pretty-widget.js";
|
|
13
23
|
export {
|
|
@@ -48,11 +58,13 @@ export {
|
|
|
48
58
|
queryByRole,
|
|
49
59
|
queryByText,
|
|
50
60
|
} from "./queries.js";
|
|
61
|
+
export type { QueryHelpers } from "./query-helpers.js";
|
|
62
|
+
export { queryAllByObjectProperty, queryByObjectProperty, queryHelpers } from "./query-helpers.js";
|
|
51
63
|
export { renderHook } from "./render-hook.js";
|
|
52
64
|
export { cleanup, render } from "./render.js";
|
|
53
|
-
export { formatRole, getRoles, logRoles, prettyRoles } from "./role-helpers.js";
|
|
65
|
+
export { computeHeadingLevel, formatRole, getRoles, logRoles, prettyRoles } from "./role-helpers.js";
|
|
54
66
|
export { screen } from "./screen.js";
|
|
55
|
-
export {
|
|
67
|
+
export { screenshot } from "./screenshot.js";
|
|
56
68
|
export type { Method, Suggestion, Variant } from "./suggestions.js";
|
|
57
69
|
export { getSuggestedQuery } from "./suggestions.js";
|
|
58
70
|
export type { Container } from "./traversal.js";
|
|
@@ -71,7 +83,6 @@ export type {
|
|
|
71
83
|
ScreenshotOptions,
|
|
72
84
|
ScreenshotResult,
|
|
73
85
|
WaitForOptions,
|
|
74
|
-
WindowSelector,
|
|
75
86
|
WrapperComponent,
|
|
76
87
|
} from "./types.js";
|
|
77
88
|
export type { ControllerConstructor } from "./user-event/controller.js";
|
|
@@ -91,13 +102,9 @@ export type {
|
|
|
91
102
|
TabOptions,
|
|
92
103
|
TypeOptions,
|
|
93
104
|
UserEvent,
|
|
105
|
+
UserEventOptions,
|
|
94
106
|
} from "./user-event/index.js";
|
|
95
107
|
export { userEvent } from "./user-event/index.js";
|
|
96
108
|
export { waitFor, waitForElementToBeRemoved } from "./wait-for.js";
|
|
97
|
-
export {
|
|
98
|
-
|
|
99
|
-
getWidgetInvalidState,
|
|
100
|
-
getWidgetNodeText,
|
|
101
|
-
getWidgetTextContent,
|
|
102
|
-
} from "./widget-accessible-properties.js";
|
|
103
|
-
export { within } from "./within.js";
|
|
109
|
+
export { getWidgetText, isInaccessible } from "./widget-accessible-properties.js";
|
|
110
|
+
export { getQueriesForElement, within } from "./within.js";
|
package/src/internal.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export {
|
|
2
|
+
readAccessibleBooleanProperty,
|
|
3
|
+
readAccessibleFlag,
|
|
4
|
+
readAccessibleInt,
|
|
5
|
+
readAccessibleNumber,
|
|
6
|
+
readAccessibleRelation,
|
|
7
|
+
readAccessibleState,
|
|
8
|
+
readAccessibleString,
|
|
9
|
+
} from "./accessible-native.js";
|
|
10
|
+
export { cleanup, render } from "./production.js";
|
|
11
|
+
export { renderChildren, type ChildrenBuilder } from "./render-children.js";
|