@gtkx/testing 1.0.0-rc.4 → 1.1.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/act.d.ts +1 -3
- package/dist/act.d.ts.map +1 -1
- package/dist/act.js +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 +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/config.d.ts +8 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- 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 +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 +3 -2
- package/dist/frame-sync.d.ts.map +1 -1
- package/dist/frame-sync.js +19 -9
- package/dist/frame-sync.js.map +1 -1
- package/dist/harness-window.d.ts +5 -0
- package/dist/harness-window.d.ts.map +1 -0
- package/dist/harness-window.js +17 -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 +5 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +5 -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 +178 -20
- 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 +75 -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 +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 +12 -1
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +52 -16
- 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 +15 -5
- 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 +179 -93
- package/dist/screenshot.js.map +1 -1
- package/dist/timers.d.ts +9 -0
- package/dist/timers.d.ts.map +1 -0
- package/dist/timers.js +21 -0
- package/dist/timers.js.map +1 -0
- package/dist/traversal.d.ts +7 -1
- package/dist/traversal.d.ts.map +1 -1
- package/dist/traversal.js +40 -6
- package/dist/traversal.js.map +1 -1
- package/dist/types.d.ts +32 -15
- 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 +25 -3
- package/dist/user-event/adjustment.js.map +1 -1
- package/dist/user-event/click.d.ts +44 -8
- package/dist/user-event/click.d.ts.map +1 -1
- package/dist/user-event/click.js +176 -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 +55 -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 +34 -20
- package/dist/user-event/event-wrapper.js.map +1 -1
- package/dist/user-event/index.d.ts +80 -13
- package/dist/user-event/index.d.ts.map +1 -1
- package/dist/user-event/index.js +44 -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 +115 -31
- 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 +38 -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 +36 -0
- package/dist/user-event/native-click.js.map +1 -0
- package/dist/user-event/notebook-tab-click.d.ts +5 -0
- package/dist/user-event/notebook-tab-click.d.ts.map +1 -0
- package/dist/user-event/notebook-tab-click.js +39 -0
- package/dist/user-event/notebook-tab-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 +12 -5
- package/dist/user-event/text.d.ts.map +1 -1
- package/dist/user-event/text.js +151 -46
- package/dist/user-event/text.js.map +1 -1
- package/dist/wait-for.d.ts.map +1 -1
- package/dist/wait-for.js +4 -3
- package/dist/wait-for.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 +11 -0
- package/dist/widget-getters.d.ts.map +1 -0
- package/dist/widget-getters.js +46 -0
- package/dist/widget-getters.js.map +1 -0
- package/dist/window-state.d.ts +10 -0
- package/dist/window-state.d.ts.map +1 -0
- package/dist/window-state.js +41 -0
- package/dist/window-state.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 +21 -8
- package/src/accessible-native.ts +333 -0
- package/src/act.ts +1 -1
- package/src/build-queries.ts +47 -41
- package/src/cleanup-registry.ts +1 -1
- package/src/config.ts +10 -1
- package/src/errors.ts +12 -1
- package/src/fire-event.ts +61 -8
- package/src/frame-sync.ts +30 -9
- package/src/harness-window.ts +23 -0
- package/src/index.ts +18 -11
- package/src/internal.ts +12 -0
- package/src/matchers.ts +457 -72
- package/src/pretty-format.ts +1 -0
- package/src/pretty-widget.ts +98 -70
- package/src/production.ts +51 -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 +77 -17
- package/src/role-helpers.ts +16 -5
- package/src/role-naming.ts +99 -0
- package/src/screenshot.ts +266 -104
- package/src/timers.ts +31 -0
- package/src/traversal.ts +66 -6
- package/src/types.ts +34 -17
- package/src/user-event/adjustment.ts +31 -3
- package/src/user-event/click.ts +248 -52
- package/src/user-event/column-header-click.ts +76 -0
- package/src/user-event/event-wrapper.ts +41 -23
- package/src/user-event/index.ts +130 -40
- package/src/user-event/indexed-children.ts +75 -0
- package/src/user-event/keyboard.ts +161 -43
- package/src/user-event/list-row-click.ts +54 -0
- package/src/user-event/native-click.ts +51 -0
- package/src/user-event/notebook-tab-click.ts +57 -0
- package/src/user-event/pointer.ts +48 -9
- package/src/user-event/selection.ts +67 -41
- package/src/user-event/text.ts +192 -46
- package/src/wait-for.ts +4 -4
- package/src/widget-accessible-properties.ts +183 -230
- package/src/widget-getters.ts +85 -0
- package/src/window-state.ts +70 -0
- package/src/within.ts +3 -2
package/src/matchers.ts
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
import type { SyncExpectationResult } from "@vitest/expect";
|
|
2
2
|
import * as GObject from "@gtkx/gi/gobject";
|
|
3
3
|
import * as Gtk from "@gtkx/gi/gtk";
|
|
4
|
+
import type { ByRoleOptions, Matcher, MatcherOptions } from "./types.js";
|
|
5
|
+
import {
|
|
6
|
+
ACCESSIBLE_NUMBER_TOLERANCE,
|
|
7
|
+
type AccessibleAttributeValue,
|
|
8
|
+
isAccessibleNumberMatch,
|
|
9
|
+
isAccessibleNumberProperty,
|
|
10
|
+
readAccessibleProperty,
|
|
11
|
+
readAccessibleState,
|
|
12
|
+
} from "./accessible-native.js";
|
|
4
13
|
import { getDefaultNormalizer } from "./normalize.js";
|
|
14
|
+
import {
|
|
15
|
+
queryAllByDisplayValue,
|
|
16
|
+
queryAllByLabelText,
|
|
17
|
+
queryAllByPlaceholderText,
|
|
18
|
+
queryAllByRole,
|
|
19
|
+
queryAllByText,
|
|
20
|
+
} from "./queries.js";
|
|
5
21
|
import { formatRole } from "./role-helpers.js";
|
|
22
|
+
import { type Container, descendants } from "./traversal.js";
|
|
6
23
|
import {
|
|
7
24
|
type CheckedState,
|
|
8
25
|
getWidgetAccessibleName,
|
|
@@ -10,20 +27,20 @@ import {
|
|
|
10
27
|
getWidgetDescribedByText,
|
|
11
28
|
getWidgetDisplayValue,
|
|
12
29
|
getWidgetErrorMessage,
|
|
13
|
-
getWidgetExpandedState,
|
|
14
30
|
getWidgetInvalidState,
|
|
15
31
|
getWidgetLabelText,
|
|
16
|
-
getWidgetPlaceholderText,
|
|
17
32
|
getWidgetPressedState,
|
|
18
33
|
getWidgetRequiredState,
|
|
19
|
-
getWidgetSelectedState,
|
|
20
34
|
getWidgetSelection,
|
|
21
35
|
getWidgetTextContent,
|
|
22
|
-
|
|
36
|
+
getWidgetValueNow,
|
|
23
37
|
hasDisplayValue,
|
|
24
38
|
isWidgetDisabled,
|
|
39
|
+
isWidgetValueMatch,
|
|
25
40
|
isWidgetVisible,
|
|
26
41
|
} from "./widget-accessible-properties.js";
|
|
42
|
+
import { getTypeTag } from "./widget-getters.js";
|
|
43
|
+
import { isWindowActivated } from "./window-state.js";
|
|
27
44
|
|
|
28
45
|
/** The expected value for a text matcher: an exact string or a regular expression. */
|
|
29
46
|
type TextExpectation = string | RegExp;
|
|
@@ -40,15 +57,60 @@ type TextContentOptions = {
|
|
|
40
57
|
/** The expected value for a style class: an exact class name or a regular expression. */
|
|
41
58
|
type ClassExpectation = string | RegExp;
|
|
42
59
|
/** The outcome of a matcher: whether it passed, and the failure text built on demand. */
|
|
43
|
-
type MatcherResult =
|
|
60
|
+
type MatcherResult = Pick<SyncExpectationResult, "message" | "pass">;
|
|
61
|
+
|
|
44
62
|
/** The matcher state bound as `this`, supplying the test runner's deep equality check. */
|
|
45
|
-
type MatcherContext = {
|
|
63
|
+
type MatcherContext = {
|
|
64
|
+
/** Compares a received value against an expected one, resolving asymmetric matchers. */
|
|
65
|
+
equals: (actual: unknown, expected: unknown) => boolean;
|
|
66
|
+
};
|
|
67
|
+
|
|
46
68
|
/** Compares text read from the received widget; with no expected value, asserts the text is non-empty. */
|
|
47
69
|
type TextMatcher = (received: unknown, expected?: TextExpectation) => MatcherResult;
|
|
48
70
|
/** Asserts a single state of the received widget, taking no expected value. */
|
|
49
71
|
type StateMatcher = (received: unknown) => MatcherResult;
|
|
72
|
+
/** Trailing arguments of the `ByRole` query family, as a containment matcher takes them. */
|
|
73
|
+
type RoleQueryArgs = [role: Gtk.AccessibleRole, options?: ByRoleOptions];
|
|
74
|
+
/** Trailing arguments of the text-based query families, as a containment matcher takes them. */
|
|
75
|
+
type TextQueryArgs = [text: Matcher, options?: MatcherOptions];
|
|
76
|
+
/** Counts the descendants a query family finds under the received widget. */
|
|
77
|
+
type ContainmentMatcher<Args extends unknown[]> = (received: unknown, ...args: Args) => MatcherResult;
|
|
50
78
|
type TextMatcherContext = { matcherName: string; widget: Gtk.Widget; actual: string | null };
|
|
51
79
|
type ClassArguments = { expected: ClassExpectation[]; isExact: boolean };
|
|
80
|
+
type QueryAll<Args extends unknown[]> = (container: Container, ...args: Args) => Gtk.Widget[];
|
|
81
|
+
|
|
82
|
+
type BooleanAccessibleState =
|
|
83
|
+
Gtk.AccessibleState.BUSY |
|
|
84
|
+
Gtk.AccessibleState.DISABLED |
|
|
85
|
+
Gtk.AccessibleState.EXPANDED |
|
|
86
|
+
Gtk.AccessibleState.HIDDEN |
|
|
87
|
+
Gtk.AccessibleState.SELECTED |
|
|
88
|
+
Gtk.AccessibleState.VISITED;
|
|
89
|
+
|
|
90
|
+
type TristateAccessibleState = Gtk.AccessibleState.CHECKED | Gtk.AccessibleState.PRESSED;
|
|
91
|
+
|
|
92
|
+
type StringAccessibleProperty =
|
|
93
|
+
Gtk.AccessibleProperty.DESCRIPTION |
|
|
94
|
+
Gtk.AccessibleProperty.HELP_TEXT |
|
|
95
|
+
Gtk.AccessibleProperty.KEY_SHORTCUTS |
|
|
96
|
+
Gtk.AccessibleProperty.LABEL |
|
|
97
|
+
Gtk.AccessibleProperty.PLACEHOLDER |
|
|
98
|
+
Gtk.AccessibleProperty.ROLE_DESCRIPTION |
|
|
99
|
+
Gtk.AccessibleProperty.VALUE_TEXT;
|
|
100
|
+
|
|
101
|
+
type BooleanAccessibleProperty =
|
|
102
|
+
Gtk.AccessibleProperty.HAS_POPUP |
|
|
103
|
+
Gtk.AccessibleProperty.MODAL |
|
|
104
|
+
Gtk.AccessibleProperty.MULTI_LINE |
|
|
105
|
+
Gtk.AccessibleProperty.MULTI_SELECTABLE |
|
|
106
|
+
Gtk.AccessibleProperty.READ_ONLY |
|
|
107
|
+
Gtk.AccessibleProperty.REQUIRED;
|
|
108
|
+
|
|
109
|
+
type NumberAccessibleProperty =
|
|
110
|
+
Gtk.AccessibleProperty.LEVEL |
|
|
111
|
+
Gtk.AccessibleProperty.VALUE_MAX |
|
|
112
|
+
Gtk.AccessibleProperty.VALUE_MIN |
|
|
113
|
+
Gtk.AccessibleProperty.VALUE_NOW;
|
|
52
114
|
|
|
53
115
|
/** A text matcher that also takes normalization options for the text it reads. */
|
|
54
116
|
type TextContentMatcher = (
|
|
@@ -72,23 +134,35 @@ type MatcherImplementations = {
|
|
|
72
134
|
toHaveAccessibleDescription: TextMatcher;
|
|
73
135
|
/** Asserts the joined accessible names of the widget's `error-message` targets, read only while it is invalid. */
|
|
74
136
|
toHaveAccessibleErrorMessage: TextMatcher;
|
|
75
|
-
/** Asserts the widget's placeholder text; with no argument, that it has some. */
|
|
76
|
-
toHavePlaceholderText: TextMatcher;
|
|
77
137
|
/** Asserts the text currently selected in an editable widget. */
|
|
78
138
|
toHaveSelection: TextMatcher;
|
|
139
|
+
/**
|
|
140
|
+
* Asserts an accessible state GTK holds for the widget, taking the value type that state carries.
|
|
141
|
+
* With no expected value, asserts only that the state is set to something determinate.
|
|
142
|
+
*/
|
|
143
|
+
toHaveAccessibleState: (
|
|
144
|
+
received: unknown,
|
|
145
|
+
state: Gtk.AccessibleState,
|
|
146
|
+
expected?: boolean | number,
|
|
147
|
+
) => MatcherResult;
|
|
148
|
+
/**
|
|
149
|
+
* Asserts an accessible property GTK holds for the widget, taking the value type that property
|
|
150
|
+
* carries. With no expected value, asserts only that the property is set. Numeric properties
|
|
151
|
+
* compare the way `toHaveValue` and the `value` option of the `ByRole` queries do, within 0.001.
|
|
152
|
+
*/
|
|
153
|
+
toHaveAccessibleProperty: (
|
|
154
|
+
received: unknown,
|
|
155
|
+
property: Gtk.AccessibleProperty,
|
|
156
|
+
expected?: AccessibleAttributeValue,
|
|
157
|
+
) => MatcherResult;
|
|
79
158
|
/** Asserts the widget's checked state is checked rather than unchecked or mixed. */
|
|
80
159
|
toBeChecked: StateMatcher;
|
|
81
160
|
/** Asserts the widget's checked state is mixed. */
|
|
82
161
|
toBePartiallyChecked: StateMatcher;
|
|
83
162
|
/** Asserts a `Gtk.ToggleButton` is active, and throws for any other widget. */
|
|
84
163
|
toBePressed: StateMatcher;
|
|
85
|
-
/** Asserts
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Asserts a `Gtk.ListBoxRow` or `Gtk.FlowBoxChild` is selected, or that a widget in a selectable role
|
|
89
|
-
* carries the selected state flag, and throws for anything else.
|
|
90
|
-
*/
|
|
91
|
-
toBeSelected: StateMatcher;
|
|
164
|
+
/** Asserts the widget's accessible pressed state is mixed, and throws when it exposes none. */
|
|
165
|
+
toBePartiallyPressed: StateMatcher;
|
|
92
166
|
/** Asserts the widget is insensitive, or sits inside an insensitive ancestor. */
|
|
93
167
|
toBeDisabled: StateMatcher;
|
|
94
168
|
/** Asserts the widget and all of its ancestors are sensitive. */
|
|
@@ -98,7 +172,7 @@ type MatcherImplementations = {
|
|
|
98
172
|
/** Asserts the widget's root is a window that is still in the toplevel list. */
|
|
99
173
|
toBeRooted: StateMatcher;
|
|
100
174
|
/** Asserts the widget has neither a child nor label text. */
|
|
101
|
-
|
|
175
|
+
toBeEmptyWidget: StateMatcher;
|
|
102
176
|
/** Asserts the widget's accessible invalid state is set to anything other than false. */
|
|
103
177
|
toBeInvalid: StateMatcher;
|
|
104
178
|
/** Asserts the widget's accessible invalid state is unset or false. */
|
|
@@ -107,12 +181,45 @@ type MatcherImplementations = {
|
|
|
107
181
|
toBeRequired: StateMatcher;
|
|
108
182
|
/** Asserts the widget holds the platform focus state. */
|
|
109
183
|
toHaveFocus: StateMatcher;
|
|
110
|
-
/**
|
|
184
|
+
/**
|
|
185
|
+
* Asserts a widget's numeric value, or its display value when a string is given.
|
|
186
|
+
*
|
|
187
|
+
* Numbers come from the accessibility tree, which GTK keeps to a resolution of 0.001: it drops an
|
|
188
|
+
* update whose value is nearer than that to the one already published, so a widget that moves by
|
|
189
|
+
* less keeps its previous value. Numbers therefore match within 0.001, the same tolerance the
|
|
190
|
+
* `value` option of the `ByRole` queries and `toHaveAccessibleProperty` apply. That option reads
|
|
191
|
+
* the same tree, where the maximum of a paged widget such as a scrollbar is the last value it can
|
|
192
|
+
* reach, its adjustment's upper bound less one page.
|
|
193
|
+
*/
|
|
111
194
|
toHaveValue: (received: unknown, expected?: number | string) => MatcherResult;
|
|
112
195
|
/** Asserts the widget's accessible role. */
|
|
113
196
|
toHaveRole: (received: unknown, expected: Gtk.AccessibleRole) => MatcherResult;
|
|
114
197
|
/** Asserts the widget is, or is an ancestor of, the given widget. */
|
|
115
198
|
toContainElement: (received: unknown, descendant: Gtk.Widget | null) => MatcherResult;
|
|
199
|
+
/** Asserts the widget comes before the given widget in the widget tree, neither containing the other. */
|
|
200
|
+
toAppearBefore: (received: unknown, other: Gtk.Widget) => MatcherResult;
|
|
201
|
+
/** Asserts the widget comes after the given widget in the widget tree, neither containing the other. */
|
|
202
|
+
toAppearAfter: (received: unknown, other: Gtk.Widget) => MatcherResult;
|
|
203
|
+
/** Asserts at least one widget under the received one matches the `ByRole` query. */
|
|
204
|
+
toContainAnyByRole: ContainmentMatcher<RoleQueryArgs>;
|
|
205
|
+
/** Asserts exactly one widget under the received one matches the `ByRole` query. */
|
|
206
|
+
toContainOneByRole: ContainmentMatcher<RoleQueryArgs>;
|
|
207
|
+
/** Asserts at least one widget under the received one matches the `ByText` query. */
|
|
208
|
+
toContainAnyByText: ContainmentMatcher<TextQueryArgs>;
|
|
209
|
+
/** Asserts exactly one widget under the received one matches the `ByText` query. */
|
|
210
|
+
toContainOneByText: ContainmentMatcher<TextQueryArgs>;
|
|
211
|
+
/** Asserts at least one widget under the received one matches the `ByLabelText` query. */
|
|
212
|
+
toContainAnyByLabelText: ContainmentMatcher<TextQueryArgs>;
|
|
213
|
+
/** Asserts exactly one widget under the received one matches the `ByLabelText` query. */
|
|
214
|
+
toContainOneByLabelText: ContainmentMatcher<TextQueryArgs>;
|
|
215
|
+
/** Asserts at least one widget under the received one matches the `ByPlaceholderText` query. */
|
|
216
|
+
toContainAnyByPlaceholderText: ContainmentMatcher<TextQueryArgs>;
|
|
217
|
+
/** Asserts exactly one widget under the received one matches the `ByPlaceholderText` query. */
|
|
218
|
+
toContainOneByPlaceholderText: ContainmentMatcher<TextQueryArgs>;
|
|
219
|
+
/** Asserts at least one widget under the received one matches the `ByDisplayValue` query. */
|
|
220
|
+
toContainAnyByDisplayValue: ContainmentMatcher<TextQueryArgs>;
|
|
221
|
+
/** Asserts exactly one widget under the received one matches the `ByDisplayValue` query. */
|
|
222
|
+
toContainOneByDisplayValue: ContainmentMatcher<TextQueryArgs>;
|
|
116
223
|
/**
|
|
117
224
|
* Asserts the widget carries every given style class, each a name, a space-separated list, or a pattern.
|
|
118
225
|
* Pass `{ exact: true }` last to require exactly that set, which rules out patterns.
|
|
@@ -127,7 +234,18 @@ type MatcherImplementations = {
|
|
|
127
234
|
|
|
128
235
|
type ExpectExtend = { extend: (m: MatcherImplementations) => void };
|
|
129
236
|
|
|
237
|
+
type AttributeExpectation = {
|
|
238
|
+
label: string;
|
|
239
|
+
comparison: string;
|
|
240
|
+
expected: AccessibleAttributeValue;
|
|
241
|
+
actual: AccessibleAttributeValue | null;
|
|
242
|
+
isPass: boolean;
|
|
243
|
+
isReadingRounded: boolean;
|
|
244
|
+
};
|
|
245
|
+
|
|
130
246
|
const registration = { isRegistered: false };
|
|
247
|
+
const MIXED_TRISTATE: number = Gtk.AccessibleTristate.MIXED;
|
|
248
|
+
const ROUNDED_READING = ", which the accessibility tree rounds to six significant digits";
|
|
131
249
|
const displayValueMatcher: TextMatcher = textMatcher("toHaveDisplayValue", getWidgetDisplayValue, "exact");
|
|
132
250
|
const toHaveAccessibleName: TextMatcher = textMatcher("toHaveAccessibleName", getWidgetAccessibleName, "exact");
|
|
133
251
|
|
|
@@ -143,13 +261,70 @@ const toHaveAccessibleErrorMessage: TextMatcher = textMatcher(
|
|
|
143
261
|
"exact",
|
|
144
262
|
);
|
|
145
263
|
|
|
146
|
-
const toHavePlaceholderText: TextMatcher = textMatcher("toHavePlaceholderText", getWidgetPlaceholderText, "exact");
|
|
147
264
|
const toHaveSelection: TextMatcher = textMatcher("toHaveSelection", getWidgetSelection, "exact");
|
|
148
265
|
const toBePressed: StateMatcher = booleanStateMatcher("toBePressed", "pressed", getWidgetPressedState);
|
|
149
|
-
const toBeExpanded: StateMatcher = booleanStateMatcher("toBeExpanded", "expanded", getWidgetExpandedState);
|
|
150
|
-
const toBeSelected: StateMatcher = booleanStateMatcher("toBeSelected", "selected", getWidgetSelectedState);
|
|
151
266
|
const toBeRequired: StateMatcher = booleanStateMatcher("toBeRequired", "required", getWidgetRequiredState);
|
|
152
267
|
|
|
268
|
+
const toContainAnyByRole: ContainmentMatcher<RoleQueryArgs> = containmentMatcher(
|
|
269
|
+
"toContainAnyByRole",
|
|
270
|
+
false,
|
|
271
|
+
queryAllByRole,
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
const toContainOneByRole: ContainmentMatcher<RoleQueryArgs> = containmentMatcher(
|
|
275
|
+
"toContainOneByRole",
|
|
276
|
+
true,
|
|
277
|
+
queryAllByRole,
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
const toContainAnyByText: ContainmentMatcher<TextQueryArgs> = containmentMatcher(
|
|
281
|
+
"toContainAnyByText",
|
|
282
|
+
false,
|
|
283
|
+
queryAllByText,
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
const toContainOneByText: ContainmentMatcher<TextQueryArgs> = containmentMatcher(
|
|
287
|
+
"toContainOneByText",
|
|
288
|
+
true,
|
|
289
|
+
queryAllByText,
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
const toContainAnyByLabelText: ContainmentMatcher<TextQueryArgs> = containmentMatcher(
|
|
293
|
+
"toContainAnyByLabelText",
|
|
294
|
+
false,
|
|
295
|
+
queryAllByLabelText,
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
const toContainOneByLabelText: ContainmentMatcher<TextQueryArgs> = containmentMatcher(
|
|
299
|
+
"toContainOneByLabelText",
|
|
300
|
+
true,
|
|
301
|
+
queryAllByLabelText,
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
const toContainAnyByPlaceholderText: ContainmentMatcher<TextQueryArgs> = containmentMatcher(
|
|
305
|
+
"toContainAnyByPlaceholderText",
|
|
306
|
+
false,
|
|
307
|
+
queryAllByPlaceholderText,
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
const toContainOneByPlaceholderText: ContainmentMatcher<TextQueryArgs> = containmentMatcher(
|
|
311
|
+
"toContainOneByPlaceholderText",
|
|
312
|
+
true,
|
|
313
|
+
queryAllByPlaceholderText,
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
const toContainAnyByDisplayValue: ContainmentMatcher<TextQueryArgs> = containmentMatcher(
|
|
317
|
+
"toContainAnyByDisplayValue",
|
|
318
|
+
false,
|
|
319
|
+
queryAllByDisplayValue,
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
const toContainOneByDisplayValue: ContainmentMatcher<TextQueryArgs> = containmentMatcher(
|
|
323
|
+
"toContainOneByDisplayValue",
|
|
324
|
+
true,
|
|
325
|
+
queryAllByDisplayValue,
|
|
326
|
+
);
|
|
327
|
+
|
|
153
328
|
/** The widget assertion matchers keyed by name, suitable for passing to `expect.extend`. */
|
|
154
329
|
const matchers: MatcherImplementations = {
|
|
155
330
|
toHaveDisplayValue,
|
|
@@ -157,18 +332,18 @@ const matchers: MatcherImplementations = {
|
|
|
157
332
|
toHaveAccessibleName,
|
|
158
333
|
toHaveAccessibleDescription,
|
|
159
334
|
toHaveAccessibleErrorMessage,
|
|
160
|
-
toHavePlaceholderText,
|
|
161
335
|
toHaveSelection,
|
|
336
|
+
toHaveAccessibleState,
|
|
337
|
+
toHaveAccessibleProperty,
|
|
162
338
|
toBeChecked,
|
|
163
339
|
toBePartiallyChecked,
|
|
164
340
|
toBePressed,
|
|
165
|
-
|
|
166
|
-
toBeSelected,
|
|
341
|
+
toBePartiallyPressed,
|
|
167
342
|
toBeDisabled,
|
|
168
343
|
toBeEnabled,
|
|
169
344
|
toBeVisible,
|
|
170
345
|
toBeRooted,
|
|
171
|
-
|
|
346
|
+
toBeEmptyWidget,
|
|
172
347
|
toBeInvalid,
|
|
173
348
|
toBeValid,
|
|
174
349
|
toBeRequired,
|
|
@@ -176,6 +351,18 @@ const matchers: MatcherImplementations = {
|
|
|
176
351
|
toHaveValue,
|
|
177
352
|
toHaveRole,
|
|
178
353
|
toContainElement,
|
|
354
|
+
toAppearBefore,
|
|
355
|
+
toAppearAfter,
|
|
356
|
+
toContainAnyByRole,
|
|
357
|
+
toContainOneByRole,
|
|
358
|
+
toContainAnyByText,
|
|
359
|
+
toContainOneByText,
|
|
360
|
+
toContainAnyByLabelText,
|
|
361
|
+
toContainOneByLabelText,
|
|
362
|
+
toContainAnyByPlaceholderText,
|
|
363
|
+
toContainOneByPlaceholderText,
|
|
364
|
+
toContainAnyByDisplayValue,
|
|
365
|
+
toContainOneByDisplayValue,
|
|
179
366
|
toHaveClass,
|
|
180
367
|
toHaveObjectProperty,
|
|
181
368
|
};
|
|
@@ -204,7 +391,7 @@ const describeWidget = (widget: Gtk.Widget): string => {
|
|
|
204
391
|
};
|
|
205
392
|
|
|
206
393
|
const describeObject = (object: GObject.Object): string =>
|
|
207
|
-
object instanceof Gtk.Widget ? describeWidget(object) : `<${object
|
|
394
|
+
object instanceof Gtk.Widget ? describeWidget(object) : `<${getTypeTag(object)}>`;
|
|
208
395
|
|
|
209
396
|
const isTextMatch = (actual: string, expected: TextExpectation, mode: "exact" | "substring"): boolean => {
|
|
210
397
|
if (expected instanceof RegExp) {
|
|
@@ -244,6 +431,100 @@ const stateResult = (widget: Gtk.Widget, stateName: string, isPass: boolean): Ma
|
|
|
244
431
|
message: () => `expected widget ${negationPrefix(isPass)}to be ${stateName}\n${describeWidget(widget)}`,
|
|
245
432
|
});
|
|
246
433
|
|
|
434
|
+
const isHoldingFocus = (widget: Gtk.Widget, root: Gtk.Window): boolean => {
|
|
435
|
+
const focus = root.getFocus();
|
|
436
|
+
|
|
437
|
+
return focus !== null && (focus === widget || focus.isAncestor(widget));
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
const isFocusHeldByInactiveWindow = (widget: Gtk.Widget): boolean => {
|
|
441
|
+
const root = widget.getRoot();
|
|
442
|
+
|
|
443
|
+
return root instanceof Gtk.Window && !isWindowActivated(root) && isHoldingFocus(widget, root);
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
const focusResult = (widget: Gtk.Widget, isPass: boolean): MatcherResult => {
|
|
447
|
+
if (isPass || !isFocusHeldByInactiveWindow(widget)) {
|
|
448
|
+
return stateResult(widget, "focused", isPass);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
return {
|
|
452
|
+
pass: false,
|
|
453
|
+
message: () =>
|
|
454
|
+
"expected widget to be focused: its window has given it the focus, " +
|
|
455
|
+
`but that window is not active\n${describeWidget(widget)}`,
|
|
456
|
+
};
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
const describeAttributeValue = (value: AccessibleAttributeValue | null): string =>
|
|
460
|
+
value === null ? "unset" : JSON.stringify(value);
|
|
461
|
+
|
|
462
|
+
const attributeSetResult = (
|
|
463
|
+
widget: Gtk.Widget,
|
|
464
|
+
label: string,
|
|
465
|
+
actual: AccessibleAttributeValue | null,
|
|
466
|
+
): MatcherResult => {
|
|
467
|
+
const isSet = actual !== null;
|
|
468
|
+
|
|
469
|
+
return {
|
|
470
|
+
pass: isSet,
|
|
471
|
+
message: () => `expected widget ${negationPrefix(isSet)}to have ${label} set\n${describeWidget(widget)}`,
|
|
472
|
+
};
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
const describeReading = (expectation: AttributeExpectation): string =>
|
|
476
|
+
`${describeAttributeValue(expectation.actual)}${expectation.isReadingRounded ? ROUNDED_READING : ""}`;
|
|
477
|
+
|
|
478
|
+
const attributeValueResult = (widget: Gtk.Widget, expectation: AttributeExpectation): MatcherResult => ({
|
|
479
|
+
pass: expectation.isPass,
|
|
480
|
+
message: () =>
|
|
481
|
+
`expected widget ${negationPrefix(expectation.isPass)}to have ${expectation.label} ` +
|
|
482
|
+
`${expectation.comparison} ${describeAttributeValue(expectation.expected)}, but received ` +
|
|
483
|
+
`${describeReading(expectation)}\n${describeWidget(widget)}`,
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
const orderResult = (widget: Gtk.Widget, other: Gtk.Widget, position: string, isPass: boolean): MatcherResult => ({
|
|
487
|
+
pass: isPass,
|
|
488
|
+
message: () =>
|
|
489
|
+
`expected widget ${negationPrefix(isPass)}to appear ${position} ${describeWidget(other)} ` +
|
|
490
|
+
`in the widget tree\n${describeWidget(widget)}`,
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
const getTreeRoot = (widget: Gtk.Widget): Gtk.Widget => {
|
|
494
|
+
let root = widget;
|
|
495
|
+
let parent = root.getParent();
|
|
496
|
+
|
|
497
|
+
while (parent) {
|
|
498
|
+
root = parent;
|
|
499
|
+
parent = root.getParent();
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
return root;
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
const isSeparateWidget = (first: Gtk.Widget, second: Gtk.Widget): boolean =>
|
|
506
|
+
first !== second && !first.isAncestor(second) && !second.isAncestor(first);
|
|
507
|
+
|
|
508
|
+
const isPrecedingWidget = (root: Gtk.Widget, first: Gtk.Widget, second: Gtk.Widget): boolean => {
|
|
509
|
+
for (const widget of descendants(root)) {
|
|
510
|
+
if (widget === first) {
|
|
511
|
+
return true;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
if (widget === second) {
|
|
515
|
+
return false;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
return false;
|
|
520
|
+
};
|
|
521
|
+
|
|
522
|
+
const isAppearingBefore = (first: Gtk.Widget, second: Gtk.Widget): boolean => {
|
|
523
|
+
const root = getTreeRoot(first);
|
|
524
|
+
|
|
525
|
+
return isSeparateWidget(first, second) && root === getTreeRoot(second) && isPrecedingWidget(root, first, second);
|
|
526
|
+
};
|
|
527
|
+
|
|
247
528
|
const camelCase = (name: string): string =>
|
|
248
529
|
name.replaceAll(/-([a-z])/g, (_match, letter: string) => letter.toUpperCase());
|
|
249
530
|
|
|
@@ -426,6 +707,117 @@ function booleanStateMatcher(
|
|
|
426
707
|
};
|
|
427
708
|
}
|
|
428
709
|
|
|
710
|
+
function containmentMatcher<Args extends unknown[]>(
|
|
711
|
+
matcherName: string,
|
|
712
|
+
isSingle: boolean,
|
|
713
|
+
queryAll: QueryAll<Args>,
|
|
714
|
+
): ContainmentMatcher<Args> {
|
|
715
|
+
const quantity = isSingle ? "exactly one widget" : "any widget";
|
|
716
|
+
|
|
717
|
+
return (received: unknown, ...args: Args): MatcherResult => {
|
|
718
|
+
const widget = asWidget(received, matcherName);
|
|
719
|
+
const matches = queryAll(widget, ...args);
|
|
720
|
+
const isPass = isSingle ? matches.length === 1 : matches.length > 0;
|
|
721
|
+
|
|
722
|
+
return {
|
|
723
|
+
pass: isPass,
|
|
724
|
+
message: () =>
|
|
725
|
+
`expected widget ${negationPrefix(isPass)}to contain ${quantity} matching ${matcherName}, ` +
|
|
726
|
+
`but found ${String(matches.length)}\n${describeWidget(widget)}`,
|
|
727
|
+
};
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
function toHaveAccessibleState(
|
|
732
|
+
received: unknown,
|
|
733
|
+
state: Gtk.AccessibleState,
|
|
734
|
+
expected?: boolean | number,
|
|
735
|
+
): MatcherResult {
|
|
736
|
+
const widget = asWidget(received, "toHaveAccessibleState");
|
|
737
|
+
const actual = readAccessibleState(widget, state);
|
|
738
|
+
const label = `accessible state ${Gtk.AccessibleState[state]}`;
|
|
739
|
+
|
|
740
|
+
if (expected === undefined) {
|
|
741
|
+
return attributeSetResult(widget, label, actual);
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
const wanted = typeof expected === "boolean" ? Number(expected) : expected;
|
|
745
|
+
|
|
746
|
+
return attributeValueResult(widget, {
|
|
747
|
+
label,
|
|
748
|
+
comparison: "equal to",
|
|
749
|
+
expected: wanted,
|
|
750
|
+
actual,
|
|
751
|
+
isPass: actual === wanted,
|
|
752
|
+
isReadingRounded: false,
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
const propertyLabel = (property: Gtk.AccessibleProperty): string =>
|
|
757
|
+
`accessible property ${Gtk.AccessibleProperty[property]}`;
|
|
758
|
+
|
|
759
|
+
const propertyExpectation = (
|
|
760
|
+
widget: Gtk.Widget,
|
|
761
|
+
property: Gtk.AccessibleProperty,
|
|
762
|
+
expected: AccessibleAttributeValue,
|
|
763
|
+
actual: AccessibleAttributeValue | null,
|
|
764
|
+
): AttributeExpectation => {
|
|
765
|
+
const label = propertyLabel(property);
|
|
766
|
+
|
|
767
|
+
if (typeof expected === "number" && isAccessibleNumberProperty(property)) {
|
|
768
|
+
return {
|
|
769
|
+
label,
|
|
770
|
+
comparison: `within ${String(ACCESSIBLE_NUMBER_TOLERANCE)} of`,
|
|
771
|
+
expected,
|
|
772
|
+
actual,
|
|
773
|
+
isPass: isAccessibleNumberMatch(widget, property, expected),
|
|
774
|
+
isReadingRounded: actual !== null,
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
return { label, comparison: "equal to", expected, actual, isPass: actual === expected, isReadingRounded: false };
|
|
779
|
+
};
|
|
780
|
+
|
|
781
|
+
function toHaveAccessibleProperty(
|
|
782
|
+
received: unknown,
|
|
783
|
+
property: Gtk.AccessibleProperty,
|
|
784
|
+
expected?: AccessibleAttributeValue,
|
|
785
|
+
): MatcherResult {
|
|
786
|
+
const widget = asWidget(received, "toHaveAccessibleProperty");
|
|
787
|
+
const actual = readAccessibleProperty(widget, property);
|
|
788
|
+
|
|
789
|
+
if (expected === undefined) {
|
|
790
|
+
return attributeSetResult(widget, propertyLabel(property), actual);
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
return attributeValueResult(widget, propertyExpectation(widget, property, expected, actual));
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
function toBePartiallyPressed(received: unknown): MatcherResult {
|
|
797
|
+
const widget = asWidget(received, "toBePartiallyPressed");
|
|
798
|
+
const state = readAccessibleState(widget, Gtk.AccessibleState.PRESSED);
|
|
799
|
+
|
|
800
|
+
if (state === null) {
|
|
801
|
+
throw notApplicable("toBePartiallyPressed", "pressed state", widget);
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
return stateResult(widget, "partially pressed", state === MIXED_TRISTATE);
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
function toAppearBefore(received: unknown, other: Gtk.Widget): MatcherResult {
|
|
808
|
+
const widget = asWidget(received, "toAppearBefore");
|
|
809
|
+
const target = asWidget(other, "toAppearBefore");
|
|
810
|
+
|
|
811
|
+
return orderResult(widget, target, "before", isAppearingBefore(widget, target));
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
function toAppearAfter(received: unknown, other: Gtk.Widget): MatcherResult {
|
|
815
|
+
const widget = asWidget(received, "toAppearAfter");
|
|
816
|
+
const target = asWidget(other, "toAppearAfter");
|
|
817
|
+
|
|
818
|
+
return orderResult(widget, target, "after", isAppearingBefore(target, widget));
|
|
819
|
+
}
|
|
820
|
+
|
|
429
821
|
function readCheckedState(widget: Gtk.Widget, matcherName: string): CheckedState {
|
|
430
822
|
const state = getWidgetCheckedState(widget);
|
|
431
823
|
|
|
@@ -458,6 +850,9 @@ function toHaveDisplayValue(received: unknown, expected?: TextExpectation): Matc
|
|
|
458
850
|
return displayValueMatcher(received, expected);
|
|
459
851
|
}
|
|
460
852
|
|
|
853
|
+
const describeValueExpectation = (expected: number | undefined): string =>
|
|
854
|
+
expected === undefined ? "set" : `within ${String(ACCESSIBLE_NUMBER_TOLERANCE)} of ${String(expected)}`;
|
|
855
|
+
|
|
461
856
|
function toHaveValue(received: unknown, expected?: number | string): MatcherResult {
|
|
462
857
|
const widget = asWidget(received, "toHaveValue");
|
|
463
858
|
|
|
@@ -465,19 +860,19 @@ function toHaveValue(received: unknown, expected?: number | string): MatcherResu
|
|
|
465
860
|
return displayValueMatcher(received, expected);
|
|
466
861
|
}
|
|
467
862
|
|
|
468
|
-
const actual =
|
|
863
|
+
const actual = getWidgetValueNow(widget);
|
|
469
864
|
|
|
470
865
|
if (actual === null) {
|
|
471
866
|
throw notApplicable("toHaveValue", "numeric value", widget);
|
|
472
867
|
}
|
|
473
868
|
|
|
474
|
-
const isPass = expected === undefined ||
|
|
869
|
+
const isPass = expected === undefined || isWidgetValueMatch(widget, "now", expected);
|
|
475
870
|
|
|
476
871
|
return {
|
|
477
872
|
pass: isPass,
|
|
478
873
|
message: () =>
|
|
479
|
-
`expected widget ${negationPrefix(isPass)}to have value ${
|
|
480
|
-
`but received ${String(actual)}\n${describeWidget(widget)}`,
|
|
874
|
+
`expected widget ${negationPrefix(isPass)}to have value ${describeValueExpectation(expected)}, ` +
|
|
875
|
+
`but received ${String(actual)}${ROUNDED_READING}\n${describeWidget(widget)}`,
|
|
481
876
|
};
|
|
482
877
|
}
|
|
483
878
|
|
|
@@ -509,8 +904,8 @@ function toBeRooted(received: unknown): MatcherResult {
|
|
|
509
904
|
return stateResult(widget, "rooted in a window", isWidgetRooted(widget));
|
|
510
905
|
}
|
|
511
906
|
|
|
512
|
-
function
|
|
513
|
-
const widget = asWidget(received, "
|
|
907
|
+
function toBeEmptyWidget(received: unknown): MatcherResult {
|
|
908
|
+
const widget = asWidget(received, "toBeEmptyWidget");
|
|
514
909
|
|
|
515
910
|
return stateResult(widget, "empty", widget.getFirstChild() === null && getWidgetLabelText(widget) === null);
|
|
516
911
|
}
|
|
@@ -532,7 +927,7 @@ function toBeValid(received: unknown): MatcherResult {
|
|
|
532
927
|
function toHaveFocus(received: unknown): MatcherResult {
|
|
533
928
|
const widget = asWidget(received, "toHaveFocus");
|
|
534
929
|
|
|
535
|
-
return
|
|
930
|
+
return focusResult(widget, widget.getPlatformState(Gtk.AccessiblePlatformState.FOCUSED));
|
|
536
931
|
}
|
|
537
932
|
|
|
538
933
|
function toHaveRole(received: unknown, expected: Gtk.AccessibleRole): MatcherResult {
|
|
@@ -599,8 +994,6 @@ function toHaveObjectProperty(this: MatcherContext, received: unknown, ...args:
|
|
|
599
994
|
};
|
|
600
995
|
}
|
|
601
996
|
|
|
602
|
-
/* eslint-disable-next-line unicorn/no-this-outside-of-class --
|
|
603
|
-
expect.extend invokes matchers with the matcher state as `this` */
|
|
604
997
|
const isPass = isEqualValue(this, actual, expected);
|
|
605
998
|
|
|
606
999
|
return {
|
|
@@ -635,18 +1028,30 @@ declare module "@vitest/expect" {
|
|
|
635
1028
|
toHaveAccessibleName(expected?: TextExpectation): void;
|
|
636
1029
|
toHaveAccessibleDescription(expected?: TextExpectation): void;
|
|
637
1030
|
toHaveAccessibleErrorMessage(expected?: TextExpectation): void;
|
|
638
|
-
toHavePlaceholderText(expected?: TextExpectation): void;
|
|
639
1031
|
toHaveSelection(expected?: TextExpectation): void;
|
|
1032
|
+
/* eslint-disable-next-line unicorn/consistent-boolean-name -- expected is the jest-dom matcher argument name */
|
|
1033
|
+
toHaveAccessibleState(state: BooleanAccessibleState, expected?: boolean): void;
|
|
1034
|
+
toHaveAccessibleState(state: TristateAccessibleState, expected?: Gtk.AccessibleTristate): void;
|
|
1035
|
+
toHaveAccessibleState(state: Gtk.AccessibleState.INVALID, expected?: Gtk.AccessibleInvalidState): void;
|
|
1036
|
+
toHaveAccessibleProperty(property: StringAccessibleProperty, expected?: string): void;
|
|
1037
|
+
/* eslint-disable-next-line unicorn/consistent-boolean-name -- expected is the jest-dom matcher argument name */
|
|
1038
|
+
toHaveAccessibleProperty(property: BooleanAccessibleProperty, expected?: boolean): void;
|
|
1039
|
+
toHaveAccessibleProperty(property: NumberAccessibleProperty, expected?: number): void;
|
|
1040
|
+
toHaveAccessibleProperty(
|
|
1041
|
+
property: Gtk.AccessibleProperty.AUTOCOMPLETE,
|
|
1042
|
+
expected?: Gtk.AccessibleAutocomplete,
|
|
1043
|
+
): void;
|
|
1044
|
+
toHaveAccessibleProperty(property: Gtk.AccessibleProperty.ORIENTATION, expected?: Gtk.Orientation): void;
|
|
1045
|
+
toHaveAccessibleProperty(property: Gtk.AccessibleProperty.SORT, expected?: Gtk.AccessibleSort): void;
|
|
640
1046
|
toBeChecked(): void;
|
|
641
1047
|
toBePartiallyChecked(): void;
|
|
642
1048
|
toBePressed(): void;
|
|
643
|
-
|
|
644
|
-
toBeSelected(): void;
|
|
1049
|
+
toBePartiallyPressed(): void;
|
|
645
1050
|
toBeDisabled(): void;
|
|
646
1051
|
toBeEnabled(): void;
|
|
647
1052
|
toBeVisible(): void;
|
|
648
1053
|
toBeRooted(): void;
|
|
649
|
-
|
|
1054
|
+
toBeEmptyWidget(): void;
|
|
650
1055
|
toBeInvalid(): void;
|
|
651
1056
|
toBeValid(): void;
|
|
652
1057
|
toBeRequired(): void;
|
|
@@ -654,6 +1059,18 @@ declare module "@vitest/expect" {
|
|
|
654
1059
|
toHaveValue(expected?: number | string): void;
|
|
655
1060
|
toHaveRole(expected: Gtk.AccessibleRole): void;
|
|
656
1061
|
toContainElement(descendant: Gtk.Widget | null): void;
|
|
1062
|
+
toAppearBefore(other: Gtk.Widget): void;
|
|
1063
|
+
toAppearAfter(other: Gtk.Widget): void;
|
|
1064
|
+
toContainAnyByRole(...args: RoleQueryArgs): void;
|
|
1065
|
+
toContainOneByRole(...args: RoleQueryArgs): void;
|
|
1066
|
+
toContainAnyByText(...args: TextQueryArgs): void;
|
|
1067
|
+
toContainOneByText(...args: TextQueryArgs): void;
|
|
1068
|
+
toContainAnyByLabelText(...args: TextQueryArgs): void;
|
|
1069
|
+
toContainOneByLabelText(...args: TextQueryArgs): void;
|
|
1070
|
+
toContainAnyByPlaceholderText(...args: TextQueryArgs): void;
|
|
1071
|
+
toContainOneByPlaceholderText(...args: TextQueryArgs): void;
|
|
1072
|
+
toContainAnyByDisplayValue(...args: TextQueryArgs): void;
|
|
1073
|
+
toContainOneByDisplayValue(...args: TextQueryArgs): void;
|
|
657
1074
|
toHaveClass(...args: (ClassExpectation | { exact: boolean })[]): void;
|
|
658
1075
|
toHaveObjectProperty(name: string, expected?: unknown): void;
|
|
659
1076
|
}
|
|
@@ -663,36 +1080,4 @@ declare module "@vitest/expect" {
|
|
|
663
1080
|
/* eslint-enable @typescript-eslint/consistent-type-definitions */
|
|
664
1081
|
}
|
|
665
1082
|
|
|
666
|
-
export {
|
|
667
|
-
toHaveDisplayValue,
|
|
668
|
-
toHaveTextContent,
|
|
669
|
-
toHaveAccessibleName,
|
|
670
|
-
toHaveAccessibleDescription,
|
|
671
|
-
toHaveAccessibleErrorMessage,
|
|
672
|
-
toHavePlaceholderText,
|
|
673
|
-
toHaveSelection,
|
|
674
|
-
toBeChecked,
|
|
675
|
-
toBePartiallyChecked,
|
|
676
|
-
toBePressed,
|
|
677
|
-
toBeExpanded,
|
|
678
|
-
toBeSelected,
|
|
679
|
-
toBeDisabled,
|
|
680
|
-
toBeEnabled,
|
|
681
|
-
toBeVisible,
|
|
682
|
-
toBeRooted,
|
|
683
|
-
toBeEmpty,
|
|
684
|
-
toBeInvalid,
|
|
685
|
-
toBeValid,
|
|
686
|
-
toBeRequired,
|
|
687
|
-
toHaveFocus,
|
|
688
|
-
toHaveValue,
|
|
689
|
-
toHaveRole,
|
|
690
|
-
toContainElement,
|
|
691
|
-
toHaveClass,
|
|
692
|
-
toHaveObjectProperty,
|
|
693
|
-
matchers,
|
|
694
|
-
registerMatchers,
|
|
695
|
-
type ClassExpectation,
|
|
696
|
-
type TextContentOptions,
|
|
697
|
-
type TextExpectation,
|
|
698
|
-
};
|
|
1083
|
+
export { matchers, registerMatchers, type ClassExpectation, type TextContentOptions, type TextExpectation };
|