testdriverai 5.1.2 → 5.2.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/electron/overlay.html +38 -2
- package/electron/overlay.js +1 -1
- package/lib/commands.js +70 -83
- package/lib/events.js +1 -0
- package/lib/init.js +1 -1
- package/lib/overlay.js +0 -1
- package/package.json +1 -1
package/electron/overlay.html
CHANGED
|
@@ -93,9 +93,9 @@
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
.box {
|
|
96
|
-
border:
|
|
96
|
+
border: 1px solid #B0CF34;
|
|
97
97
|
position: absolute;
|
|
98
|
-
|
|
98
|
+
border-radius: 5px;
|
|
99
99
|
animation-duration: 5s;
|
|
100
100
|
animation-delay: 0s;
|
|
101
101
|
animation-timing-function: cubic-bezier(0.26, 0.53, 0.74, 1.48);
|
|
@@ -111,6 +111,29 @@
|
|
|
111
111
|
position: absolute;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
+
#mouse {
|
|
115
|
+
margin-left: -100px;
|
|
116
|
+
margin-top: -100px;
|
|
117
|
+
width: 50px;
|
|
118
|
+
height: 50px;
|
|
119
|
+
opacity: 50%;
|
|
120
|
+
position: absolute;
|
|
121
|
+
transform: translate(-50%, -50%);
|
|
122
|
+
border-radius: 70%;
|
|
123
|
+
background: #FFD700;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
#mouse #dot {
|
|
127
|
+
width: 7px;
|
|
128
|
+
height: 7px;
|
|
129
|
+
position: absolute;
|
|
130
|
+
top: 50%;
|
|
131
|
+
left: 50%;
|
|
132
|
+
transform: translate(-50%, -50%);
|
|
133
|
+
border-radius: 50%;
|
|
134
|
+
background-color: black;
|
|
135
|
+
}
|
|
136
|
+
|
|
114
137
|
#pointer {
|
|
115
138
|
width: 25px;
|
|
116
139
|
height: 25px;
|
|
@@ -213,6 +236,7 @@
|
|
|
213
236
|
<div id="main" class="container">
|
|
214
237
|
<div id="boxes">
|
|
215
238
|
<div id="pointer"></div>
|
|
239
|
+
<div id="mouse"><div id="dot"></div></div>
|
|
216
240
|
</div>
|
|
217
241
|
<div id="terminal-wrapper">
|
|
218
242
|
<img src="td.png" alt="td" style="position: absolute; top: 20; right: 20; height: 40px; z-index: 9999; background-color: black;">
|
|
@@ -226,6 +250,7 @@
|
|
|
226
250
|
const { ipcRenderer } = require("electron");
|
|
227
251
|
const { events } = require("../lib/events.js");
|
|
228
252
|
|
|
253
|
+
const mouse = document.querySelector("#mouse");
|
|
229
254
|
const pointer = document.querySelector("#pointer");
|
|
230
255
|
const container = document.querySelector("#main");
|
|
231
256
|
const screenshotElement = document.querySelector("#screenshot");
|
|
@@ -277,9 +302,20 @@
|
|
|
277
302
|
container.style.opacity = 1
|
|
278
303
|
}, 2000)
|
|
279
304
|
});
|
|
305
|
+
ipcRenderer.on(events.mouseMove,
|
|
306
|
+
(event, { x, y } = {}) => {
|
|
307
|
+
|
|
308
|
+
console.log("mouseMove", x, y)
|
|
309
|
+
|
|
310
|
+
mouse.style.marginLeft = toCss(x);
|
|
311
|
+
mouse.style.marginTop = toCss(y);
|
|
312
|
+
|
|
313
|
+
},
|
|
314
|
+
);
|
|
280
315
|
|
|
281
316
|
ipcRenderer.on(events.mouseClick,
|
|
282
317
|
(event, { x, y, click = "single" } = {}) => {
|
|
318
|
+
|
|
283
319
|
pointer.style.marginLeft = toCss(x);
|
|
284
320
|
pointer.style.marginTop = toCss(y);
|
|
285
321
|
pointer.setAttribute("class", "");
|
package/electron/overlay.js
CHANGED
package/lib/commands.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// the actual commands to interact with the system
|
|
2
2
|
const sdk = require("./sdk");
|
|
3
|
-
const vm = require('vm');
|
|
4
3
|
const chalk = require("chalk");
|
|
5
4
|
const {
|
|
6
5
|
captureScreenBase64,
|
|
@@ -8,9 +7,10 @@ const {
|
|
|
8
7
|
platform,
|
|
9
8
|
activeWin,
|
|
10
9
|
} = require("./system");
|
|
11
|
-
|
|
10
|
+
const keymap = require("./keymap");
|
|
12
11
|
const { focusApplication } = require("./focus-application");
|
|
13
12
|
const fs = require("fs").promises; // Using the promises version for async operations
|
|
13
|
+
const robot = require("robotjs");
|
|
14
14
|
const { findTemplateImage } = require("./subimage/index");
|
|
15
15
|
const { cwd } = require("node:process");
|
|
16
16
|
const path = require("path");
|
|
@@ -18,24 +18,14 @@ const Jimp = require("jimp");
|
|
|
18
18
|
const os = require("os");
|
|
19
19
|
const cliProgress = require("cli-progress");
|
|
20
20
|
const redraw = require("./redraw");
|
|
21
|
-
const sandbox = require("./sandbox.js");
|
|
22
|
-
const config = require("./config.js");
|
|
23
|
-
let robot;
|
|
24
|
-
|
|
25
|
-
let keymap;
|
|
26
|
-
if (config.TD_VM) {
|
|
27
|
-
keymap = require("./keymaps/sandbox.js");
|
|
28
|
-
} else {
|
|
29
|
-
robot = require("robotjs");
|
|
30
|
-
keymap = require("./keymaps/robot.js");
|
|
31
|
-
}
|
|
32
|
-
|
|
33
21
|
const {
|
|
34
22
|
logger,
|
|
35
23
|
prettyMarkdown,
|
|
36
24
|
createMarkdownStreamLogger,
|
|
37
25
|
} = require("./logger");
|
|
38
26
|
const { emitter, events } = require("./events.js");
|
|
27
|
+
const util = require('util');
|
|
28
|
+
const exec = util.promisify(require('child_process').exec);
|
|
39
29
|
|
|
40
30
|
const niceSeconds = (ms) => {
|
|
41
31
|
return Math.round(ms / 1000);
|
|
@@ -187,26 +177,26 @@ const scroll = async (direction = "down", amount = 300, method = "mouse") => {
|
|
|
187
177
|
switch (direction) {
|
|
188
178
|
case "up":
|
|
189
179
|
if (method === "mouse") {
|
|
190
|
-
|
|
180
|
+
await robot.scrollMouse(0, amount );
|
|
191
181
|
} else {
|
|
192
|
-
|
|
182
|
+
await robot.keyTap("pageup");
|
|
193
183
|
}
|
|
194
184
|
await redraw.wait(2500);
|
|
195
185
|
break;
|
|
196
186
|
case "down":
|
|
197
187
|
if (method === "mouse") {
|
|
198
|
-
|
|
188
|
+
await robot.scrollMouse(0, amount * -1);
|
|
199
189
|
} else {
|
|
200
|
-
|
|
190
|
+
await robot.keyTap("pagedown");
|
|
201
191
|
}
|
|
202
192
|
await redraw.wait(2500);
|
|
203
193
|
break;
|
|
204
194
|
case "left":
|
|
205
|
-
|
|
195
|
+
await robot.scrollMouse(amount * -1, 0);
|
|
206
196
|
await redraw.wait(2500);
|
|
207
197
|
break;
|
|
208
198
|
case "right":
|
|
209
|
-
|
|
199
|
+
await robot.scrollMouse(amount, 0);
|
|
210
200
|
await redraw.wait(2500);
|
|
211
201
|
break;
|
|
212
202
|
default:
|
|
@@ -229,20 +219,22 @@ const click = async (x, y, action = "click") => {
|
|
|
229
219
|
double = true;
|
|
230
220
|
}
|
|
231
221
|
|
|
232
|
-
logger.debug(chalk.dim(`${
|
|
222
|
+
logger.debug(chalk.dim(`${action} ${button} clicking at ${x}, ${y}...`), true);
|
|
233
223
|
|
|
234
224
|
x = parseInt(x);
|
|
235
225
|
y = parseInt(y);
|
|
236
226
|
|
|
237
|
-
|
|
227
|
+
robot.moveMouseSmooth(x, y, 0.1);
|
|
228
|
+
|
|
238
229
|
await delay(1000); // wait for the mouse to move
|
|
239
230
|
|
|
240
|
-
if (
|
|
231
|
+
if (process.platform === "darwin" && action === "right-click") {
|
|
241
232
|
robot.keyToggle('control', 'down', 'control');
|
|
242
233
|
await delay(250);
|
|
243
234
|
}
|
|
244
235
|
|
|
245
236
|
if (action !== "hover") {
|
|
237
|
+
|
|
246
238
|
if (config.TD_VM) {
|
|
247
239
|
if (action === "click" || action === "left-click") {
|
|
248
240
|
await sandbox.send({type: "leftClick" })
|
|
@@ -252,14 +244,28 @@ const click = async (x, y, action = "click") => {
|
|
|
252
244
|
await sandbox.send({type: "middleClick" })
|
|
253
245
|
} else if (action === "double-click") {
|
|
254
246
|
await sandbox.send({type: "doubleClick" })
|
|
247
|
+
}else if (action === "drag-start") {
|
|
248
|
+
await sandbox.send({type: "mousePressLeft" })
|
|
249
|
+
}else if (action === "drag-end") {
|
|
250
|
+
await sandbox.send({type: "doubleClick" })
|
|
255
251
|
}
|
|
256
252
|
} else {
|
|
257
|
-
|
|
253
|
+
|
|
254
|
+
if (action === "drag-start") {
|
|
255
|
+
robot.mouseToggle("down", button);
|
|
256
|
+
} else if( action === "drag-end") {
|
|
257
|
+
robot.mouseToggle("up", button);
|
|
258
|
+
} else {
|
|
259
|
+
robot.mouseClick(button, double);
|
|
260
|
+
}
|
|
261
|
+
|
|
258
262
|
}
|
|
263
|
+
|
|
259
264
|
emitter.emit(events.mouseClick, { x, y, button, click });
|
|
265
|
+
|
|
260
266
|
}
|
|
261
267
|
|
|
262
|
-
if (
|
|
268
|
+
if (process.platform === "darwin" && action === "right-click") {
|
|
263
269
|
await delay(250);
|
|
264
270
|
robot.keyToggle('control', 'up', 'control');
|
|
265
271
|
}
|
|
@@ -274,7 +280,7 @@ const hover = async (x, y) => {
|
|
|
274
280
|
x = parseInt(x);
|
|
275
281
|
y = parseInt(y);
|
|
276
282
|
|
|
277
|
-
await
|
|
283
|
+
await robot.moveMouseSmooth(x, y, 0.1);
|
|
278
284
|
|
|
279
285
|
await redraw.wait(2500);
|
|
280
286
|
|
|
@@ -385,13 +391,7 @@ let commands = {
|
|
|
385
391
|
// type a string
|
|
386
392
|
type: async (string, delay = 500) => {
|
|
387
393
|
await redraw.start();
|
|
388
|
-
|
|
389
394
|
string = string.toString();
|
|
390
|
-
|
|
391
|
-
if (config.TD_VM) {
|
|
392
|
-
await sandbox.send({type: "write", text: string });
|
|
393
|
-
} else {
|
|
394
|
-
|
|
395
395
|
// there is a bug in robotjs that causes repeated characters to only be typed once
|
|
396
396
|
// so we need to check for repeated characters and type them slowly if so
|
|
397
397
|
const hasRepeatedChars = /(.)\1/.test(string);
|
|
@@ -399,8 +399,7 @@ let commands = {
|
|
|
399
399
|
await robot.typeStringDelayed(string, delay);
|
|
400
400
|
else
|
|
401
401
|
await robot.typeString(string);
|
|
402
|
-
|
|
403
|
-
// await redraw.wait(5000);
|
|
402
|
+
await redraw.wait(5000);
|
|
404
403
|
return;
|
|
405
404
|
},
|
|
406
405
|
// press keys
|
|
@@ -423,7 +422,7 @@ let commands = {
|
|
|
423
422
|
key = "control";
|
|
424
423
|
}
|
|
425
424
|
|
|
426
|
-
if (
|
|
425
|
+
if (modifierKeys.includes(key)) {
|
|
427
426
|
modifierKeysPressed.push(key);
|
|
428
427
|
} else {
|
|
429
428
|
keysPressed.push(key);
|
|
@@ -439,40 +438,32 @@ let commands = {
|
|
|
439
438
|
});
|
|
440
439
|
|
|
441
440
|
// only one key can be pressed at a time
|
|
442
|
-
if (
|
|
441
|
+
if (keysPressed.length > 1) {
|
|
443
442
|
throw new AiError(
|
|
444
443
|
"Only one key can be pressed at a time. However, multiple modifier keys can be pressed at the same time.",
|
|
445
444
|
);
|
|
446
445
|
}
|
|
447
446
|
|
|
448
447
|
// make sure modifier keys are valid, multiple are allowed
|
|
449
|
-
let modsToPress =
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
return keymap[key];
|
|
458
|
-
}
|
|
459
|
-
});
|
|
460
|
-
robot.keyTap(keysPressed[0], modsToPress);
|
|
461
|
-
} else {
|
|
462
|
-
await sandbox.send({type: "press", keys: keysPressed });
|
|
463
|
-
}
|
|
448
|
+
let modsToPress = modifierKeysPressed.map((key) => {
|
|
449
|
+
if (keymap[key] === undefined) {
|
|
450
|
+
logger.error(`Modifier key not found: ${key}`);
|
|
451
|
+
throw new AiError(`Modifier key not found: ${key}`);
|
|
452
|
+
} else {
|
|
453
|
+
return keymap[key];
|
|
454
|
+
}
|
|
455
|
+
});
|
|
464
456
|
|
|
465
457
|
// finally, press the keys
|
|
458
|
+
robot.keyTap(keysPressed[0], modsToPress);
|
|
466
459
|
|
|
467
460
|
await redraw.wait(5000);
|
|
468
461
|
|
|
469
462
|
// keyTap will release the normal keys, but will not release modifier keys
|
|
470
463
|
// so we need to release the modifier keys manually
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
});
|
|
475
|
-
}
|
|
464
|
+
modsToPress.forEach((key) => {
|
|
465
|
+
robot.keyToggle(key, "up");
|
|
466
|
+
});
|
|
476
467
|
|
|
477
468
|
return;
|
|
478
469
|
},
|
|
@@ -582,18 +573,15 @@ let commands = {
|
|
|
582
573
|
|
|
583
574
|
if (method === "keyboard") {
|
|
584
575
|
try {
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
await sandbox.send({type: "press", keys: ["escape"] });
|
|
595
|
-
}
|
|
596
|
-
|
|
576
|
+
// use robot to press CMD+F
|
|
577
|
+
await robot.keyTap("f", commandOrControl);
|
|
578
|
+
// keyTap will release the normal keys, but will not release modifier keys
|
|
579
|
+
// so we need to release the modifier keys manually
|
|
580
|
+
robot.keyToggle(commandOrControl, "up");
|
|
581
|
+
// type the text
|
|
582
|
+
await robot.typeStringDelayed(text, 500);
|
|
583
|
+
await redraw.wait(5000);
|
|
584
|
+
await robot.keyTap("escape");
|
|
597
585
|
} catch (e) {
|
|
598
586
|
logger.error("%s", e);
|
|
599
587
|
throw new AiError(
|
|
@@ -703,26 +691,25 @@ let commands = {
|
|
|
703
691
|
assert: async (assertion, async = false) => {
|
|
704
692
|
return await assert(assertion, true, async);
|
|
705
693
|
},
|
|
706
|
-
exec: async (
|
|
694
|
+
exec: async (cli_command, use_stderr = false, silent = false) => {
|
|
707
695
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
696
|
+
let args = {};
|
|
697
|
+
if (silent) {
|
|
698
|
+
args = { stdio: [] };
|
|
699
|
+
}
|
|
711
700
|
|
|
712
|
-
const
|
|
713
|
-
const script = new vm.Script(`
|
|
714
|
-
(async () => {
|
|
715
|
-
${nodejs_code}
|
|
716
|
-
})();
|
|
717
|
-
`);
|
|
701
|
+
const { stdout, stderr } = await exec(cli_command, args);
|
|
718
702
|
|
|
719
|
-
|
|
703
|
+
if (!silent) {
|
|
704
|
+
logger.info(chalk.dim(stdout), true);
|
|
705
|
+
}
|
|
720
706
|
|
|
721
|
-
|
|
722
|
-
|
|
707
|
+
if (use_stderr) {
|
|
708
|
+
return stderr;
|
|
709
|
+
} else {
|
|
710
|
+
return stdout;
|
|
711
|
+
}
|
|
723
712
|
|
|
724
|
-
return stepResult;
|
|
725
|
-
|
|
726
713
|
}
|
|
727
714
|
};
|
|
728
715
|
|
package/lib/events.js
CHANGED
package/lib/init.js
CHANGED
package/lib/overlay.js
CHANGED