testdriverai 5.2.0 → 5.2.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.
@@ -75,7 +75,7 @@ app.whenReady().then(() => {
75
75
  });
76
76
 
77
77
  // open developer tools
78
- window.webContents.openDevTools();
78
+ // window.webContents.openDevTools();
79
79
 
80
80
  ipc.serve(() => {
81
81
  for (const event of eventsArray) {
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
- const keymap = require("./keymap");
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(`${action} ${button} clicking at ${x}, ${y}...`), true);
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: "mousePressLeft" })
258
+ await sandbox.send({type: "mousePress", button: "left" })
249
259
  }else if (action === "drag-end") {
250
- await sandbox.send({type: "doubleClick" })
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 robot.moveMouseSmooth(x, y, 0.1);
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
- await redraw.wait(5000);
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 = 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
+ 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
- modsToPress.forEach((key) => {
465
- robot.keyToggle(key, "up");
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
- // 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");
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 (cli_command, use_stderr = false, silent = false) => {
721
+ exec: async (nodejs_code) => {
695
722
 
696
- let args = {};
697
- if (silent) {
698
- args = { stdio: [] };
699
- }
723
+ // must be assigned to `result`
724
+ // do not overwrite `result`
725
+ // must install locally via npm install
700
726
 
701
- const { stdout, stderr } = await exec(cli_command, args);
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
- if (!silent) {
704
- logger.info(chalk.dim(stdout), true);
705
- }
734
+ await script.runInContext(context);
706
735
 
707
- if (use_stderr) {
708
- return stderr;
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testdriverai",
3
- "version": "5.2.0",
3
+ "version": "5.2.2",
4
4
  "description": "Next generation autonomous AI agent for end-to-end testing of web & desktop",
5
5
  "main": "index.js",
6
6
  "bin": {