@gtkx/testing 0.2.7 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/fire-event.js +1 -1
- package/dist/queries.js +20 -30
- package/dist/render.js +6 -6
- package/dist/user-event.js +18 -20
- package/dist/widget.d.ts +0 -2
- package/dist/widget.js +4 -4
- package/package.json +4 -4
package/dist/fire-event.js
CHANGED
|
@@ -14,5 +14,5 @@ import { call } from "@gtkx/native";
|
|
|
14
14
|
* fireEvent(widget, "custom-signal", { type: { type: "int", size: 32 }, value: 42 })
|
|
15
15
|
*/
|
|
16
16
|
export const fireEvent = (element, signalName, ...args) => {
|
|
17
|
-
call("libgobject-2.0.so.0", "g_signal_emit_by_name", [{ type: { type: "gobject" }, value: element.
|
|
17
|
+
call("libgobject-2.0.so.0", "g_signal_emit_by_name", [{ type: { type: "gobject" }, value: element.id }, { type: { type: "string" }, value: signalName }, ...args], { type: "undefined" });
|
|
18
18
|
};
|
package/dist/queries.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { AccessibleRole, Button, CheckButton, Editable, Expander, Frame, Label, StackPage, Switch, ToggleButton, Window, } from "@gtkx/ffi/gtk";
|
|
1
|
+
import { getInterface } from "@gtkx/ffi";
|
|
2
|
+
import { Accessible, AccessibleRole, Button, CheckButton, Editable, Expander, Frame, Label, StackPage, Switch, ToggleButton, Window, } from "@gtkx/ffi/gtk";
|
|
3
3
|
import { findAll } from "./traversal.js";
|
|
4
4
|
import { waitFor } from "./wait-for.js";
|
|
5
|
-
import { asAccessible } from "./widget.js";
|
|
6
5
|
const DEFAULT_NORMALIZER = (text) => text.trim().replace(/\s+/g, " ");
|
|
7
6
|
const normalizeText = (text, options) => {
|
|
8
7
|
const normalizer = options?.normalizer ?? DEFAULT_NORMALIZER;
|
|
@@ -19,14 +18,6 @@ const matchText = (actual, expected, options) => {
|
|
|
19
18
|
}
|
|
20
19
|
return expected.test(normalizedActual);
|
|
21
20
|
};
|
|
22
|
-
const asButton = (widget) => getObject(widget.ptr, Button);
|
|
23
|
-
const asLabel = (widget) => getObject(widget.ptr, Label);
|
|
24
|
-
const asCheckButton = (widget) => getObject(widget.ptr, CheckButton);
|
|
25
|
-
const asToggleButton = (widget) => getObject(widget.ptr, ToggleButton);
|
|
26
|
-
const asExpander = (widget) => getObject(widget.ptr, Expander);
|
|
27
|
-
const asFrame = (widget) => getObject(widget.ptr, Frame);
|
|
28
|
-
const asWindow = (widget) => getObject(widget.ptr, Window);
|
|
29
|
-
const asStackPage = (widget) => getObject(widget.ptr, StackPage);
|
|
30
21
|
const ROLES_WITH_INTERNAL_LABELS = new Set([
|
|
31
22
|
AccessibleRole.BUTTON,
|
|
32
23
|
AccessibleRole.TOGGLE_BUTTON,
|
|
@@ -39,38 +30,38 @@ const ROLES_WITH_INTERNAL_LABELS = new Set([
|
|
|
39
30
|
AccessibleRole.LINK,
|
|
40
31
|
]);
|
|
41
32
|
const isInternalLabel = (widget) => {
|
|
42
|
-
const accessible =
|
|
33
|
+
const accessible = getInterface(widget, Accessible);
|
|
43
34
|
if (accessible.getAccessibleRole() !== AccessibleRole.LABEL)
|
|
44
35
|
return false;
|
|
45
36
|
const parent = widget.getParent();
|
|
46
37
|
if (!parent)
|
|
47
38
|
return false;
|
|
48
|
-
const parentRole =
|
|
39
|
+
const parentRole = getInterface(parent, Accessible).getAccessibleRole();
|
|
49
40
|
return ROLES_WITH_INTERNAL_LABELS.has(parentRole);
|
|
50
41
|
};
|
|
51
42
|
const getWidgetText = (widget) => {
|
|
52
43
|
if (isInternalLabel(widget))
|
|
53
44
|
return null;
|
|
54
|
-
const role =
|
|
45
|
+
const role = getInterface(widget, Accessible).getAccessibleRole();
|
|
55
46
|
switch (role) {
|
|
56
47
|
case AccessibleRole.BUTTON:
|
|
57
48
|
case AccessibleRole.LINK:
|
|
58
49
|
case AccessibleRole.TAB:
|
|
59
|
-
return
|
|
50
|
+
return getInterface(widget, Button).getLabel();
|
|
60
51
|
case AccessibleRole.TOGGLE_BUTTON:
|
|
61
|
-
return
|
|
52
|
+
return getInterface(widget, ToggleButton).getLabel();
|
|
62
53
|
case AccessibleRole.CHECKBOX:
|
|
63
54
|
case AccessibleRole.RADIO:
|
|
64
|
-
return
|
|
55
|
+
return getInterface(widget, CheckButton).getLabel();
|
|
65
56
|
case AccessibleRole.LABEL:
|
|
66
|
-
return
|
|
57
|
+
return getInterface(widget, Label).getLabel();
|
|
67
58
|
case AccessibleRole.TEXT_BOX:
|
|
68
59
|
case AccessibleRole.SEARCH_BOX:
|
|
69
60
|
case AccessibleRole.SPIN_BUTTON:
|
|
70
|
-
return
|
|
61
|
+
return getInterface(widget, Editable).getText();
|
|
71
62
|
case AccessibleRole.GROUP:
|
|
72
63
|
try {
|
|
73
|
-
return
|
|
64
|
+
return getInterface(widget, Frame).getLabel();
|
|
74
65
|
}
|
|
75
66
|
catch {
|
|
76
67
|
return null;
|
|
@@ -78,10 +69,10 @@ const getWidgetText = (widget) => {
|
|
|
78
69
|
case AccessibleRole.WINDOW:
|
|
79
70
|
case AccessibleRole.DIALOG:
|
|
80
71
|
case AccessibleRole.ALERT_DIALOG:
|
|
81
|
-
return
|
|
72
|
+
return getInterface(widget, Window).getTitle();
|
|
82
73
|
case AccessibleRole.TAB_PANEL:
|
|
83
74
|
try {
|
|
84
|
-
return
|
|
75
|
+
return getInterface(widget, StackPage).getTitle();
|
|
85
76
|
}
|
|
86
77
|
catch {
|
|
87
78
|
return null;
|
|
@@ -95,28 +86,27 @@ const getWidgetText = (widget) => {
|
|
|
95
86
|
const getWidgetTestId = (widget) => {
|
|
96
87
|
return widget.getName();
|
|
97
88
|
};
|
|
98
|
-
const asSwitch = (widget) => getObject(widget.ptr, Switch);
|
|
99
89
|
const getWidgetCheckedState = (widget) => {
|
|
100
|
-
const role =
|
|
90
|
+
const role = getInterface(widget, Accessible).getAccessibleRole();
|
|
101
91
|
switch (role) {
|
|
102
92
|
case AccessibleRole.CHECKBOX:
|
|
103
93
|
case AccessibleRole.RADIO:
|
|
104
|
-
return
|
|
94
|
+
return getInterface(widget, CheckButton).getActive();
|
|
105
95
|
case AccessibleRole.TOGGLE_BUTTON:
|
|
106
|
-
return
|
|
96
|
+
return getInterface(widget, ToggleButton).getActive();
|
|
107
97
|
case AccessibleRole.SWITCH:
|
|
108
|
-
return
|
|
98
|
+
return getInterface(widget, Switch).getActive();
|
|
109
99
|
default:
|
|
110
100
|
return undefined;
|
|
111
101
|
}
|
|
112
102
|
};
|
|
113
103
|
const getWidgetExpandedState = (widget) => {
|
|
114
|
-
const role =
|
|
104
|
+
const role = getInterface(widget, Accessible).getAccessibleRole();
|
|
115
105
|
if (role === AccessibleRole.BUTTON) {
|
|
116
106
|
const parent = widget.getParent();
|
|
117
107
|
if (!parent)
|
|
118
108
|
return undefined;
|
|
119
|
-
return
|
|
109
|
+
return getInterface(parent, Expander).getExpanded();
|
|
120
110
|
}
|
|
121
111
|
return undefined;
|
|
122
112
|
};
|
|
@@ -159,7 +149,7 @@ const formatByRoleError = (role, options) => {
|
|
|
159
149
|
};
|
|
160
150
|
const getAllByRole = (container, role, options) => {
|
|
161
151
|
const matches = findAll(container, (node) => {
|
|
162
|
-
if (
|
|
152
|
+
if (getInterface(node, Accessible).getAccessibleRole() !== role)
|
|
163
153
|
return false;
|
|
164
154
|
return matchByRoleOptions(node, options);
|
|
165
155
|
});
|
package/dist/render.js
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { getCurrentApp,
|
|
2
|
+
import { getCurrentApp, getInterface, start, stop } from "@gtkx/ffi";
|
|
3
3
|
import * as Gtk from "@gtkx/ffi/gtk";
|
|
4
4
|
import { ApplicationWindow, reconciler } from "@gtkx/react";
|
|
5
5
|
import * as queries from "./queries.js";
|
|
6
6
|
import { setScreenRoot } from "./screen.js";
|
|
7
7
|
import { tick } from "./timing.js";
|
|
8
|
-
import {
|
|
8
|
+
import { hasLabel } from "./widget.js";
|
|
9
9
|
const ROOT_NODE_CONTAINER = Symbol.for("ROOT_NODE_CONTAINER");
|
|
10
10
|
const APP_ID = "com.gtkx.testing";
|
|
11
11
|
let container = null;
|
|
12
12
|
const getWidgetLabel = (widget) => {
|
|
13
13
|
if (!hasLabel(widget))
|
|
14
14
|
return null;
|
|
15
|
-
const role =
|
|
15
|
+
const role = getInterface(widget, Gtk.Accessible).getAccessibleRole();
|
|
16
16
|
if (role === Gtk.AccessibleRole.LABEL) {
|
|
17
|
-
return
|
|
17
|
+
return getInterface(widget, Gtk.Label).getLabel();
|
|
18
18
|
}
|
|
19
|
-
return
|
|
19
|
+
return getInterface(widget, Gtk.Button).getLabel();
|
|
20
20
|
};
|
|
21
21
|
const printWidgetTree = (root, indent = 0) => {
|
|
22
22
|
const prefix = " ".repeat(indent);
|
|
23
|
-
const role = Gtk.AccessibleRole[
|
|
23
|
+
const role = Gtk.AccessibleRole[getInterface(root, Gtk.Accessible).getAccessibleRole()] ?? "UNKNOWN";
|
|
24
24
|
const labelText = getWidgetLabel(root);
|
|
25
25
|
const label = labelText ? ` label="${labelText}"` : "";
|
|
26
26
|
let result = `${prefix}<${root.constructor.name} role=${role}${label}>\n`;
|
package/dist/user-event.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { getInterface } from "@gtkx/ffi";
|
|
2
|
+
import { Accessible, AccessibleRole, DirectionType, Editable, Widget, } from "@gtkx/ffi/gtk";
|
|
3
3
|
import { fireEvent } from "./fire-event.js";
|
|
4
4
|
import { tick } from "./timing.js";
|
|
5
|
-
import {
|
|
5
|
+
import { isEditable } from "./widget.js";
|
|
6
6
|
const TOGGLEABLE_ROLES = new Set([AccessibleRole.CHECKBOX, AccessibleRole.RADIO, AccessibleRole.TOGGLE_BUTTON]);
|
|
7
7
|
const isToggleable = (widget) => {
|
|
8
|
-
const role =
|
|
8
|
+
const role = getInterface(widget, Accessible).getAccessibleRole();
|
|
9
9
|
return TOGGLEABLE_ROLES.has(role);
|
|
10
10
|
};
|
|
11
11
|
const click = async (element) => {
|
|
12
12
|
if (isToggleable(element)) {
|
|
13
|
-
const role =
|
|
13
|
+
const role = getInterface(element, Accessible).getAccessibleRole();
|
|
14
14
|
if (role === AccessibleRole.CHECKBOX || role === AccessibleRole.RADIO) {
|
|
15
|
-
const checkButton =
|
|
15
|
+
const checkButton = element;
|
|
16
16
|
checkButton.setActive(!checkButton.getActive());
|
|
17
17
|
}
|
|
18
18
|
else {
|
|
19
|
-
const toggleButton =
|
|
19
|
+
const toggleButton = element;
|
|
20
20
|
toggleButton.setActive(!toggleButton.getActive());
|
|
21
21
|
}
|
|
22
22
|
// Note: setActive() automatically emits the "toggled" signal, so we don't need to emit it manually
|
|
@@ -48,8 +48,7 @@ const tab = async (element, options) => {
|
|
|
48
48
|
const direction = options?.shift ? DirectionType.TAB_BACKWARD : DirectionType.TAB_FORWARD;
|
|
49
49
|
const root = element.getRoot();
|
|
50
50
|
if (root) {
|
|
51
|
-
|
|
52
|
-
rootWidget.childFocus(direction);
|
|
51
|
+
getInterface(root, Widget).childFocus(direction);
|
|
53
52
|
}
|
|
54
53
|
await tick();
|
|
55
54
|
};
|
|
@@ -57,7 +56,7 @@ const type = async (element, text) => {
|
|
|
57
56
|
if (!isEditable(element)) {
|
|
58
57
|
throw new Error("Cannot type into element: element is not editable (TEXT_BOX, SEARCH_BOX, or SPIN_BUTTON)");
|
|
59
58
|
}
|
|
60
|
-
const editable =
|
|
59
|
+
const editable = getInterface(element, Editable);
|
|
61
60
|
const currentText = editable.getText();
|
|
62
61
|
editable.setText(currentText + text);
|
|
63
62
|
await tick();
|
|
@@ -66,20 +65,19 @@ const clear = async (element) => {
|
|
|
66
65
|
if (!isEditable(element)) {
|
|
67
66
|
throw new Error("Cannot clear element: element is not editable (TEXT_BOX, SEARCH_BOX, or SPIN_BUTTON)");
|
|
68
67
|
}
|
|
69
|
-
|
|
70
|
-
editable.setText("");
|
|
68
|
+
getInterface(element, Editable).setText("");
|
|
71
69
|
await tick();
|
|
72
70
|
};
|
|
73
71
|
const SELECTABLE_ROLES = new Set([AccessibleRole.COMBO_BOX, AccessibleRole.LIST]);
|
|
74
72
|
const isSelectable = (widget) => {
|
|
75
|
-
const role =
|
|
73
|
+
const role = getInterface(widget, Accessible).getAccessibleRole();
|
|
76
74
|
return SELECTABLE_ROLES.has(role);
|
|
77
75
|
};
|
|
78
76
|
const selectOptions = async (element, values) => {
|
|
79
77
|
if (!isSelectable(element)) {
|
|
80
78
|
throw new Error("Cannot select options: element is not a selectable widget (COMBO_BOX or LIST)");
|
|
81
79
|
}
|
|
82
|
-
const role =
|
|
80
|
+
const role = getInterface(element, Accessible).getAccessibleRole();
|
|
83
81
|
const valueArray = Array.isArray(values) ? values : [values];
|
|
84
82
|
if (role === AccessibleRole.COMBO_BOX) {
|
|
85
83
|
if (valueArray.length > 1) {
|
|
@@ -91,14 +89,14 @@ const selectOptions = async (element, values) => {
|
|
|
91
89
|
}
|
|
92
90
|
const isDropDown = element.constructor.name === "DropDown";
|
|
93
91
|
if (isDropDown) {
|
|
94
|
-
|
|
92
|
+
element.setSelected(value);
|
|
95
93
|
}
|
|
96
94
|
else {
|
|
97
|
-
|
|
95
|
+
element.setActive(value);
|
|
98
96
|
}
|
|
99
97
|
}
|
|
100
98
|
else if (role === AccessibleRole.LIST) {
|
|
101
|
-
const listBox =
|
|
99
|
+
const listBox = element;
|
|
102
100
|
for (const value of valueArray) {
|
|
103
101
|
if (typeof value !== "number") {
|
|
104
102
|
throw new Error("ListBox selection requires numeric indices");
|
|
@@ -112,16 +110,16 @@ const selectOptions = async (element, values) => {
|
|
|
112
110
|
await tick();
|
|
113
111
|
};
|
|
114
112
|
const deselectOptions = async (element, values) => {
|
|
115
|
-
const role =
|
|
113
|
+
const role = getInterface(element, Accessible).getAccessibleRole();
|
|
116
114
|
if (role !== AccessibleRole.LIST) {
|
|
117
115
|
throw new Error("Cannot deselect options: only ListBox supports deselection");
|
|
118
116
|
}
|
|
119
|
-
const listBox =
|
|
117
|
+
const listBox = element;
|
|
120
118
|
const valueArray = Array.isArray(values) ? values : [values];
|
|
121
119
|
for (const value of valueArray) {
|
|
122
120
|
const row = listBox.getRowAtIndex(value);
|
|
123
121
|
if (row) {
|
|
124
|
-
listBox.unselectRow(
|
|
122
|
+
listBox.unselectRow(row);
|
|
125
123
|
}
|
|
126
124
|
}
|
|
127
125
|
await tick();
|
package/dist/widget.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
1
|
import type * as Gtk from "@gtkx/ffi/gtk";
|
|
2
|
-
import { type Accessible } from "@gtkx/ffi/gtk";
|
|
3
|
-
export declare const asAccessible: (widget: Gtk.Widget) => Accessible;
|
|
4
2
|
export declare const isEditable: (widget: Gtk.Widget) => boolean;
|
|
5
3
|
export declare const hasLabel: (widget: Gtk.Widget) => boolean;
|
package/dist/widget.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { getInterface } from "@gtkx/ffi";
|
|
2
|
+
import { Accessible, AccessibleRole } from "@gtkx/ffi/gtk";
|
|
3
3
|
const EDITABLE_ROLES = new Set([AccessibleRole.TEXT_BOX, AccessibleRole.SEARCH_BOX, AccessibleRole.SPIN_BUTTON]);
|
|
4
4
|
export const isEditable = (widget) => {
|
|
5
|
-
const role =
|
|
5
|
+
const role = getInterface(widget, Accessible).getAccessibleRole();
|
|
6
6
|
return EDITABLE_ROLES.has(role);
|
|
7
7
|
};
|
|
8
8
|
const LABEL_ROLES = new Set([
|
|
@@ -16,6 +16,6 @@ const LABEL_ROLES = new Set([
|
|
|
16
16
|
AccessibleRole.MENU_ITEM_RADIO,
|
|
17
17
|
]);
|
|
18
18
|
export const hasLabel = (widget) => {
|
|
19
|
-
const role =
|
|
19
|
+
const role = getInterface(widget, Accessible).getAccessibleRole();
|
|
20
20
|
return LABEL_ROLES.has(role);
|
|
21
21
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gtkx/testing",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Testing utilities for GTKX applications",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"gtk",
|
|
@@ -32,9 +32,9 @@
|
|
|
32
32
|
"dist"
|
|
33
33
|
],
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@gtkx/ffi": "0.
|
|
36
|
-
"@gtkx/
|
|
37
|
-
"@gtkx/
|
|
35
|
+
"@gtkx/ffi": "0.3.1",
|
|
36
|
+
"@gtkx/native": "0.3.1",
|
|
37
|
+
"@gtkx/react": "0.3.1"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "tsc -b && cp ../../README.md .",
|