testdriverai 5.2.0 → 5.2.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/lib/commands.js +86 -58
- package/package.json +1 -1
package/lib/commands.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// the actual commands to interact with the system
|
|
2
2
|
const sdk = require("./sdk");
|
|
3
|
+
const vm = require('vm');
|
|
3
4
|
const chalk = require("chalk");
|
|
4
5
|
const {
|
|
5
6
|
captureScreenBase64,
|
|
@@ -7,10 +8,9 @@ const {
|
|
|
7
8
|
platform,
|
|
8
9
|
activeWin,
|
|
9
10
|
} = require("./system");
|
|
10
|
-
|
|
11
|
+
|
|
11
12
|
const { focusApplication } = require("./focus-application");
|
|
12
13
|
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,14 +18,24 @@ 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
|
+
|
|
21
33
|
const {
|
|
22
34
|
logger,
|
|
23
35
|
prettyMarkdown,
|
|
24
36
|
createMarkdownStreamLogger,
|
|
25
37
|
} = require("./logger");
|
|
26
38
|
const { emitter, events } = require("./events.js");
|
|
27
|
-
const util = require('util');
|
|
28
|
-
const exec = util.promisify(require('child_process').exec);
|
|
29
39
|
|
|
30
40
|
const niceSeconds = (ms) => {
|
|
31
41
|
return Math.round(ms / 1000);
|
|
@@ -177,26 +187,26 @@ const scroll = async (direction = "down", amount = 300, method = "mouse") => {
|
|
|
177
187
|
switch (direction) {
|
|
178
188
|
case "up":
|
|
179
189
|
if (method === "mouse") {
|
|
180
|
-
await robot.scrollMouse(0, amount );
|
|
190
|
+
config.TD_VM ? await sandbox.send({type: "scroll", amount }) : await robot.scrollMouse(0, amount );
|
|
181
191
|
} else {
|
|
182
|
-
await robot.keyTap("pageup");
|
|
192
|
+
config.TD_VM ? await sandbox.send({type: "press", keys: ["pageup"]}) : await robot.keyTap("pageup");
|
|
183
193
|
}
|
|
184
194
|
await redraw.wait(2500);
|
|
185
195
|
break;
|
|
186
196
|
case "down":
|
|
187
197
|
if (method === "mouse") {
|
|
188
|
-
await robot.scrollMouse(0, amount * -1);
|
|
198
|
+
config.TD_VM ? await sandbox.send({type: "scroll", amount: amount * -1}) : await robot.scrollMouse(0, amount * -1);
|
|
189
199
|
} else {
|
|
190
|
-
await robot.keyTap("pagedown");
|
|
200
|
+
config.TD_VM ? await sandbox.send({type: "press", keys: ["pagedown"] }) : await robot.keyTap("pagedown");
|
|
191
201
|
}
|
|
192
202
|
await redraw.wait(2500);
|
|
193
203
|
break;
|
|
194
204
|
case "left":
|
|
195
|
-
await robot.scrollMouse(amount * -1, 0);
|
|
205
|
+
config.TD_VM ? console.log('Not Supported') : await robot.scrollMouse(amount * -1, 0);
|
|
196
206
|
await redraw.wait(2500);
|
|
197
207
|
break;
|
|
198
208
|
case "right":
|
|
199
|
-
await robot.scrollMouse(amount, 0);
|
|
209
|
+
config.TD_VM ? console.log('Not Supported') : await robot.scrollMouse(amount, 0);
|
|
200
210
|
await redraw.wait(2500);
|
|
201
211
|
break;
|
|
202
212
|
default:
|
|
@@ -219,22 +229,22 @@ const click = async (x, y, action = "click") => {
|
|
|
219
229
|
double = true;
|
|
220
230
|
}
|
|
221
231
|
|
|
222
|
-
logger.debug(chalk.dim(`${
|
|
232
|
+
logger.debug(chalk.dim(`${click} ${button} clicking at ${x}, ${y}...`), true);
|
|
223
233
|
|
|
224
234
|
x = parseInt(x);
|
|
225
235
|
y = parseInt(y);
|
|
226
236
|
|
|
227
|
-
robot.moveMouseSmooth(x, y, 0.1);
|
|
228
|
-
|
|
237
|
+
config.TD_VM ? await sandbox.send({type: "moveMouse", x, y }) : await robot.moveMouseSmooth(x, y, 0.1);
|
|
238
|
+
emitter.emit(events.mouseMove, { x, y });
|
|
239
|
+
|
|
229
240
|
await delay(1000); // wait for the mouse to move
|
|
230
241
|
|
|
231
|
-
if (process.platform === "darwin" && action === "right-click") {
|
|
242
|
+
if (!config.TD_VM && process.platform === "darwin" && action === "right-click") {
|
|
232
243
|
robot.keyToggle('control', 'down', 'control');
|
|
233
244
|
await delay(250);
|
|
234
245
|
}
|
|
235
246
|
|
|
236
247
|
if (action !== "hover") {
|
|
237
|
-
|
|
238
248
|
if (config.TD_VM) {
|
|
239
249
|
if (action === "click" || action === "left-click") {
|
|
240
250
|
await sandbox.send({type: "leftClick" })
|
|
@@ -245,9 +255,9 @@ const click = async (x, y, action = "click") => {
|
|
|
245
255
|
} else if (action === "double-click") {
|
|
246
256
|
await sandbox.send({type: "doubleClick" })
|
|
247
257
|
}else if (action === "drag-start") {
|
|
248
|
-
await sandbox.send({type: "
|
|
258
|
+
await sandbox.send({type: "mousePress", button: "left" })
|
|
249
259
|
}else if (action === "drag-end") {
|
|
250
|
-
await sandbox.send({type: "
|
|
260
|
+
await sandbox.send({type: "mouseRelease", button: "left" })
|
|
251
261
|
}
|
|
252
262
|
} else {
|
|
253
263
|
|
|
@@ -262,10 +272,9 @@ const click = async (x, y, action = "click") => {
|
|
|
262
272
|
}
|
|
263
273
|
|
|
264
274
|
emitter.emit(events.mouseClick, { x, y, button, click });
|
|
265
|
-
|
|
266
275
|
}
|
|
267
276
|
|
|
268
|
-
if (process.platform === "darwin" && action === "right-click") {
|
|
277
|
+
if (!config.TD_VM && process.platform === "darwin" && action === "right-click") {
|
|
269
278
|
await delay(250);
|
|
270
279
|
robot.keyToggle('control', 'up', 'control');
|
|
271
280
|
}
|
|
@@ -280,7 +289,7 @@ const hover = async (x, y) => {
|
|
|
280
289
|
x = parseInt(x);
|
|
281
290
|
y = parseInt(y);
|
|
282
291
|
|
|
283
|
-
await
|
|
292
|
+
await sandbox.send({type: "moveMouse", x, y });
|
|
284
293
|
|
|
285
294
|
await redraw.wait(2500);
|
|
286
295
|
|
|
@@ -391,7 +400,13 @@ let commands = {
|
|
|
391
400
|
// type a string
|
|
392
401
|
type: async (string, delay = 500) => {
|
|
393
402
|
await redraw.start();
|
|
403
|
+
|
|
394
404
|
string = string.toString();
|
|
405
|
+
|
|
406
|
+
if (config.TD_VM) {
|
|
407
|
+
await sandbox.send({type: "write", text: string });
|
|
408
|
+
} else {
|
|
409
|
+
|
|
395
410
|
// there is a bug in robotjs that causes repeated characters to only be typed once
|
|
396
411
|
// so we need to check for repeated characters and type them slowly if so
|
|
397
412
|
const hasRepeatedChars = /(.)\1/.test(string);
|
|
@@ -399,7 +414,8 @@ let commands = {
|
|
|
399
414
|
await robot.typeStringDelayed(string, delay);
|
|
400
415
|
else
|
|
401
416
|
await robot.typeString(string);
|
|
402
|
-
|
|
417
|
+
}
|
|
418
|
+
// await redraw.wait(5000);
|
|
403
419
|
return;
|
|
404
420
|
},
|
|
405
421
|
// press keys
|
|
@@ -422,7 +438,7 @@ let commands = {
|
|
|
422
438
|
key = "control";
|
|
423
439
|
}
|
|
424
440
|
|
|
425
|
-
if (modifierKeys.includes(key)) {
|
|
441
|
+
if (!config.TD_VM && modifierKeys.includes(key)) {
|
|
426
442
|
modifierKeysPressed.push(key);
|
|
427
443
|
} else {
|
|
428
444
|
keysPressed.push(key);
|
|
@@ -438,32 +454,40 @@ let commands = {
|
|
|
438
454
|
});
|
|
439
455
|
|
|
440
456
|
// only one key can be pressed at a time
|
|
441
|
-
if (keysPressed.length > 1) {
|
|
457
|
+
if (!config.TD_VM && keysPressed.length > 1) {
|
|
442
458
|
throw new AiError(
|
|
443
459
|
"Only one key can be pressed at a time. However, multiple modifier keys can be pressed at the same time.",
|
|
444
460
|
);
|
|
445
461
|
}
|
|
446
462
|
|
|
447
463
|
// make sure modifier keys are valid, multiple are allowed
|
|
448
|
-
let modsToPress =
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
464
|
+
let modsToPress = [];
|
|
465
|
+
|
|
466
|
+
if (!config.TD_VM) {
|
|
467
|
+
modifierKeysPressed.map((key) => {
|
|
468
|
+
if (keymap[key] === undefined) {
|
|
469
|
+
logger.error(`Modifier key not found: ${key}`);
|
|
470
|
+
throw new AiError(`Modifier key not found: ${key}`);
|
|
471
|
+
} else {
|
|
472
|
+
return keymap[key];
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
robot.keyTap(keysPressed[0], modsToPress);
|
|
476
|
+
} else {
|
|
477
|
+
await sandbox.send({type: "press", keys: keysPressed });
|
|
478
|
+
}
|
|
456
479
|
|
|
457
480
|
// finally, press the keys
|
|
458
|
-
robot.keyTap(keysPressed[0], modsToPress);
|
|
459
481
|
|
|
460
482
|
await redraw.wait(5000);
|
|
461
483
|
|
|
462
484
|
// keyTap will release the normal keys, but will not release modifier keys
|
|
463
485
|
// so we need to release the modifier keys manually
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
486
|
+
if (!config.TD_VM) {
|
|
487
|
+
modsToPress.forEach((key) => {
|
|
488
|
+
robot.keyToggle(key, "up");
|
|
489
|
+
});
|
|
490
|
+
}
|
|
467
491
|
|
|
468
492
|
return;
|
|
469
493
|
},
|
|
@@ -573,15 +597,18 @@ let commands = {
|
|
|
573
597
|
|
|
574
598
|
if (method === "keyboard") {
|
|
575
599
|
try {
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
600
|
+
|
|
601
|
+
if (!config.TD_VM) {
|
|
602
|
+
await robot.keyTap("f", commandOrControl);;
|
|
603
|
+
robot.keyToggle(commandOrControl, "up");
|
|
604
|
+
await robot.typeStringDelayed(text, 500);
|
|
605
|
+
} else {
|
|
606
|
+
await sandbox.send({type: "press", keys: ["f", commandOrControl] })
|
|
607
|
+
await sandbox.send({type: "write", text });
|
|
608
|
+
await redraw.wait(5000);
|
|
609
|
+
await sandbox.send({type: "press", keys: ["escape"] });
|
|
610
|
+
}
|
|
611
|
+
|
|
585
612
|
} catch (e) {
|
|
586
613
|
logger.error("%s", e);
|
|
587
614
|
throw new AiError(
|
|
@@ -691,25 +718,26 @@ let commands = {
|
|
|
691
718
|
assert: async (assertion, async = false) => {
|
|
692
719
|
return await assert(assertion, true, async);
|
|
693
720
|
},
|
|
694
|
-
exec: async (
|
|
721
|
+
exec: async (nodejs_code) => {
|
|
695
722
|
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
}
|
|
723
|
+
// must be assigned to `result`
|
|
724
|
+
// do not overwrite `result`
|
|
725
|
+
// must install locally via npm install
|
|
700
726
|
|
|
701
|
-
const {
|
|
727
|
+
const context = vm.createContext({ require, console, fs, process });
|
|
728
|
+
const script = new vm.Script(`
|
|
729
|
+
(async () => {
|
|
730
|
+
${nodejs_code}
|
|
731
|
+
})();
|
|
732
|
+
`);
|
|
702
733
|
|
|
703
|
-
|
|
704
|
-
logger.info(chalk.dim(stdout), true);
|
|
705
|
-
}
|
|
734
|
+
await script.runInContext(context);
|
|
706
735
|
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
} else {
|
|
710
|
-
return stdout;
|
|
711
|
-
}
|
|
736
|
+
// wait for context.result to resolve
|
|
737
|
+
const stepResult = await context.result;
|
|
712
738
|
|
|
739
|
+
return stepResult;
|
|
740
|
+
|
|
713
741
|
}
|
|
714
742
|
};
|
|
715
743
|
|