testdriverai 5.6.2 → 5.6.3
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/agent.js +3 -3
- package/docs/support/known-bugs.mdx +85 -0
- package/index.js +1 -0
- package/lib/commander.js +1 -1
- package/lib/commands.js +9 -0
- package/lib/focus-application.js +7 -5
- package/package.json +1 -1
package/agent.js
CHANGED
|
@@ -233,14 +233,14 @@ const haveAIResolveError = async (
|
|
|
233
233
|
|
|
234
234
|
let safeKey = JSON.stringify(eMessage);
|
|
235
235
|
errorCounts[safeKey] = errorCounts[safeKey] ? errorCounts[safeKey] + 1 : 1;
|
|
236
|
+
|
|
237
|
+
logger.error(chalk.red("Error detected"));
|
|
236
238
|
|
|
237
|
-
|
|
239
|
+
log.prettyMarkdown(eMessage);
|
|
238
240
|
|
|
239
241
|
logger.debug("%j", error);
|
|
240
242
|
logger.debug("%s", error.stack);
|
|
241
243
|
|
|
242
|
-
log.prettyMarkdown(eMessage);
|
|
243
|
-
|
|
244
244
|
// if we get the same error 3 times in `run` mode, we exit
|
|
245
245
|
if (errorCounts[safeKey] > errorLimit - 1) {
|
|
246
246
|
logger.info(chalk.red("Error loop detected. Exiting."));
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: macOS Automation Limitations
|
|
3
|
+
description: Understanding the limitations of synthetic input automation on macOS when using tools like robot.js in TestDriver.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# macOS Automation Limitations
|
|
7
|
+
|
|
8
|
+
macOS includes several system-level security features that affect how synthetic input—like mouse clicks and keyboard presses generated by automation tools—is interpreted. If you're using tools like `robot.js` for test automation, it's important to understand which applications and interactions may be blocked or ignored by the system.
|
|
9
|
+
|
|
10
|
+
## 🔐 System-Level Protected Apps
|
|
11
|
+
|
|
12
|
+
Some macOS applications are **heavily protected** by System Integrity Protection (SIP) and will **not respond to synthetic input**, even if Accessibility permissions are granted.
|
|
13
|
+
|
|
14
|
+
Examples include:
|
|
15
|
+
|
|
16
|
+
- **Finder**
|
|
17
|
+
- **System Settings / System Preferences**
|
|
18
|
+
- **Dock**
|
|
19
|
+
- **Menu Bar**
|
|
20
|
+
- **Login Window**
|
|
21
|
+
- **Launchpad**
|
|
22
|
+
- **Installer**
|
|
23
|
+
- **File Open / Save Dialogs**
|
|
24
|
+
|
|
25
|
+
These apps typically ignore input generated by tools like `robot.js` or even AppleScript unless scripted via system-sanctioned methods.
|
|
26
|
+
|
|
27
|
+
<Alert type="warning" title="Heads up">
|
|
28
|
+
Synthetic double-clicks often fail in Finder, even when the correct timing and coordinates are used.
|
|
29
|
+
</Alert>
|
|
30
|
+
|
|
31
|
+
## 🛡️ TCC-Protected Applications
|
|
32
|
+
|
|
33
|
+
Apps protected by Transparency, Consent, and Control (TCC) **can be automated** if the right permissions are granted.
|
|
34
|
+
|
|
35
|
+
To enable automation for these apps:
|
|
36
|
+
|
|
37
|
+
1. Go to **System Settings > Privacy & Security > Accessibility**
|
|
38
|
+
2. Add and check the app or terminal running your automation (e.g., Terminal, iTerm, VS Code).
|
|
39
|
+
3. You may also need to grant:
|
|
40
|
+
- **Input Monitoring**
|
|
41
|
+
- **Screen Recording**
|
|
42
|
+
- **Full Disk Access**
|
|
43
|
+
|
|
44
|
+
These permissions allow tools like `robot.js` to simulate clicks, keystrokes, and screen interactions in:
|
|
45
|
+
|
|
46
|
+
- **Google Chrome**
|
|
47
|
+
- **Safari**
|
|
48
|
+
- **Slack**
|
|
49
|
+
- **Mail**
|
|
50
|
+
- **Calendar**
|
|
51
|
+
- **Notes**
|
|
52
|
+
- **VS Code**
|
|
53
|
+
- **Xcode**
|
|
54
|
+
|
|
55
|
+
## ⚙️ Best Targets for UI Automation
|
|
56
|
+
|
|
57
|
+
For reliable automation, use `robot.js` or TestDriver with:
|
|
58
|
+
|
|
59
|
+
- Chromium-based browsers (Chrome, Brave, Edge)
|
|
60
|
+
- Electron apps (Slack, Discord)
|
|
61
|
+
- Most third-party GUI apps
|
|
62
|
+
- Terminal emulators
|
|
63
|
+
|
|
64
|
+
These apps typically respect synthetic input when appropriate permissions are granted.
|
|
65
|
+
|
|
66
|
+
## 🚫 Actions That Can't Be Automated
|
|
67
|
+
|
|
68
|
+
macOS enforces strict security policies on certain sensitive UI elements. Automation is **not possible** for:
|
|
69
|
+
|
|
70
|
+
- Login screen interactions
|
|
71
|
+
- Security permission prompts (e.g., “Allow Screen Recording”)
|
|
72
|
+
- Password input in secure dialogs
|
|
73
|
+
- Force Quit window
|
|
74
|
+
- Crash reporter popups
|
|
75
|
+
|
|
76
|
+
## ✅ Recommendations
|
|
77
|
+
|
|
78
|
+
- Always **grant Accessibility permissions** to the app or terminal running `robot.js`.
|
|
79
|
+
- Use **AppleScript** for system apps like Finder or System Settings.
|
|
80
|
+
- For GUI testing, prefer apps that are not protected by SIP.
|
|
81
|
+
- Consider using native tools like **XCUITest** or **Appium** for native macOS apps.
|
|
82
|
+
|
|
83
|
+
<Alert type="info" title="Need Help?">
|
|
84
|
+
If you're running into automation issues in specific apps, reach out on Discord or contact the TestDriver team.
|
|
85
|
+
</Alert>
|
package/index.js
CHANGED
package/lib/commander.js
CHANGED
package/lib/commands.js
CHANGED
|
@@ -233,6 +233,9 @@ const scroll = async (direction = "down", amount = 300, method = "mouse") => {
|
|
|
233
233
|
// perform a mouse click
|
|
234
234
|
// click, right-click, double-click, hover
|
|
235
235
|
const click = async (x, y, action = "click") => {
|
|
236
|
+
|
|
237
|
+
emitter.emit(events.interactive, true);
|
|
238
|
+
|
|
236
239
|
await redraw.start();
|
|
237
240
|
|
|
238
241
|
let button = "left";
|
|
@@ -256,6 +259,7 @@ const click = async (x, y, action = "click") => {
|
|
|
256
259
|
config.TD_VM
|
|
257
260
|
? await sandbox.send({ type: "moveMouse", x, y })
|
|
258
261
|
: await robot.moveMouseSmooth(x, y, 0.1);
|
|
262
|
+
|
|
259
263
|
emitter.emit(events.mouseMove, { x, y });
|
|
260
264
|
|
|
261
265
|
await delay(1000); // wait for the mouse to move
|
|
@@ -286,8 +290,10 @@ const click = async (x, y, action = "click") => {
|
|
|
286
290
|
} else if (action === "drag-end") {
|
|
287
291
|
robot.mouseToggle("up", button);
|
|
288
292
|
} else {
|
|
293
|
+
|
|
289
294
|
robot.mouseClick(button, double);
|
|
290
295
|
}
|
|
296
|
+
|
|
291
297
|
}
|
|
292
298
|
|
|
293
299
|
emitter.emit(events.mouseClick, { x, y, button, click });
|
|
@@ -299,6 +305,9 @@ const click = async (x, y, action = "click") => {
|
|
|
299
305
|
}
|
|
300
306
|
|
|
301
307
|
await redraw.wait(5000);
|
|
308
|
+
|
|
309
|
+
emitter.emit(events.interactive, false);
|
|
310
|
+
|
|
302
311
|
return;
|
|
303
312
|
};
|
|
304
313
|
|
package/lib/focus-application.js
CHANGED
|
@@ -49,7 +49,7 @@ async function focusApplication(appName) {
|
|
|
49
49
|
if (config.TD_VM) {
|
|
50
50
|
let result = await sandbox.send({type: "commands.run", command: `/home/user/scripts/control_window.sh "${appName}" Focus`});
|
|
51
51
|
if (result.type == "error") {
|
|
52
|
-
logger.
|
|
52
|
+
logger.debug(result.error.result.stdout);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
return;
|
|
@@ -65,7 +65,7 @@ async function focusApplication(appName) {
|
|
|
65
65
|
return runPwsh(appName, "Focus");
|
|
66
66
|
}
|
|
67
67
|
} catch (error) {
|
|
68
|
-
logger.
|
|
68
|
+
logger.debug(error);
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
|
|
@@ -79,7 +79,7 @@ async function hideTerminal(appName) {
|
|
|
79
79
|
return runPwsh(appName, "Minimize");
|
|
80
80
|
}
|
|
81
81
|
} catch (error) {
|
|
82
|
-
logger.
|
|
82
|
+
logger.debug(error);
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
}
|
|
@@ -88,12 +88,14 @@ async function showTerminal(appName) {
|
|
|
88
88
|
if (!config.TD_VM) {
|
|
89
89
|
try {
|
|
90
90
|
if (platform() == "mac") {
|
|
91
|
-
|
|
91
|
+
await execSync(`osascript -e '${appleScriptActivate(appName)}'`);
|
|
92
|
+
await execSync(`osascript -e '${appleScriptSetFrontmost(appName)}'`);
|
|
93
|
+
|
|
92
94
|
} else if (platform() == "windows") {
|
|
93
95
|
return runPwsh(appName, "Restore");
|
|
94
96
|
}
|
|
95
97
|
} catch (error) {
|
|
96
|
-
logger.
|
|
98
|
+
logger.debug(error);
|
|
97
99
|
}
|
|
98
100
|
}
|
|
99
101
|
}
|