@elizaos/computeruse 0.24.20

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.
@@ -0,0 +1,264 @@
1
+ const { Desktop } = require("../index.js");
2
+
3
+ /**
4
+ * Test for Element.getValue() and setValue() methods
5
+ *
6
+ * Note: This test requires an application with text input fields.
7
+ * Common apps with text inputs: Notepad, Browser address bar, Settings search
8
+ */
9
+ async function testGetSetValue() {
10
+ console.log("📝 Testing Element getValue/setValue methods...");
11
+
12
+ try {
13
+ const desktop = new Desktop();
14
+
15
+ // Try to find a text input field (edit control)
16
+ console.log("Searching for text input fields...");
17
+
18
+ // Common roles for value-based controls: edit, textfield, combobox
19
+ const editLocator = desktop.locator("role:edit");
20
+
21
+ try {
22
+ const editField = await editLocator.first(2000);
23
+ console.log(`✅ Found edit field: ${editField.name() || '(unnamed)'}`);
24
+
25
+ // Test: Get current value
26
+ console.log("Test: Get current value");
27
+ const currentValue = editField.getValue();
28
+ console.log(` Current value: ${currentValue !== null ? `"${currentValue}"` : 'null'}`);
29
+
30
+ // Test: Set a new value
31
+ console.log("Test: Set value");
32
+ const testValue = "Test Input 123";
33
+ editField.setValue(testValue);
34
+ console.log(` Set value to: "${testValue}"`);
35
+
36
+ // Wait a bit for the UI to update
37
+ await new Promise(resolve => setTimeout(resolve, 500));
38
+
39
+ // Verify the value changed
40
+ const newValue = editField.getValue();
41
+ console.log(` New value: ${newValue !== null ? `"${newValue}"` : 'null'}`);
42
+
43
+ if (newValue === testValue) {
44
+ console.log(` ✅ Value set successfully`);
45
+ } else {
46
+ console.log(` âš ī¸ Value changed but doesn't match exactly (may be platform behavior)`);
47
+ }
48
+
49
+ // Restore original value if it existed
50
+ if (currentValue !== null) {
51
+ editField.setValue(currentValue);
52
+ console.log(` Restored original value: "${currentValue}"`);
53
+ } else {
54
+ // Clear the field
55
+ editField.setValue("");
56
+ console.log(` Cleared field`);
57
+ }
58
+
59
+ return true;
60
+ } catch (error) {
61
+ if (error.message && error.message.includes("Timed out")) {
62
+ console.log("â„šī¸ No edit field found - this is acceptable if no text input apps are running");
63
+ console.log(" Try running: Notepad, Browser, or Settings app with search field");
64
+ return true; // Not a test failure, just no suitable UI available
65
+ }
66
+ throw error;
67
+ }
68
+ } catch (error) {
69
+ console.error("❌ getValue/setValue test failed:", error.message);
70
+ return false;
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Test getValue with combo box
76
+ */
77
+ async function testComboBoxValue() {
78
+ console.log("📝 Testing combo box value...");
79
+
80
+ try {
81
+ const desktop = new Desktop();
82
+
83
+ // Try to find a combo box
84
+ console.log("Searching for combo box controls...");
85
+ const comboLocator = desktop.locator("role:combobox");
86
+
87
+ try {
88
+ const comboBox = await comboLocator.first(2000);
89
+ console.log(`✅ Found combo box: ${comboBox.name() || '(unnamed)'}`);
90
+
91
+ // Just verify we can read the value
92
+ const comboValue = comboBox.getValue();
93
+ console.log(` Combo box value: ${comboValue !== null ? `"${comboValue}"` : 'null'}`);
94
+
95
+ console.log("✅ Successfully read combo box value");
96
+ return true;
97
+ } catch (error) {
98
+ if (error.message && error.message.includes("Timed out")) {
99
+ console.log("â„šī¸ No combo box found - this is acceptable");
100
+ return true;
101
+ }
102
+ throw error;
103
+ }
104
+ } catch (error) {
105
+ console.error("❌ Combo box value test failed:", error.message);
106
+ return false;
107
+ }
108
+ }
109
+
110
+ /**
111
+ * Test getValue returns null for non-value elements
112
+ */
113
+ async function testGetValueNull() {
114
+ console.log("📝 Testing getValue with non-value element...");
115
+
116
+ try {
117
+ const desktop = new Desktop();
118
+
119
+ // Try to get value from a button (which shouldn't have a value attribute)
120
+ console.log("Test: Get value from button element");
121
+
122
+ try {
123
+ const button = await desktop.locator("role:button").first(2000);
124
+
125
+ const buttonValue = button.getValue();
126
+ if (buttonValue === null) {
127
+ console.log(` ✅ Correctly returned null for button element`);
128
+ } else {
129
+ console.log(` âš ī¸ Got value from button: "${buttonValue}" (unexpected but not fatal)`);
130
+ }
131
+
132
+ return true;
133
+ } catch (error) {
134
+ if (error.message && error.message.includes("Timed out")) {
135
+ console.log("â„šī¸ No button found for null value test");
136
+ return true;
137
+ }
138
+ throw error;
139
+ }
140
+ } catch (error) {
141
+ console.error("❌ getValue null test failed:", error.message);
142
+ return false;
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Test setValue with empty string
148
+ */
149
+ async function testSetValueEmpty() {
150
+ console.log("📝 Testing setValue with empty string...");
151
+
152
+ try {
153
+ const desktop = new Desktop();
154
+
155
+ console.log("Test: Set empty value");
156
+
157
+ try {
158
+ const editField = await desktop.locator("role:edit").first(2000);
159
+
160
+ // Get current value
161
+ const currentValue = editField.getValue();
162
+ console.log(` Current value: ${currentValue !== null ? `"${currentValue}"` : 'null'}`);
163
+
164
+ // Set to empty
165
+ editField.setValue("");
166
+ console.log(` Set value to empty string`);
167
+
168
+ await new Promise(resolve => setTimeout(resolve, 300));
169
+
170
+ // Verify it's empty
171
+ const emptyValue = editField.getValue();
172
+ console.log(` New value: ${emptyValue !== null ? `"${emptyValue}"` : 'null'}`);
173
+
174
+ if (emptyValue === "" || emptyValue === null) {
175
+ console.log(` ✅ Field cleared successfully`);
176
+ }
177
+
178
+ // Restore original value
179
+ if (currentValue !== null && currentValue !== "") {
180
+ editField.setValue(currentValue);
181
+ console.log(` Restored original value`);
182
+ }
183
+
184
+ return true;
185
+ } catch (error) {
186
+ if (error.message && error.message.includes("Timed out")) {
187
+ console.log("â„šī¸ No edit field found for empty value test");
188
+ return true;
189
+ }
190
+ throw error;
191
+ }
192
+ } catch (error) {
193
+ console.error("❌ setValue empty test failed:", error.message);
194
+ return false;
195
+ }
196
+ }
197
+
198
+ /**
199
+ * Main test runner
200
+ */
201
+ async function runValueTests() {
202
+ console.log("🚀 Starting Element value tests...\n");
203
+
204
+ let passed = 0;
205
+ let total = 0;
206
+
207
+ // Test 1: Basic get/set value
208
+ total++;
209
+ if (await testGetSetValue()) {
210
+ passed++;
211
+ }
212
+
213
+ console.log(); // Empty line
214
+
215
+ // Test 2: Combo box value
216
+ total++;
217
+ if (await testComboBoxValue()) {
218
+ passed++;
219
+ }
220
+
221
+ console.log(); // Empty line
222
+
223
+ // Test 3: getValue returns null
224
+ total++;
225
+ if (await testGetValueNull()) {
226
+ passed++;
227
+ }
228
+
229
+ console.log(); // Empty line
230
+
231
+ // Test 4: setValue empty string
232
+ total++;
233
+ if (await testSetValueEmpty()) {
234
+ passed++;
235
+ }
236
+
237
+ console.log(); // Empty line
238
+
239
+ // Results
240
+ if (passed === total) {
241
+ console.log(`🎉 All value tests passed! (${passed}/${total})`);
242
+ process.exit(0);
243
+ } else {
244
+ console.log(`❌ Some tests failed: ${passed}/${total} passed`);
245
+ process.exit(1);
246
+ }
247
+ }
248
+
249
+ // Export for use in other test files
250
+ module.exports = {
251
+ testGetSetValue,
252
+ testComboBoxValue,
253
+ testGetValueNull,
254
+ testSetValueEmpty,
255
+ runValueTests,
256
+ };
257
+
258
+ // Run tests if this file is executed directly
259
+ if (require.main === module) {
260
+ runValueTests().catch((error) => {
261
+ console.error("đŸ’Ĩ Test runner crashed:", error);
262
+ process.exit(1);
263
+ });
264
+ }
@@ -0,0 +1,135 @@
1
+ const assert = require("assert");
2
+ const path = require("path");
3
+ const fs = require("fs");
4
+
5
+ const { Desktop } = require("../wrapper.js");
6
+
7
+ async function testFunctionInput() {
8
+ let capturedScript = null;
9
+ const expected = { greeting: "hello", answer: 42 };
10
+ const fake = {
11
+ _originalExecuteBrowserScript: async (script) => {
12
+ capturedScript = script;
13
+ return JSON.stringify(expected);
14
+ },
15
+ };
16
+
17
+ const result = await Desktop.prototype.executeBrowserScript.call(
18
+ fake,
19
+ ({ greeting, answer }) => ({ greeting, answer }),
20
+ { greeting: "hello", answer: 42 },
21
+ );
22
+
23
+ assert.deepStrictEqual(result, expected);
24
+ assert.ok(
25
+ capturedScript.includes('"greeting":"hello"') &&
26
+ capturedScript.includes('"answer":42'),
27
+ "env payload should be embedded in generated script",
28
+ );
29
+ assert.ok(
30
+ capturedScript.trim().startsWith("(async function()"),
31
+ "generated script should be wrapped in async IIFE",
32
+ );
33
+ }
34
+
35
+ async function testStringInput() {
36
+ const fake = {
37
+ _originalExecuteBrowserScript: async () => "raw-result",
38
+ };
39
+ const script = '(() => "ignored")()';
40
+ const result = await Desktop.prototype.executeBrowserScript.call(
41
+ fake,
42
+ script,
43
+ );
44
+ assert.strictEqual(result, "raw-result");
45
+ }
46
+
47
+ async function testFileInput() {
48
+ const fixturePath = path.join(
49
+ __dirname,
50
+ "fixtures",
51
+ "sample-browser-script.js",
52
+ );
53
+ const expectedScript = fs.readFileSync(fixturePath, "utf8");
54
+ let receivedScript = null;
55
+ const fake = {
56
+ _originalExecuteBrowserScript: async (script) => {
57
+ receivedScript = script;
58
+ return "file-result";
59
+ },
60
+ };
61
+
62
+ // Test without env - should not inject
63
+ const result = await Desktop.prototype.executeBrowserScript.call(fake, {
64
+ file: fixturePath,
65
+ });
66
+
67
+ assert.strictEqual(result, "file-result");
68
+ assert.strictEqual(receivedScript, expectedScript);
69
+ }
70
+
71
+ async function testFileInputWithEnvInjection() {
72
+ const fixturePath = path.join(__dirname, "fixtures", "script-with-env.js");
73
+ const columnPositions = [10, 20, 30];
74
+ let receivedScript = null;
75
+ const fake = {
76
+ _originalExecuteBrowserScript: async (script) => {
77
+ receivedScript = script;
78
+ // Simulate executing the script with injected env
79
+ const column_positions = columnPositions;
80
+ const result = eval(script);
81
+ return JSON.stringify(result);
82
+ },
83
+ };
84
+
85
+ const result = await Desktop.prototype.executeBrowserScript.call(fake, {
86
+ file: fixturePath,
87
+ env: { column_positions: columnPositions },
88
+ });
89
+
90
+ // Result comes back as JSON string for file-based scripts
91
+ const parsed = JSON.parse(result);
92
+ assert.deepStrictEqual(parsed, {
93
+ positions: columnPositions,
94
+ count: 3,
95
+ });
96
+
97
+ // Verify the env was injected into the script as an env object
98
+ assert.ok(
99
+ receivedScript.includes("const env = "),
100
+ "env object should be injected into script",
101
+ );
102
+ assert.ok(
103
+ receivedScript.includes('"column_positions"'),
104
+ "column_positions key should be in env object",
105
+ );
106
+ assert.ok(
107
+ receivedScript.includes(JSON.stringify(columnPositions)),
108
+ "column_positions value should be embedded",
109
+ );
110
+ }
111
+
112
+ async function run() {
113
+ try {
114
+ await testFunctionInput();
115
+ console.log("✅ executeBrowserScript handles function input");
116
+
117
+ await testStringInput();
118
+ console.log("✅ executeBrowserScript preserves string behavior");
119
+
120
+ await testFileInput();
121
+ console.log("✅ executeBrowserScript loads scripts from files");
122
+
123
+ await testFileInputWithEnvInjection();
124
+ console.log(
125
+ "✅ executeBrowserScript injects env variables into file scripts",
126
+ );
127
+
128
+ console.log("🎉 All executeBrowserScript wrapper tests passed");
129
+ } catch (err) {
130
+ console.error("❌ executeBrowserScript wrapper test failed:", err);
131
+ process.exitCode = 1;
132
+ }
133
+ }
134
+
135
+ run();
@@ -0,0 +1,7 @@
1
+ (() => {
2
+ const el = document.querySelector('h1');
3
+ const text = el ? el.textContent : 'no-heading';
4
+ return `fixture:${text}`;
5
+ })()
6
+
7
+
@@ -0,0 +1,16 @@
1
+ // Browser script that uses injected env object
2
+ (() => {
3
+ // env object should be auto-injected by wrapper
4
+ if (typeof env === "undefined") {
5
+ throw new Error("env not injected");
6
+ }
7
+
8
+ if (!env.column_positions) {
9
+ throw new Error("column_positions not in env");
10
+ }
11
+
12
+ return {
13
+ positions: env.column_positions,
14
+ count: env.column_positions.length,
15
+ };
16
+ })();
@@ -0,0 +1,260 @@
1
+ const { Desktop } = require("../index.js");
2
+
3
+ /**
4
+ * Test for Locator.validate() method
5
+ * This test verifies that validate() returns ValidationResult without throwing errors
6
+ */
7
+ async function testValidateExists() {
8
+ console.log("🔍 Testing Locator.validate() for existing elements...");
9
+
10
+ try {
11
+ const desktop = new Desktop();
12
+
13
+ // Get any available application for testing
14
+ const apps = desktop.applications();
15
+ if (apps.length === 0) {
16
+ throw new Error("No applications found for testing");
17
+ }
18
+
19
+ const testApp = apps[0];
20
+ console.log(`📱 Testing with app: ${testApp.name()}`);
21
+
22
+ // Test 1: Validate an existing element (the app window itself)
23
+ console.log("Test 1: Validate existing element");
24
+ const result = await desktop.locator("role:window").validate(2000);
25
+
26
+ if (!result.exists) {
27
+ throw new Error("Expected element to exist");
28
+ }
29
+ if (!result.element) {
30
+ throw new Error("Expected element to be present in result");
31
+ }
32
+ if (result.error) {
33
+ throw new Error(`Expected no error, got: ${result.error}`);
34
+ }
35
+
36
+ console.log(`✅ Window element found: ${result.element.name()}`);
37
+
38
+ return true;
39
+ } catch (error) {
40
+ console.error("❌ Validate exists test failed:", error.message);
41
+ return false;
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Test validate() with non-existent element
47
+ */
48
+ async function testValidateNotExists() {
49
+ console.log("🔍 Testing Locator.validate() for non-existent elements...");
50
+
51
+ try {
52
+ const desktop = new Desktop();
53
+
54
+ // Test: Validate a non-existent element
55
+ console.log("Test: Validate non-existent element");
56
+ const result = await desktop
57
+ .locator("role:button|ThisButtonDoesNotExist12345XYZ")
58
+ .validate(1000);
59
+
60
+ if (result.exists) {
61
+ throw new Error("Expected element to not exist");
62
+ }
63
+ if (result.element) {
64
+ throw new Error("Expected element to be undefined");
65
+ }
66
+ if (result.error) {
67
+ // Errors should only happen for invalid selectors, not for "not found"
68
+ throw new Error(`Unexpected error in validation: ${result.error}`);
69
+ }
70
+
71
+ console.log("✅ Correctly reported element as not existing");
72
+
73
+ return true;
74
+ } catch (error) {
75
+ console.error("❌ Validate not exists test failed:", error.message);
76
+ return false;
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Test validate() with chained locators
82
+ */
83
+ async function testValidateChaining() {
84
+ console.log("🔍 Testing Locator.validate() with chaining...");
85
+
86
+ try {
87
+ const desktop = new Desktop();
88
+ const apps = desktop.applications();
89
+
90
+ if (apps.length === 0) {
91
+ throw new Error("No applications found for testing");
92
+ }
93
+
94
+ const testApp = apps[0];
95
+
96
+ // Test: Validate with chained locator
97
+ console.log("Test: Validate with chained locator");
98
+ const result = await testApp
99
+ .locator("role:window")
100
+ .locator("role:button")
101
+ .validate(2000);
102
+
103
+ // Either exists or doesn't exist - both are valid, we just check no crash
104
+ if (result.exists) {
105
+ console.log(`✅ Found button in chain: ${result.element.name()}`);
106
+ } else {
107
+ console.log("✅ No button found in chain (expected)");
108
+ }
109
+
110
+ if (result.error) {
111
+ throw new Error(`Unexpected error: ${result.error}`);
112
+ }
113
+
114
+ return true;
115
+ } catch (error) {
116
+ console.error("❌ Validate chaining test failed:", error.message);
117
+ return false;
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Test validate() with zero timeout
123
+ */
124
+ async function testValidateZeroTimeout() {
125
+ console.log("🔍 Testing Locator.validate() with zero timeout...");
126
+
127
+ try {
128
+ const desktop = new Desktop();
129
+
130
+ // Test: Immediate validation (no retry)
131
+ console.log("Test: Validate with zero timeout (immediate)");
132
+ const result = await desktop.locator("role:window").validate(0);
133
+
134
+ // With zero timeout, should still find immediate elements
135
+ console.log(`✅ Immediate validation returned: exists=${result.exists}`);
136
+
137
+ return true;
138
+ } catch (error) {
139
+ console.error("❌ Validate zero timeout test failed:", error.message);
140
+ return false;
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Test that validate() doesn't throw like first() does
146
+ */
147
+ async function testValidateVsFirst() {
148
+ console.log("🔍 Testing validate() vs first() behavior...");
149
+
150
+ try {
151
+ const desktop = new Desktop();
152
+ const selector = "role:button|ThisButtonDoesNotExist12345XYZ";
153
+
154
+ // Test: first() should throw
155
+ console.log("Test: Verifying first() throws on not found");
156
+ let firstThrew = false;
157
+ try {
158
+ await desktop.locator(selector).first(500);
159
+ } catch (err) {
160
+ firstThrew = true;
161
+ console.log("✅ first() correctly threw error");
162
+ }
163
+
164
+ if (!firstThrew) {
165
+ throw new Error("Expected first() to throw, but it didn't");
166
+ }
167
+
168
+ // Test: validate() should NOT throw
169
+ console.log("Test: Verifying validate() doesn't throw on not found");
170
+ const result = await desktop.locator(selector).validate(500);
171
+
172
+ if (result.exists) {
173
+ throw new Error("Expected element to not exist");
174
+ }
175
+
176
+ console.log("✅ validate() correctly returned {exists: false} without throwing");
177
+
178
+ return true;
179
+ } catch (error) {
180
+ console.error("❌ Validate vs first test failed:", error.message);
181
+ return false;
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Main test runner
187
+ */
188
+ async function runValidateTests() {
189
+ console.log("🚀 Starting Locator.validate() tests...\n");
190
+
191
+ let passed = 0;
192
+ let total = 0;
193
+
194
+ // Test 1: Validate existing element
195
+ total++;
196
+ if (await testValidateExists()) {
197
+ passed++;
198
+ }
199
+
200
+ console.log(); // Empty line
201
+
202
+ // Test 2: Validate non-existent element
203
+ total++;
204
+ if (await testValidateNotExists()) {
205
+ passed++;
206
+ }
207
+
208
+ console.log(); // Empty line
209
+
210
+ // Test 3: Validate with chaining
211
+ total++;
212
+ if (await testValidateChaining()) {
213
+ passed++;
214
+ }
215
+
216
+ console.log(); // Empty line
217
+
218
+ // Test 4: Validate with zero timeout
219
+ total++;
220
+ if (await testValidateZeroTimeout()) {
221
+ passed++;
222
+ }
223
+
224
+ console.log(); // Empty line
225
+
226
+ // Test 5: Validate vs first behavior
227
+ total++;
228
+ if (await testValidateVsFirst()) {
229
+ passed++;
230
+ }
231
+
232
+ console.log(); // Empty line
233
+
234
+ // Results
235
+ if (passed === total) {
236
+ console.log(`🎉 All validate tests passed! (${passed}/${total})`);
237
+ process.exit(0);
238
+ } else {
239
+ console.log(`❌ Some tests failed: ${passed}/${total} passed`);
240
+ process.exit(1);
241
+ }
242
+ }
243
+
244
+ // Export for use in other test files
245
+ module.exports = {
246
+ testValidateExists,
247
+ testValidateNotExists,
248
+ testValidateChaining,
249
+ testValidateZeroTimeout,
250
+ testValidateVsFirst,
251
+ runValidateTests,
252
+ };
253
+
254
+ // Run tests if this file is executed directly
255
+ if (require.main === module) {
256
+ runValidateTests().catch((error) => {
257
+ console.error("đŸ’Ĩ Test runner crashed:", error);
258
+ process.exit(1);
259
+ });
260
+ }