@gtkx/testing 1.0.0-rc.4 → 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 +5 -5
- 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/build-queries.d.ts +27 -10
- package/dist/build-queries.d.ts.map +1 -1
- package/dist/build-queries.js +22 -24
- 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/errors.d.ts +10 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +10 -1
- 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 +88 -46
- 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 +5 -2
- package/dist/pretty-widget.d.ts.map +1 -1
- package/dist/pretty-widget.js +73 -56
- 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 +98 -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 +11 -9
- 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/traversal.d.ts +4 -1
- package/dist/traversal.d.ts.map +1 -1
- package/dist/traversal.js +25 -6
- package/dist/traversal.js.map +1 -1
- package/dist/types.d.ts +26 -14
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/user-event/adjustment.d.ts +3 -0
- package/dist/user-event/adjustment.d.ts.map +1 -1
- package/dist/user-event/adjustment.js +23 -2
- package/dist/user-event/adjustment.js.map +1 -1
- package/dist/user-event/click.d.ts +43 -8
- package/dist/user-event/click.d.ts.map +1 -1
- package/dist/user-event/click.js +175 -44
- 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/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/index.d.ts +51 -10
- 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.map +1 -1
- package/dist/user-event/keyboard.js +33 -4
- 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 +33 -9
- package/dist/user-event/pointer.js.map +1 -1
- package/dist/user-event/selection.d.ts +11 -8
- package/dist/user-event/selection.d.ts.map +1 -1
- package/dist/user-event/selection.js +49 -38
- package/dist/user-event/selection.js.map +1 -1
- package/dist/user-event/text.d.ts +6 -2
- package/dist/user-event/text.d.ts.map +1 -1
- package/dist/user-event/text.js +68 -18
- package/dist/user-event/text.js.map +1 -1
- package/dist/widget-accessible-properties.d.ts +14 -26
- package/dist/widget-accessible-properties.d.ts.map +1 -1
- package/dist/widget-accessible-properties.js +135 -190
- 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 +12 -7
- package/src/accessible-native.ts +333 -0
- package/src/build-queries.ts +47 -41
- package/src/cleanup-registry.ts +1 -1
- package/src/errors.ts +12 -1
- 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 +428 -70
- package/src/pretty-format.ts +1 -0
- package/src/pretty-widget.ts +97 -70
- package/src/production.ts +52 -0
- package/src/queries.ts +127 -89
- package/src/query-helpers.ts +97 -0
- package/src/render-children.ts +25 -0
- package/src/render.tsx +16 -11
- package/src/role-helpers.ts +14 -4
- package/src/role-naming.ts +99 -0
- package/src/screenshot.ts +272 -103
- package/src/traversal.ts +44 -6
- package/src/types.ts +28 -16
- package/src/user-event/adjustment.ts +29 -2
- package/src/user-event/click.ts +247 -52
- package/src/user-event/column-header-click.ts +90 -0
- package/src/user-event/event-wrapper.ts +3 -1
- package/src/user-event/index.ts +100 -37
- package/src/user-event/indexed-children.ts +75 -0
- package/src/user-event/keyboard.ts +52 -4
- 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 +48 -9
- package/src/user-event/selection.ts +67 -41
- package/src/user-event/text.ts +92 -21
- package/src/widget-accessible-properties.ts +183 -230
- package/src/widget-getters.ts +32 -0
- package/src/within.ts +3 -2
package/src/queries.ts
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
getWidgetDescription,
|
|
18
18
|
getWidgetDisplayValue,
|
|
19
19
|
getWidgetExpandedState,
|
|
20
|
-
|
|
20
|
+
getWidgetExternalLabelText,
|
|
21
21
|
getWidgetLabelText,
|
|
22
22
|
getWidgetLevel,
|
|
23
23
|
getWidgetName,
|
|
@@ -25,9 +25,12 @@ import {
|
|
|
25
25
|
getWidgetPlaceholderText,
|
|
26
26
|
getWidgetPressedState,
|
|
27
27
|
getWidgetSelectedState,
|
|
28
|
-
|
|
28
|
+
getWidgetValueText,
|
|
29
29
|
isInaccessible,
|
|
30
30
|
isWidgetChecked,
|
|
31
|
+
isWidgetValueMatch,
|
|
32
|
+
namingLabelText,
|
|
33
|
+
type WidgetValueField,
|
|
31
34
|
} from "./widget-accessible-properties.js";
|
|
32
35
|
|
|
33
36
|
/** The built-in queries in their unbound form, each taking the container to search as its first argument. */
|
|
@@ -37,7 +40,6 @@ const roleQueries = nameQueryFamily(
|
|
|
37
40
|
"Role",
|
|
38
41
|
queryAllByRole,
|
|
39
42
|
buildQueries<[role: Gtk.AccessibleRole, options?: ByRoleOptions]>(
|
|
40
|
-
"Role",
|
|
41
43
|
queryAllByRole,
|
|
42
44
|
(container, matches, role, options) =>
|
|
43
45
|
multipleFoundError(container, { queryType: "role", role, options }, matches),
|
|
@@ -49,7 +51,6 @@ const labelTextQueries = nameQueryFamily(
|
|
|
49
51
|
"LabelText",
|
|
50
52
|
queryAllByLabelText,
|
|
51
53
|
buildQueries<[text: Matcher, options?: MatcherOptions]>(
|
|
52
|
-
"LabelText",
|
|
53
54
|
queryAllByLabelText,
|
|
54
55
|
(container, matches, text) => multipleFoundError(container, { queryType: "labelText", text }, matches),
|
|
55
56
|
(container, text) => notFoundError(container, { queryType: "labelText", text }),
|
|
@@ -60,7 +61,6 @@ const textQueries = nameQueryFamily(
|
|
|
60
61
|
"Text",
|
|
61
62
|
queryAllByText,
|
|
62
63
|
buildQueries<[text: Matcher, options?: MatcherOptions]>(
|
|
63
|
-
"Text",
|
|
64
64
|
queryAllByText,
|
|
65
65
|
(container, matches, text) => multipleFoundError(container, { queryType: "text", text }, matches),
|
|
66
66
|
(container, text) => notFoundError(container, { queryType: "text", text }),
|
|
@@ -71,7 +71,6 @@ const nameQueries = nameQueryFamily(
|
|
|
71
71
|
"Name",
|
|
72
72
|
queryAllByName,
|
|
73
73
|
buildQueries<[name: Matcher, options?: MatcherOptions]>(
|
|
74
|
-
"Name",
|
|
75
74
|
queryAllByName,
|
|
76
75
|
(container, matches, name) => multipleFoundError(container, { queryType: "name", name }, matches),
|
|
77
76
|
(container, name) => notFoundError(container, { queryType: "name", name }),
|
|
@@ -82,7 +81,6 @@ const placeholderTextQueries = nameQueryFamily(
|
|
|
82
81
|
"PlaceholderText",
|
|
83
82
|
queryAllByPlaceholderText,
|
|
84
83
|
buildQueries<[text: Matcher, options?: MatcherOptions]>(
|
|
85
|
-
"PlaceholderText",
|
|
86
84
|
queryAllByPlaceholderText,
|
|
87
85
|
(container, matches, text) => multipleFoundError(container, { queryType: "placeholderText", text }, matches),
|
|
88
86
|
(container, text) => notFoundError(container, { queryType: "placeholderText", text }),
|
|
@@ -93,7 +91,6 @@ const displayValueQueries = nameQueryFamily(
|
|
|
93
91
|
"DisplayValue",
|
|
94
92
|
queryAllByDisplayValue,
|
|
95
93
|
buildQueries<[value: Matcher, options?: MatcherOptions]>(
|
|
96
|
-
"DisplayValue",
|
|
97
94
|
queryAllByDisplayValue,
|
|
98
95
|
(container, matches, value) => multipleFoundError(container, { queryType: "displayValue", value }, matches),
|
|
99
96
|
(container, value) => notFoundError(container, { queryType: "displayValue", value }),
|
|
@@ -110,120 +107,159 @@ const builtinQueries = {
|
|
|
110
107
|
} as BuiltinQueries;
|
|
111
108
|
|
|
112
109
|
/**
|
|
113
|
-
* Returns the single widget with a matching accessible role and options, or null when none
|
|
114
|
-
* Throws when more than one matches.
|
|
110
|
+
* Returns the single mapped widget with a matching accessible role and options, or null when none
|
|
111
|
+
* match. Widgets that are not mapped are never matched. Throws when more than one matches.
|
|
115
112
|
*/
|
|
116
113
|
const queryByRole: BuiltinQueries["queryByRole"] = builtinQueries.queryByRole;
|
|
117
|
-
/**
|
|
114
|
+
/**
|
|
115
|
+
* Returns every mapped widget with a matching accessible role and options. Widgets that are not
|
|
116
|
+
* mapped are never matched. Throws when none match.
|
|
117
|
+
*/
|
|
118
118
|
const getAllByRole: BuiltinQueries["getAllByRole"] = builtinQueries.getAllByRole;
|
|
119
119
|
/**
|
|
120
|
-
* Returns the single widget with a matching accessible role and options.
|
|
121
|
-
* Throws when none or more than one matches.
|
|
120
|
+
* Returns the single mapped widget with a matching accessible role and options. Widgets that are not
|
|
121
|
+
* mapped are never matched. Throws when none or more than one matches.
|
|
122
122
|
*/
|
|
123
123
|
const getByRole: BuiltinQueries["getByRole"] = builtinQueries.getByRole;
|
|
124
124
|
/**
|
|
125
|
-
* Waits for and returns every widget with a matching accessible role and options, retrying
|
|
126
|
-
* least one appears or the timeout elapses.
|
|
125
|
+
* Waits for and returns every mapped widget with a matching accessible role and options, retrying
|
|
126
|
+
* until at least one appears or the timeout elapses. Widgets that are not mapped are never matched.
|
|
127
127
|
*/
|
|
128
128
|
const findAllByRole: BuiltinQueries["findAllByRole"] = builtinQueries.findAllByRole;
|
|
129
129
|
/**
|
|
130
|
-
* Waits for and returns the single widget with a matching accessible role and options,
|
|
131
|
-
* until it appears or the timeout elapses.
|
|
130
|
+
* Waits for and returns the single mapped widget with a matching accessible role and options,
|
|
131
|
+
* retrying until it appears or the timeout elapses. Widgets that are not mapped are never matched.
|
|
132
|
+
* Rejects when none or more than one matches.
|
|
132
133
|
*/
|
|
133
134
|
const findByRole: BuiltinQueries["findByRole"] = builtinQueries.findByRole;
|
|
134
135
|
/**
|
|
135
|
-
* Returns the single widget with matching associated label text, or null when none match.
|
|
136
|
-
* Throws when more than one matches.
|
|
136
|
+
* Returns the single mapped widget with matching associated label text, or null when none match.
|
|
137
|
+
* Widgets that are not mapped are never matched. Throws when more than one matches.
|
|
137
138
|
*/
|
|
138
139
|
const queryByLabelText: BuiltinQueries["queryByLabelText"] = builtinQueries.queryByLabelText;
|
|
139
|
-
/**
|
|
140
|
+
/**
|
|
141
|
+
* Returns every mapped widget with matching associated label text. Widgets that are not mapped are
|
|
142
|
+
* never matched. Throws when none match.
|
|
143
|
+
*/
|
|
140
144
|
const getAllByLabelText: BuiltinQueries["getAllByLabelText"] = builtinQueries.getAllByLabelText;
|
|
141
|
-
/**
|
|
145
|
+
/**
|
|
146
|
+
* Returns the single mapped widget with matching associated label text. Widgets that are not mapped
|
|
147
|
+
* are never matched. Throws when none or more than one matches.
|
|
148
|
+
*/
|
|
142
149
|
const getByLabelText: BuiltinQueries["getByLabelText"] = builtinQueries.getByLabelText;
|
|
143
150
|
/**
|
|
144
|
-
* Waits for and returns every widget with matching associated label text, retrying until at
|
|
145
|
-
* one appears or the timeout elapses.
|
|
151
|
+
* Waits for and returns every mapped widget with matching associated label text, retrying until at
|
|
152
|
+
* least one appears or the timeout elapses. Widgets that are not mapped are never matched.
|
|
146
153
|
*/
|
|
147
154
|
const findAllByLabelText: BuiltinQueries["findAllByLabelText"] = builtinQueries.findAllByLabelText;
|
|
148
155
|
/**
|
|
149
|
-
* Waits for and returns the single widget with matching associated label text, retrying until
|
|
150
|
-
* appears or the timeout elapses.
|
|
156
|
+
* Waits for and returns the single mapped widget with matching associated label text, retrying until
|
|
157
|
+
* it appears or the timeout elapses. Widgets that are not mapped are never matched. Rejects when
|
|
158
|
+
* none or more than one matches.
|
|
151
159
|
*/
|
|
152
160
|
const findByLabelText: BuiltinQueries["findByLabelText"] = builtinQueries.findByLabelText;
|
|
153
161
|
/**
|
|
154
|
-
* Returns the single widget with matching rendered text content, or null when none match.
|
|
155
|
-
* Throws when more than one matches.
|
|
162
|
+
* Returns the single mapped widget with matching rendered text content, or null when none match.
|
|
163
|
+
* Widgets that are not mapped are never matched. Throws when more than one matches.
|
|
156
164
|
*/
|
|
157
165
|
const queryByText: BuiltinQueries["queryByText"] = builtinQueries.queryByText;
|
|
158
|
-
/**
|
|
166
|
+
/**
|
|
167
|
+
* Returns every mapped widget with matching rendered text content. Widgets that are not mapped are
|
|
168
|
+
* never matched. Throws when none match.
|
|
169
|
+
*/
|
|
159
170
|
const getAllByText: BuiltinQueries["getAllByText"] = builtinQueries.getAllByText;
|
|
160
|
-
/**
|
|
171
|
+
/**
|
|
172
|
+
* Returns the single mapped widget with matching rendered text content. Widgets that are not mapped
|
|
173
|
+
* are never matched. Throws when none or more than one matches.
|
|
174
|
+
*/
|
|
161
175
|
const getByText: BuiltinQueries["getByText"] = builtinQueries.getByText;
|
|
162
176
|
/**
|
|
163
|
-
* Waits for and returns every widget with matching rendered text content, retrying until at
|
|
164
|
-
* one appears or the timeout elapses.
|
|
177
|
+
* Waits for and returns every mapped widget with matching rendered text content, retrying until at
|
|
178
|
+
* least one appears or the timeout elapses. Widgets that are not mapped are never matched.
|
|
165
179
|
*/
|
|
166
180
|
const findAllByText: BuiltinQueries["findAllByText"] = builtinQueries.findAllByText;
|
|
167
181
|
/**
|
|
168
|
-
* Waits for and returns the single widget with matching rendered text content, retrying until
|
|
169
|
-
* appears or the timeout elapses.
|
|
182
|
+
* Waits for and returns the single mapped widget with matching rendered text content, retrying until
|
|
183
|
+
* it appears or the timeout elapses. Widgets that are not mapped are never matched. Rejects when
|
|
184
|
+
* none or more than one matches.
|
|
170
185
|
*/
|
|
171
186
|
const findByText: BuiltinQueries["findByText"] = builtinQueries.findByText;
|
|
172
187
|
/**
|
|
173
|
-
* Returns the single widget with a matching widget name, or null when none match.
|
|
174
|
-
* Throws when more than one matches.
|
|
188
|
+
* Returns the single mapped widget with a matching widget name, or null when none match. Widgets
|
|
189
|
+
* that are not mapped are never matched. Throws when more than one matches.
|
|
175
190
|
*/
|
|
176
191
|
const queryByName: BuiltinQueries["queryByName"] = builtinQueries.queryByName;
|
|
177
|
-
/**
|
|
192
|
+
/**
|
|
193
|
+
* Returns every mapped widget with a matching widget name. Widgets that are not mapped are never
|
|
194
|
+
* matched. Throws when none match.
|
|
195
|
+
*/
|
|
178
196
|
const getAllByName: BuiltinQueries["getAllByName"] = builtinQueries.getAllByName;
|
|
179
|
-
/**
|
|
197
|
+
/**
|
|
198
|
+
* Returns the single mapped widget with a matching widget name. Widgets that are not mapped are
|
|
199
|
+
* never matched. Throws when none or more than one matches.
|
|
200
|
+
*/
|
|
180
201
|
const getByName: BuiltinQueries["getByName"] = builtinQueries.getByName;
|
|
181
202
|
/**
|
|
182
|
-
* Waits for and returns every widget with a matching widget name, retrying until at least one
|
|
183
|
-
* appears or the timeout elapses.
|
|
203
|
+
* Waits for and returns every mapped widget with a matching widget name, retrying until at least one
|
|
204
|
+
* appears or the timeout elapses. Widgets that are not mapped are never matched.
|
|
184
205
|
*/
|
|
185
206
|
const findAllByName: BuiltinQueries["findAllByName"] = builtinQueries.findAllByName;
|
|
186
207
|
/**
|
|
187
|
-
* Waits for and returns the single widget with a matching widget name, retrying until it
|
|
188
|
-
* the timeout elapses.
|
|
208
|
+
* Waits for and returns the single mapped widget with a matching widget name, retrying until it
|
|
209
|
+
* appears or the timeout elapses. Widgets that are not mapped are never matched. Rejects when none
|
|
210
|
+
* or more than one matches.
|
|
189
211
|
*/
|
|
190
212
|
const findByName: BuiltinQueries["findByName"] = builtinQueries.findByName;
|
|
191
213
|
/**
|
|
192
|
-
* Returns the single widget with matching placeholder text, or null when none match.
|
|
193
|
-
* Throws when more than one matches.
|
|
214
|
+
* Returns the single mapped widget with matching placeholder text, or null when none match. Widgets
|
|
215
|
+
* that are not mapped are never matched. Throws when more than one matches.
|
|
194
216
|
*/
|
|
195
217
|
const queryByPlaceholderText: BuiltinQueries["queryByPlaceholderText"] = builtinQueries.queryByPlaceholderText;
|
|
196
|
-
/**
|
|
218
|
+
/**
|
|
219
|
+
* Returns every mapped widget with matching placeholder text. Widgets that are not mapped are never
|
|
220
|
+
* matched. Throws when none match.
|
|
221
|
+
*/
|
|
197
222
|
const getAllByPlaceholderText: BuiltinQueries["getAllByPlaceholderText"] = builtinQueries.getAllByPlaceholderText;
|
|
198
|
-
/**
|
|
223
|
+
/**
|
|
224
|
+
* Returns the single mapped widget with matching placeholder text. Widgets that are not mapped are
|
|
225
|
+
* never matched. Throws when none or more than one matches.
|
|
226
|
+
*/
|
|
199
227
|
const getByPlaceholderText: BuiltinQueries["getByPlaceholderText"] = builtinQueries.getByPlaceholderText;
|
|
200
228
|
/**
|
|
201
|
-
* Waits for and returns every widget with matching placeholder text, retrying until at least
|
|
202
|
-
* appears or the timeout elapses.
|
|
229
|
+
* Waits for and returns every mapped widget with matching placeholder text, retrying until at least
|
|
230
|
+
* one appears or the timeout elapses. Widgets that are not mapped are never matched.
|
|
203
231
|
*/
|
|
204
232
|
const findAllByPlaceholderText: BuiltinQueries["findAllByPlaceholderText"] = builtinQueries.findAllByPlaceholderText;
|
|
205
233
|
/**
|
|
206
|
-
* Waits for and returns the single widget with matching placeholder text, retrying until it
|
|
207
|
-
* or the timeout elapses.
|
|
234
|
+
* Waits for and returns the single mapped widget with matching placeholder text, retrying until it
|
|
235
|
+
* appears or the timeout elapses. Widgets that are not mapped are never matched. Rejects when none
|
|
236
|
+
* or more than one matches.
|
|
208
237
|
*/
|
|
209
238
|
const findByPlaceholderText: BuiltinQueries["findByPlaceholderText"] = builtinQueries.findByPlaceholderText;
|
|
210
239
|
/**
|
|
211
|
-
* Returns the single widget with a matching display value, or null when none match.
|
|
212
|
-
* Throws when more than one matches.
|
|
240
|
+
* Returns the single mapped widget with a matching display value, or null when none match. Widgets
|
|
241
|
+
* that are not mapped are never matched. Throws when more than one matches.
|
|
213
242
|
*/
|
|
214
243
|
const queryByDisplayValue: BuiltinQueries["queryByDisplayValue"] = builtinQueries.queryByDisplayValue;
|
|
215
|
-
/**
|
|
244
|
+
/**
|
|
245
|
+
* Returns every mapped widget with a matching display value. Widgets that are not mapped are never
|
|
246
|
+
* matched. Throws when none match.
|
|
247
|
+
*/
|
|
216
248
|
const getAllByDisplayValue: BuiltinQueries["getAllByDisplayValue"] = builtinQueries.getAllByDisplayValue;
|
|
217
|
-
/**
|
|
249
|
+
/**
|
|
250
|
+
* Returns the single mapped widget with a matching display value. Widgets that are not mapped are
|
|
251
|
+
* never matched. Throws when none or more than one matches.
|
|
252
|
+
*/
|
|
218
253
|
const getByDisplayValue: BuiltinQueries["getByDisplayValue"] = builtinQueries.getByDisplayValue;
|
|
219
254
|
/**
|
|
220
|
-
* Waits for and returns every widget with a matching display value, retrying until at least
|
|
221
|
-
* appears or the timeout elapses.
|
|
255
|
+
* Waits for and returns every mapped widget with a matching display value, retrying until at least
|
|
256
|
+
* one appears or the timeout elapses. Widgets that are not mapped are never matched.
|
|
222
257
|
*/
|
|
223
258
|
const findAllByDisplayValue: BuiltinQueries["findAllByDisplayValue"] = builtinQueries.findAllByDisplayValue;
|
|
224
259
|
/**
|
|
225
|
-
* Waits for and returns the single widget with a matching display value, retrying until it
|
|
226
|
-
* or the timeout elapses.
|
|
260
|
+
* Waits for and returns the single mapped widget with a matching display value, retrying until it
|
|
261
|
+
* appears or the timeout elapses. Widgets that are not mapped are never matched. Rejects when none
|
|
262
|
+
* or more than one matches.
|
|
227
263
|
*/
|
|
228
264
|
const findByDisplayValue: BuiltinQueries["findByDisplayValue"] = builtinQueries.findByDisplayValue;
|
|
229
265
|
|
|
@@ -291,25 +327,23 @@ const hasMatchingAccessibleName = (widget: Gtk.Widget, options: ByRoleOptions):
|
|
|
291
327
|
return isTextMatch(text, options.name, widget, options);
|
|
292
328
|
};
|
|
293
329
|
|
|
294
|
-
const isNumericValueMatch = (
|
|
295
|
-
expected === undefined ||
|
|
330
|
+
const isNumericValueMatch = (widget: Gtk.Widget, field: WidgetValueField, expected: number | undefined): boolean =>
|
|
331
|
+
expected === undefined || isWidgetValueMatch(widget, field, expected);
|
|
296
332
|
|
|
297
333
|
const hasMatchingAccessibleValue = (widget: Gtk.Widget, value: ByRoleValue, options: ByRoleOptions): boolean => {
|
|
298
|
-
const
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
[
|
|
302
|
-
[value.min, actual.min],
|
|
303
|
-
[value.max, actual.max],
|
|
334
|
+
const numericChecks: [WidgetValueField, number | undefined][] = [
|
|
335
|
+
["now", value.now],
|
|
336
|
+
["min", value.min],
|
|
337
|
+
["max", value.max],
|
|
304
338
|
];
|
|
305
339
|
|
|
306
|
-
for (const [
|
|
307
|
-
if (!isNumericValueMatch(
|
|
340
|
+
for (const [field, expected] of numericChecks) {
|
|
341
|
+
if (!isNumericValueMatch(widget, field, expected)) {
|
|
308
342
|
return false;
|
|
309
343
|
}
|
|
310
344
|
}
|
|
311
345
|
|
|
312
|
-
return value.text === undefined || isTextMatch(
|
|
346
|
+
return value.text === undefined || isTextMatch(getWidgetValueText(widget), value.text, widget, options);
|
|
313
347
|
};
|
|
314
348
|
|
|
315
349
|
const hasMatchingBooleanStates = (widget: Gtk.Widget, options: ByRoleOptions): boolean => {
|
|
@@ -366,19 +400,22 @@ function nameQueryFamily<Args extends unknown[]>(
|
|
|
366
400
|
queryAllBy: QueryAllBy<Args>,
|
|
367
401
|
built: BuiltQueries<Args>,
|
|
368
402
|
): Record<string, unknown> {
|
|
403
|
+
const [queryBy, getAllBy, getBy, findAllBy, findBy] = built;
|
|
404
|
+
|
|
369
405
|
return {
|
|
370
|
-
[`queryBy${suffix}`]:
|
|
406
|
+
[`queryBy${suffix}`]: queryBy,
|
|
371
407
|
[`queryAllBy${suffix}`]: queryAllBy,
|
|
372
|
-
[`getBy${suffix}`]:
|
|
373
|
-
[`getAllBy${suffix}`]:
|
|
374
|
-
[`findBy${suffix}`]:
|
|
375
|
-
[`findAllBy${suffix}`]:
|
|
408
|
+
[`getBy${suffix}`]: getBy,
|
|
409
|
+
[`getAllBy${suffix}`]: getAllBy,
|
|
410
|
+
[`findBy${suffix}`]: findBy,
|
|
411
|
+
[`findAllBy${suffix}`]: findAllBy,
|
|
376
412
|
};
|
|
377
413
|
}
|
|
378
414
|
|
|
379
415
|
/**
|
|
380
416
|
* Finds every widget under the container whose accessible role matches `role` and that satisfies the given options.
|
|
381
|
-
* Widgets excluded from the accessibility tree are
|
|
417
|
+
* Widgets that are not mapped are never matched, and widgets excluded from the accessibility tree are
|
|
418
|
+
* skipped unless `options.hidden` is set.
|
|
382
419
|
* @param container Widget subtree to search.
|
|
383
420
|
* @param role Accessible role to match.
|
|
384
421
|
* @param options Additional accessible name, state, and value constraints.
|
|
@@ -411,7 +448,7 @@ const collectMnemonicMatch = (
|
|
|
411
448
|
return null;
|
|
412
449
|
}
|
|
413
450
|
|
|
414
|
-
const labelText = widget
|
|
451
|
+
const labelText = namingLabelText(widget);
|
|
415
452
|
|
|
416
453
|
if (!labelText || !isTextMatch(labelText, text, widget, options)) {
|
|
417
454
|
return null;
|
|
@@ -420,6 +457,12 @@ const collectMnemonicMatch = (
|
|
|
420
457
|
return widget.getMnemonicWidget();
|
|
421
458
|
};
|
|
422
459
|
|
|
460
|
+
const labellingText = (widget: Gtk.Widget): string | null => {
|
|
461
|
+
const ownLabel = widget.getAccessibleRole() === Gtk.AccessibleRole.LABEL ? null : getWidgetOwnLabel(widget);
|
|
462
|
+
|
|
463
|
+
return ownLabel ?? getWidgetExternalLabelText(widget);
|
|
464
|
+
};
|
|
465
|
+
|
|
423
466
|
const collectLabelMatches = (
|
|
424
467
|
results: Set<Gtk.Widget>,
|
|
425
468
|
widget: Gtk.Widget,
|
|
@@ -432,22 +475,16 @@ const collectLabelMatches = (
|
|
|
432
475
|
results.add(mnemonicTarget);
|
|
433
476
|
}
|
|
434
477
|
|
|
435
|
-
const
|
|
436
|
-
|
|
437
|
-
if (ownLabel !== null && isTextMatch(ownLabel, text, widget, options)) {
|
|
438
|
-
results.add(widget);
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
const labelledByText = getWidgetLabelledByText(widget);
|
|
478
|
+
const labelText = labellingText(widget);
|
|
442
479
|
|
|
443
|
-
if (
|
|
480
|
+
if (labelText !== null && isTextMatch(labelText, text, widget, options)) {
|
|
444
481
|
results.add(widget);
|
|
445
482
|
}
|
|
446
483
|
};
|
|
447
484
|
|
|
448
485
|
/**
|
|
449
486
|
* Finds every widget associated with a label whose text matches: a Gtk.Label mnemonic target, the
|
|
450
|
-
* widget's own accessible label, or its labelled-by relation.
|
|
487
|
+
* widget's own accessible label, or its labelled-by relation. Widgets that are not mapped are never matched.
|
|
451
488
|
* @param container Widget subtree to search.
|
|
452
489
|
* @param text Matcher for the label text.
|
|
453
490
|
* @param options Text matching options.
|
|
@@ -464,7 +501,7 @@ function queryAllByLabelText(container: Container, text: Matcher, options?: Matc
|
|
|
464
501
|
}
|
|
465
502
|
|
|
466
503
|
/**
|
|
467
|
-
* Finds every widget whose rendered text content matches.
|
|
504
|
+
* Finds every widget whose rendered text content matches. Widgets that are not mapped are never matched.
|
|
468
505
|
* @param container Widget subtree to search.
|
|
469
506
|
* @param text Matcher for the widget text.
|
|
470
507
|
* @param options Text matching options.
|
|
@@ -479,7 +516,7 @@ function queryAllByText(container: Container, text: Matcher, options?: MatcherOp
|
|
|
479
516
|
}
|
|
480
517
|
|
|
481
518
|
/**
|
|
482
|
-
* Finds every widget whose widget name matches.
|
|
519
|
+
* Finds every widget whose widget name matches. Widgets that are not mapped are never matched.
|
|
483
520
|
* @param container Widget subtree to search.
|
|
484
521
|
* @param name Matcher for the widget name.
|
|
485
522
|
* @param options Text matching options.
|
|
@@ -493,7 +530,7 @@ function queryAllByName(container: Container, name: Matcher, options?: MatcherOp
|
|
|
493
530
|
}
|
|
494
531
|
|
|
495
532
|
/**
|
|
496
|
-
* Finds every widget whose placeholder text matches.
|
|
533
|
+
* Finds every widget whose placeholder text matches. Widgets that are not mapped are never matched.
|
|
497
534
|
* @param container Widget subtree to search.
|
|
498
535
|
* @param text Matcher for the placeholder text.
|
|
499
536
|
* @param options Text matching options.
|
|
@@ -513,7 +550,7 @@ function queryAllByPlaceholderText(
|
|
|
513
550
|
}
|
|
514
551
|
|
|
515
552
|
/**
|
|
516
|
-
* Finds every widget whose current display value matches.
|
|
553
|
+
* Finds every widget whose current display value matches. Widgets that are not mapped are never matched.
|
|
517
554
|
* @param container Widget subtree to search.
|
|
518
555
|
* @param value Matcher for the display value.
|
|
519
556
|
* @param options Text matching options.
|
|
@@ -530,6 +567,8 @@ function queryAllByDisplayValue(container: Container, value: Matcher, options?:
|
|
|
530
567
|
|
|
531
568
|
export {
|
|
532
569
|
builtinQueries,
|
|
570
|
+
isMatchingWidgetType,
|
|
571
|
+
isTextMatch,
|
|
533
572
|
queryByRole,
|
|
534
573
|
getAllByRole,
|
|
535
574
|
getByRole,
|
|
@@ -566,5 +605,4 @@ export {
|
|
|
566
605
|
queryAllByName,
|
|
567
606
|
queryAllByPlaceholderText,
|
|
568
607
|
queryAllByDisplayValue,
|
|
569
|
-
type BuiltinQueries,
|
|
570
608
|
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type * as Gtk from "@gtkx/gi/gtk";
|
|
2
|
+
import { camelCase } from "@gtkx/utils";
|
|
3
|
+
import type { Matcher, MatcherOptions } from "./types.js";
|
|
4
|
+
import { buildQueries } from "./build-queries.js";
|
|
5
|
+
import { getElementError } from "./errors.js";
|
|
6
|
+
import { isMatchingWidgetType, isTextMatch } from "./queries.js";
|
|
7
|
+
import { type Container, findAll } from "./traversal.js";
|
|
8
|
+
|
|
9
|
+
/** The helpers used to build custom queries, bundled the way DOM Testing Library exposes them. */
|
|
10
|
+
type QueryHelpers = {
|
|
11
|
+
/** Derives a query family's variants from its `queryAllBy` function. */
|
|
12
|
+
buildQueries: typeof buildQueries;
|
|
13
|
+
/** Builds the error a failing query throws. */
|
|
14
|
+
getElementError: typeof getElementError;
|
|
15
|
+
/** Finds every widget whose GObject property matches. */
|
|
16
|
+
queryAllByObjectProperty: typeof queryAllByObjectProperty;
|
|
17
|
+
/** Finds the single widget whose GObject property matches. */
|
|
18
|
+
queryByObjectProperty: typeof queryByObjectProperty;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/** The query-building helpers, bundled so they can be reached under a single import. */
|
|
22
|
+
const queryHelpers: QueryHelpers = {
|
|
23
|
+
buildQueries,
|
|
24
|
+
getElementError,
|
|
25
|
+
queryAllByObjectProperty,
|
|
26
|
+
queryByObjectProperty,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const readObjectProperty = (widget: Gtk.Widget, property: string): string | null => {
|
|
30
|
+
const value: unknown = Reflect.get(widget, camelCase(property));
|
|
31
|
+
|
|
32
|
+
if (typeof value === "string") {
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
37
|
+
return String(value);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return null;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Finds every widget carrying a GObject property whose value matches, the counterpart of DOM Testing
|
|
45
|
+
* Library's `queryAllByAttribute`. The property name may be given in kebab-case or camelCase, and
|
|
46
|
+
* widgets that are not mapped are never matched.
|
|
47
|
+
*
|
|
48
|
+
* @param property Name of the GObject property to read.
|
|
49
|
+
* @param container Widget subtree to search.
|
|
50
|
+
* @param text Matcher for the property's value.
|
|
51
|
+
* @param options Text matching options.
|
|
52
|
+
* @returns Every matching widget, or an empty array when none match.
|
|
53
|
+
*/
|
|
54
|
+
function queryAllByObjectProperty(
|
|
55
|
+
property: string,
|
|
56
|
+
container: Container,
|
|
57
|
+
text: Matcher,
|
|
58
|
+
options?: MatcherOptions,
|
|
59
|
+
): Gtk.Widget[] {
|
|
60
|
+
return findAll(
|
|
61
|
+
container,
|
|
62
|
+
(widget) =>
|
|
63
|
+
isMatchingWidgetType(widget, options) &&
|
|
64
|
+
isTextMatch(readObjectProperty(widget, property), text, widget, options),
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Returns the single widget carrying a GObject property whose value matches, or null when none do,
|
|
70
|
+
* the counterpart of DOM Testing Library's `queryByAttribute`.
|
|
71
|
+
*
|
|
72
|
+
* @param property Name of the GObject property to read.
|
|
73
|
+
* @param container Widget subtree to search.
|
|
74
|
+
* @param text Matcher for the property's value.
|
|
75
|
+
* @param options Text matching options.
|
|
76
|
+
* @returns The matching widget, or null when none match.
|
|
77
|
+
* @throws When more than one widget matches.
|
|
78
|
+
*/
|
|
79
|
+
function queryByObjectProperty(
|
|
80
|
+
property: string,
|
|
81
|
+
container: Container,
|
|
82
|
+
text: Matcher,
|
|
83
|
+
options?: MatcherOptions,
|
|
84
|
+
): Gtk.Widget | null {
|
|
85
|
+
const matches = queryAllByObjectProperty(property, container, text, options);
|
|
86
|
+
|
|
87
|
+
if (matches.length > 1) {
|
|
88
|
+
throw getElementError(
|
|
89
|
+
`Found ${String(matches.length)} elements with the '${property}' property, but expected only one`,
|
|
90
|
+
container,
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return matches[0] ?? null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export { queryAllByObjectProperty, queryByObjectProperty, queryHelpers, type QueryHelpers };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import type { RenderOptions } from "./types.js";
|
|
3
|
+
import { render } from "./render.js";
|
|
4
|
+
|
|
5
|
+
type ChildrenBuilder<T> = (items: T[]) => ReactNode;
|
|
6
|
+
|
|
7
|
+
type RenderChildrenResult<T> = {
|
|
8
|
+
rerender: (items: T[]) => Promise<void>;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
async function renderChildren<T>(
|
|
12
|
+
initial: T[],
|
|
13
|
+
build: ChildrenBuilder<T>,
|
|
14
|
+
options?: RenderOptions,
|
|
15
|
+
): Promise<RenderChildrenResult<T>> {
|
|
16
|
+
const { rerender } = await render(build(initial), options);
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
rerender: async (items: T[]) => {
|
|
20
|
+
await rerender(build(items));
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export { renderChildren, type ChildrenBuilder };
|
package/src/render.tsx
CHANGED
|
@@ -5,23 +5,28 @@ import {
|
|
|
5
5
|
isRootElement,
|
|
6
6
|
type ReconcilerRoot,
|
|
7
7
|
setReconcilerErrorHandler,
|
|
8
|
+
settleAccessible,
|
|
8
9
|
} from "@gtkx/react/internal";
|
|
9
10
|
import { type ErrorInfo, type ReactNode, StrictMode } from "react";
|
|
10
11
|
import type { RenderResult } from "./bound-queries.js";
|
|
11
|
-
import type { QueryMap, RenderOptions, ScreenshotOptions
|
|
12
|
+
import type { QueryMap, RenderOptions, ScreenshotOptions } from "./types.js";
|
|
12
13
|
import { runInAct } from "./act.js";
|
|
13
14
|
import { addToCleanupQueue, runCleanup } from "./cleanup-registry.js";
|
|
14
15
|
import { scheduleAfterLayout } from "./frame-sync.js";
|
|
16
|
+
import { createHarnessWindow } from "./harness-window.js";
|
|
15
17
|
import { logWidget, type PrettyWidgetOptions } from "./pretty-widget.js";
|
|
16
18
|
import { logRoles } from "./role-helpers.js";
|
|
17
19
|
import { clearScreen, setScreen } from "./screen.js";
|
|
18
|
-
import {
|
|
19
|
-
import { type Container,
|
|
20
|
+
import { captureScreen } from "./screenshot.js";
|
|
21
|
+
import { type Container, roots, TOPLEVELS } from "./traversal.js";
|
|
20
22
|
import { resetClipboard } from "./user-event/index.js";
|
|
21
23
|
import { within } from "./within.js";
|
|
22
24
|
|
|
25
|
+
/** A mounted render tracked so cleanup can unmount it. */
|
|
23
26
|
type ActiveRender = {
|
|
27
|
+
/** Root that rerenders drive and that cleanup tears the tree down through. */
|
|
24
28
|
root: ReconcilerRoot;
|
|
29
|
+
/** Harness window created for the render, null when it renders into a container the caller supplied. */
|
|
25
30
|
window: Gtk.Window | null;
|
|
26
31
|
};
|
|
27
32
|
|
|
@@ -37,12 +42,13 @@ type ReconcilerErrorState = {
|
|
|
37
42
|
|
|
38
43
|
const reconcilerErrors: ReconcilerErrorState = { lastError: null, isHandlerInstalled: false };
|
|
39
44
|
const activeRenders: Set<ActiveRender> = new Set();
|
|
40
|
-
const HARNESS_WINDOW_WIDTH = 800;
|
|
41
|
-
const HARNESS_WINDOW_HEIGHT = 600;
|
|
42
45
|
|
|
43
46
|
const flushLayout = (window: Gtk.Window | null): Promise<void> =>
|
|
44
|
-
new Promise((resolve) => {
|
|
45
|
-
scheduleAfterLayout(window,
|
|
47
|
+
new Promise<void>((resolve) => {
|
|
48
|
+
scheduleAfterLayout(window, () => {
|
|
49
|
+
settleAccessible();
|
|
50
|
+
resolve();
|
|
51
|
+
});
|
|
46
52
|
});
|
|
47
53
|
|
|
48
54
|
const update = async (element: ReactNode, root: ReconcilerRoot): Promise<void> => {
|
|
@@ -96,7 +102,7 @@ const resolveContainer = (container: RenderOptions["container"]): ResolvedContai
|
|
|
96
102
|
return { containerInfo: container, window: null };
|
|
97
103
|
}
|
|
98
104
|
|
|
99
|
-
const window =
|
|
105
|
+
const window = createHarnessWindow();
|
|
100
106
|
window.setDecorated(false);
|
|
101
107
|
|
|
102
108
|
return { containerInfo: window, window };
|
|
@@ -107,7 +113,7 @@ const firstToplevelWidget = (baseElement: Container): Gtk.Widget => {
|
|
|
107
113
|
return baseElement;
|
|
108
114
|
}
|
|
109
115
|
|
|
110
|
-
const [first] =
|
|
116
|
+
const [first] = roots(baseElement);
|
|
111
117
|
|
|
112
118
|
if (first) {
|
|
113
119
|
return first;
|
|
@@ -209,8 +215,7 @@ const render = async <Q extends QueryMap = Record<never, never>>(
|
|
|
209
215
|
logRoles: () => {
|
|
210
216
|
logRoles(baseElement);
|
|
211
217
|
},
|
|
212
|
-
screenshot: (
|
|
213
|
-
captureAndSaveScreenshot(selector, screenshotOptions),
|
|
218
|
+
screenshot: (screenshotOptions?: ScreenshotOptions) => captureScreen(screenshotOptions),
|
|
214
219
|
};
|
|
215
220
|
|
|
216
221
|
setScreen(result);
|