@gtkx/testing 0.3.0 → 0.3.2
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 +0 -3
- package/dist/queries.js +20 -20
- package/dist/render.js +5 -5
- package/dist/user-event.js +10 -10
- package/dist/widget.js +4 -4
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -64,7 +64,6 @@ npm install -D @types/react typescript
|
|
|
64
64
|
Create your first app:
|
|
65
65
|
|
|
66
66
|
```tsx
|
|
67
|
-
// src/app.tsx
|
|
68
67
|
import { useState } from "react";
|
|
69
68
|
import * as Gtk from "@gtkx/ffi/gtk";
|
|
70
69
|
import { ApplicationWindow, Box, Button, Label, quit } from "@gtkx/react";
|
|
@@ -98,7 +97,6 @@ export const appId = "org.example.MyApp";
|
|
|
98
97
|
```
|
|
99
98
|
|
|
100
99
|
```tsx
|
|
101
|
-
// src/index.tsx
|
|
102
100
|
import { render } from "@gtkx/react";
|
|
103
101
|
import App, { appId } from "./app.js";
|
|
104
102
|
|
|
@@ -147,7 +145,6 @@ import { cleanup, render, screen, userEvent, fireEvent } from "@gtkx/testing";
|
|
|
147
145
|
import { AccessibleRole } from "@gtkx/ffi/gtk";
|
|
148
146
|
import { App } from "./app.js";
|
|
149
147
|
|
|
150
|
-
// Clean up after each test
|
|
151
148
|
afterEach(async () => {
|
|
152
149
|
await cleanup();
|
|
153
150
|
});
|
package/dist/queries.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { AccessibleRole, } 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
5
|
const DEFAULT_NORMALIZER = (text) => text.trim().replace(/\s+/g, " ");
|
|
@@ -30,38 +30,38 @@ const ROLES_WITH_INTERNAL_LABELS = new Set([
|
|
|
30
30
|
AccessibleRole.LINK,
|
|
31
31
|
]);
|
|
32
32
|
const isInternalLabel = (widget) => {
|
|
33
|
-
const accessible =
|
|
33
|
+
const accessible = getInterface(widget, Accessible);
|
|
34
34
|
if (accessible.getAccessibleRole() !== AccessibleRole.LABEL)
|
|
35
35
|
return false;
|
|
36
36
|
const parent = widget.getParent();
|
|
37
37
|
if (!parent)
|
|
38
38
|
return false;
|
|
39
|
-
const parentRole =
|
|
39
|
+
const parentRole = getInterface(parent, Accessible).getAccessibleRole();
|
|
40
40
|
return ROLES_WITH_INTERNAL_LABELS.has(parentRole);
|
|
41
41
|
};
|
|
42
42
|
const getWidgetText = (widget) => {
|
|
43
43
|
if (isInternalLabel(widget))
|
|
44
44
|
return null;
|
|
45
|
-
const role =
|
|
45
|
+
const role = getInterface(widget, Accessible).getAccessibleRole();
|
|
46
46
|
switch (role) {
|
|
47
47
|
case AccessibleRole.BUTTON:
|
|
48
48
|
case AccessibleRole.LINK:
|
|
49
49
|
case AccessibleRole.TAB:
|
|
50
|
-
return
|
|
50
|
+
return getInterface(widget, Button).getLabel();
|
|
51
51
|
case AccessibleRole.TOGGLE_BUTTON:
|
|
52
|
-
return
|
|
52
|
+
return getInterface(widget, ToggleButton).getLabel();
|
|
53
53
|
case AccessibleRole.CHECKBOX:
|
|
54
54
|
case AccessibleRole.RADIO:
|
|
55
|
-
return
|
|
55
|
+
return getInterface(widget, CheckButton).getLabel();
|
|
56
56
|
case AccessibleRole.LABEL:
|
|
57
|
-
return
|
|
57
|
+
return getInterface(widget, Label).getLabel();
|
|
58
58
|
case AccessibleRole.TEXT_BOX:
|
|
59
59
|
case AccessibleRole.SEARCH_BOX:
|
|
60
60
|
case AccessibleRole.SPIN_BUTTON:
|
|
61
|
-
return
|
|
61
|
+
return getInterface(widget, Editable).getText();
|
|
62
62
|
case AccessibleRole.GROUP:
|
|
63
63
|
try {
|
|
64
|
-
return
|
|
64
|
+
return getInterface(widget, Frame).getLabel();
|
|
65
65
|
}
|
|
66
66
|
catch {
|
|
67
67
|
return null;
|
|
@@ -69,10 +69,10 @@ const getWidgetText = (widget) => {
|
|
|
69
69
|
case AccessibleRole.WINDOW:
|
|
70
70
|
case AccessibleRole.DIALOG:
|
|
71
71
|
case AccessibleRole.ALERT_DIALOG:
|
|
72
|
-
return
|
|
72
|
+
return getInterface(widget, Window).getTitle();
|
|
73
73
|
case AccessibleRole.TAB_PANEL:
|
|
74
74
|
try {
|
|
75
|
-
return
|
|
75
|
+
return getInterface(widget, StackPage).getTitle();
|
|
76
76
|
}
|
|
77
77
|
catch {
|
|
78
78
|
return null;
|
|
@@ -87,26 +87,26 @@ const getWidgetTestId = (widget) => {
|
|
|
87
87
|
return widget.getName();
|
|
88
88
|
};
|
|
89
89
|
const getWidgetCheckedState = (widget) => {
|
|
90
|
-
const role =
|
|
90
|
+
const role = getInterface(widget, Accessible).getAccessibleRole();
|
|
91
91
|
switch (role) {
|
|
92
92
|
case AccessibleRole.CHECKBOX:
|
|
93
93
|
case AccessibleRole.RADIO:
|
|
94
|
-
return
|
|
94
|
+
return getInterface(widget, CheckButton).getActive();
|
|
95
95
|
case AccessibleRole.TOGGLE_BUTTON:
|
|
96
|
-
return
|
|
96
|
+
return getInterface(widget, ToggleButton).getActive();
|
|
97
97
|
case AccessibleRole.SWITCH:
|
|
98
|
-
return
|
|
98
|
+
return getInterface(widget, Switch).getActive();
|
|
99
99
|
default:
|
|
100
100
|
return undefined;
|
|
101
101
|
}
|
|
102
102
|
};
|
|
103
103
|
const getWidgetExpandedState = (widget) => {
|
|
104
|
-
const role =
|
|
104
|
+
const role = getInterface(widget, Accessible).getAccessibleRole();
|
|
105
105
|
if (role === AccessibleRole.BUTTON) {
|
|
106
106
|
const parent = widget.getParent();
|
|
107
107
|
if (!parent)
|
|
108
108
|
return undefined;
|
|
109
|
-
return
|
|
109
|
+
return getInterface(parent, Expander).getExpanded();
|
|
110
110
|
}
|
|
111
111
|
return undefined;
|
|
112
112
|
};
|
|
@@ -149,7 +149,7 @@ const formatByRoleError = (role, options) => {
|
|
|
149
149
|
};
|
|
150
150
|
const getAllByRole = (container, role, options) => {
|
|
151
151
|
const matches = findAll(container, (node) => {
|
|
152
|
-
if (
|
|
152
|
+
if (getInterface(node, Accessible).getAccessibleRole() !== role)
|
|
153
153
|
return false;
|
|
154
154
|
return matchByRoleOptions(node, options);
|
|
155
155
|
});
|
package/dist/render.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
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";
|
|
@@ -12,15 +12,15 @@ 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,16 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { AccessibleRole, DirectionType, } from "@gtkx/ffi/gtk";
|
|
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
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
15
|
const checkButton = element;
|
|
16
16
|
checkButton.setActive(!checkButton.getActive());
|
|
@@ -48,7 +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
|
-
|
|
51
|
+
getInterface(root, Widget).childFocus(direction);
|
|
52
52
|
}
|
|
53
53
|
await tick();
|
|
54
54
|
};
|
|
@@ -56,7 +56,7 @@ const type = async (element, text) => {
|
|
|
56
56
|
if (!isEditable(element)) {
|
|
57
57
|
throw new Error("Cannot type into element: element is not editable (TEXT_BOX, SEARCH_BOX, or SPIN_BUTTON)");
|
|
58
58
|
}
|
|
59
|
-
const editable =
|
|
59
|
+
const editable = getInterface(element, Editable);
|
|
60
60
|
const currentText = editable.getText();
|
|
61
61
|
editable.setText(currentText + text);
|
|
62
62
|
await tick();
|
|
@@ -65,19 +65,19 @@ const clear = async (element) => {
|
|
|
65
65
|
if (!isEditable(element)) {
|
|
66
66
|
throw new Error("Cannot clear element: element is not editable (TEXT_BOX, SEARCH_BOX, or SPIN_BUTTON)");
|
|
67
67
|
}
|
|
68
|
-
|
|
68
|
+
getInterface(element, Editable).setText("");
|
|
69
69
|
await tick();
|
|
70
70
|
};
|
|
71
71
|
const SELECTABLE_ROLES = new Set([AccessibleRole.COMBO_BOX, AccessibleRole.LIST]);
|
|
72
72
|
const isSelectable = (widget) => {
|
|
73
|
-
const role =
|
|
73
|
+
const role = getInterface(widget, Accessible).getAccessibleRole();
|
|
74
74
|
return SELECTABLE_ROLES.has(role);
|
|
75
75
|
};
|
|
76
76
|
const selectOptions = async (element, values) => {
|
|
77
77
|
if (!isSelectable(element)) {
|
|
78
78
|
throw new Error("Cannot select options: element is not a selectable widget (COMBO_BOX or LIST)");
|
|
79
79
|
}
|
|
80
|
-
const role =
|
|
80
|
+
const role = getInterface(element, Accessible).getAccessibleRole();
|
|
81
81
|
const valueArray = Array.isArray(values) ? values : [values];
|
|
82
82
|
if (role === AccessibleRole.COMBO_BOX) {
|
|
83
83
|
if (valueArray.length > 1) {
|
|
@@ -110,7 +110,7 @@ const selectOptions = async (element, values) => {
|
|
|
110
110
|
await tick();
|
|
111
111
|
};
|
|
112
112
|
const deselectOptions = async (element, values) => {
|
|
113
|
-
const role =
|
|
113
|
+
const role = getInterface(element, Accessible).getAccessibleRole();
|
|
114
114
|
if (role !== AccessibleRole.LIST) {
|
|
115
115
|
throw new Error("Cannot deselect options: only ListBox supports deselection");
|
|
116
116
|
}
|
package/dist/widget.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { AccessibleRole } from "@gtkx/ffi/gtk";
|
|
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.
|
|
3
|
+
"version": "0.3.2",
|
|
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.3.
|
|
36
|
-
"@gtkx/native": "0.3.
|
|
37
|
-
"@gtkx/react": "0.3.
|
|
35
|
+
"@gtkx/ffi": "0.3.2",
|
|
36
|
+
"@gtkx/native": "0.3.2",
|
|
37
|
+
"@gtkx/react": "0.3.2"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "tsc -b && cp ../../README.md .",
|