testdriverai 5.3.7 → 5.3.9

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/README.md CHANGED
@@ -153,4 +153,5 @@ gh pr create --web
153
153
  ```
154
154
 
155
155
  Your test will run on every commit and the results will be posted as a Dashcam.io video within your GitHub summary! Learn more about deploying on CI [here](https://docs.testdriver.ai/continuous-integration/overview).
156
+
156
157
  # vscode
package/agent.js CHANGED
@@ -353,8 +353,6 @@ const check = async () => {
353
353
  const runCommand = async (command, depth) => {
354
354
  let yml = await yaml.dump(command);
355
355
 
356
- await save({});
357
-
358
356
  logger.debug(`running command: \n\n${yml}`);
359
357
 
360
358
  try {
@@ -600,8 +598,6 @@ const exploratoryLoop = async (
600
598
  logger.debug("showing prompt from exploratoryLoop response check");
601
599
  }
602
600
 
603
- await save({ silent: false });
604
-
605
601
  return;
606
602
  };
607
603
 
@@ -996,11 +992,6 @@ let summarize = async (error = null) => {
996
992
  let save = async ({ filepath = thisFile, silent = false } = {}) => {
997
993
  analytics.track("save", { silent });
998
994
 
999
- if (!silent) {
1000
- logger.info(chalk.dim(`saving as ${filepath}...`), true);
1001
- logger.info("");
1002
- }
1003
-
1004
995
  if (!executionHistory.length) {
1005
996
  return;
1006
997
  }
@@ -1026,7 +1017,7 @@ ${regression}
1026
1017
 
1027
1018
  const fileName = filepath.split("/").pop();
1028
1019
  if (!silent) {
1029
- logger.info(chalk.dim(`saved as ${fileName}`));
1020
+ logger.info(chalk.dim(`saved as ${filepath}`));
1030
1021
  }
1031
1022
  }
1032
1023
 
@@ -1114,10 +1105,14 @@ ${yaml.dump(step)}
1114
1105
 
1115
1106
  lastPrompt = step.prompt;
1116
1107
  await actOnMarkdown(markdown, 0, true);
1108
+
1109
+ if (shouldSave) {
1110
+ await save({ silent: true });
1111
+ }
1117
1112
  }
1118
1113
 
1119
1114
  if (shouldSave) {
1120
- await save({ filepath: file });
1115
+ await save({ filepath: file, silent: false });
1121
1116
  }
1122
1117
 
1123
1118
  setTerminalWindowTransparency(false);
@@ -1280,6 +1275,7 @@ const makeSandbox = async () => {
1280
1275
  await new Promise((resolve) => setTimeout(resolve, 3000));
1281
1276
  logger.info(chalk.green(``));
1282
1277
  logger.info(chalk.green(`sandbox runner ready!`));
1278
+ logger.info(chalk.green(``));
1283
1279
  } catch (e) {
1284
1280
  logger.error(e);
1285
1281
  logger.error(chalk.red(`sandbox runner failed to start`));
@@ -42,3 +42,4 @@ else:
42
42
  - The `if` command is useful for creating conditional logic in your tests, allowing for more dynamic and flexible workflows.
43
43
  - Both the `then` and `else` blocks are optional, but at least one must be provided.
44
44
  ```
45
+
@@ -5,7 +5,17 @@ description: "Comprehensive guide to installing and setting up TestDriver.ai for
5
5
  icon: "file-code"
6
6
  ---
7
7
 
8
- [Download VSCode Extension](https://github.com/testdriverai/vscode/actions/runs/14458583961)
8
+ # Download the VSCode Extension
9
+
10
+ The TestDriver.ai VSCode extension is available for download on our GitHub releases page. This extension integrates seamlessly with Visual Studio Code, allowing you to leverage the power of TestDriver.ai directly within your development environment.
11
+
12
+ <Card
13
+ title="Download the VSCode Extension"
14
+ icon="download"
15
+ href="https://github.com/testdriverai/vscode/releases"
16
+ >
17
+ Get the latest version of the TestDriver.ai VSCode extension from our GitHub releases page.
18
+ </Card>
9
19
 
10
20
  # Install the extension
11
21
 
@@ -18,7 +28,7 @@ icon: "file-code"
18
28
 
19
29
  # Try the Walkthrough
20
30
 
21
- The extension should launch a walkthrough. If it does not, you can manually start it by running the command `TestDriver: Start Walkthrough` from the Command Palette (`Ctrl+Shift+P`).
31
+ The extension should launch a walkthrough. If it does not, you can manually start it by running the command `TestDriver: Start Setup Walkthrough` from the Command Palette (`Ctrl+Shift+P`).
22
32
 
23
33
  ![](/images/content/vscode-walkthrough.png)
24
34
 
@@ -1,8 +1,15 @@
1
1
  const { default: nodeIPC } = require("node-ipc");
2
- const { app: electronApp, remote, screen, BrowserWindow, Tray, Menu } = require("electron");
2
+ const {
3
+ app: electronApp,
4
+ remote,
5
+ screen,
6
+ BrowserWindow,
7
+ Tray,
8
+ Menu,
9
+ } = require("electron");
3
10
  const { eventsArray } = require("../lib/events.js");
4
11
  const config = require("../lib/config.js");
5
- const path = require('path');
12
+ const path = require("path");
6
13
 
7
14
  let tray = null;
8
15
 
@@ -22,22 +29,21 @@ ipc.config.retry = 0;
22
29
  ipc.config.silent = true;
23
30
 
24
31
  app.whenReady().then(() => {
25
-
26
32
  // Path to tray icon (must be .ico on Windows, .png on Mac/Linux)
27
- const iconPath = path.join(__dirname, 'tray.png');
33
+ const iconPath = path.join(__dirname, "tray.png");
28
34
 
29
35
  tray = new Tray(iconPath);
30
36
 
31
37
  const contextMenu = Menu.buildFromTemplate([
32
38
  {
33
- label: 'Quit',
39
+ label: "Quit",
34
40
  click: () => {
35
41
  app.quit();
36
42
  },
37
43
  },
38
44
  ]);
39
45
 
40
- tray.setToolTip('TestDriver.ai');
46
+ tray.setToolTip("TestDriver.ai");
41
47
  tray.setContextMenu(contextMenu);
42
48
 
43
49
  app.dock?.hide();
@@ -92,8 +98,11 @@ app.whenReady().then(() => {
92
98
  visibleOnFullScreen: true,
93
99
  });
94
100
  } else {
95
- window.setContentSize(config.TD_VM_RESOLUTION[0], config.TD_VM_RESOLUTION[1]);
96
- window.setBackgroundColor('#000')
101
+ window.setContentSize(
102
+ config.TD_VM_RESOLUTION[0],
103
+ config.TD_VM_RESOLUTION[1],
104
+ );
105
+ window.setBackgroundColor("#000");
97
106
  }
98
107
 
99
108
  window.loadFile("overlay.html");
package/lib/commands.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // the actual commands to interact with the system
2
2
  const sdk = require("./sdk");
3
- const vm = require('vm');
3
+ const vm = require("vm");
4
4
  const chalk = require("chalk");
5
5
  const server = require("./ipc").server;
6
6
  const {
@@ -21,8 +21,8 @@ const cliProgress = require("cli-progress");
21
21
  const redraw = require("./redraw");
22
22
  const sandbox = require("./sandbox.js");
23
23
  const config = require("./config.js");
24
- const util = require('util');
25
- const exec = util.promisify(require('child_process').exec);
24
+ const util = require("util");
25
+ const exec = util.promisify(require("child_process").exec);
26
26
  let robot;
27
27
 
28
28
  let keymap;
@@ -191,26 +191,38 @@ const scroll = async (direction = "down", amount = 300, method = "mouse") => {
191
191
  switch (direction) {
192
192
  case "up":
193
193
  if (method === "mouse") {
194
- config.TD_VM ? await sandbox.send({type: "scroll", amount }) : await robot.scrollMouse(0, amount );
194
+ config.TD_VM
195
+ ? await sandbox.send({ type: "scroll", amount })
196
+ : await robot.scrollMouse(0, amount);
195
197
  } else {
196
- config.TD_VM ? await sandbox.send({type: "press", keys: ["pageup"]}) : await robot.keyTap("pageup");
198
+ config.TD_VM
199
+ ? await sandbox.send({ type: "press", keys: ["pageup"] })
200
+ : await robot.keyTap("pageup");
197
201
  }
198
202
  await redraw.wait(2500);
199
203
  break;
200
204
  case "down":
201
205
  if (method === "mouse") {
202
- config.TD_VM ? await sandbox.send({type: "scroll", amount: amount * -1}) : await robot.scrollMouse(0, amount * -1);
206
+ config.TD_VM
207
+ ? await sandbox.send({ type: "scroll", amount: amount * -1 })
208
+ : await robot.scrollMouse(0, amount * -1);
203
209
  } else {
204
- config.TD_VM ? await sandbox.send({type: "press", keys: ["pagedown"] }) : await robot.keyTap("pagedown");
210
+ config.TD_VM
211
+ ? await sandbox.send({ type: "press", keys: ["pagedown"] })
212
+ : await robot.keyTap("pagedown");
205
213
  }
206
214
  await redraw.wait(2500);
207
215
  break;
208
216
  case "left":
209
- config.TD_VM ? console.log('Not Supported') : await robot.scrollMouse(amount * -1, 0);
217
+ config.TD_VM
218
+ ? console.log("Not Supported")
219
+ : await robot.scrollMouse(amount * -1, 0);
210
220
  await redraw.wait(2500);
211
221
  break;
212
222
  case "right":
213
- config.TD_VM ? console.log('Not Supported') : await robot.scrollMouse(amount, 0);
223
+ config.TD_VM
224
+ ? console.log("Not Supported")
225
+ : await robot.scrollMouse(amount, 0);
214
226
  await redraw.wait(2500);
215
227
  break;
216
228
  default:
@@ -223,65 +235,67 @@ const scroll = async (direction = "down", amount = 300, method = "mouse") => {
223
235
  const click = async (x, y, action = "click") => {
224
236
  await redraw.start();
225
237
 
226
- let button = 'left';
238
+ let button = "left";
227
239
  let double = false;
228
240
 
229
- if (action === "right-click" && platform !== "darwin" ) {
241
+ if (action === "right-click" && platform !== "darwin") {
230
242
  button = "right";
231
243
  }
232
244
  if (action === "double-click") {
233
245
  double = true;
234
246
  }
235
247
 
236
- logger.debug(chalk.dim(`${action} ${button} clicking at ${x}, ${y}...`), true);
248
+ logger.debug(
249
+ chalk.dim(`${action} ${button} clicking at ${x}, ${y}...`),
250
+ true,
251
+ );
237
252
 
238
253
  x = parseInt(x);
239
254
  y = parseInt(y);
240
255
 
241
- config.TD_VM ? await sandbox.send({type: "moveMouse", x, y }) : await robot.moveMouseSmooth(x, y, 0.1);
256
+ config.TD_VM
257
+ ? await sandbox.send({ type: "moveMouse", x, y })
258
+ : await robot.moveMouseSmooth(x, y, 0.1);
242
259
  emitter.emit(events.mouseMove, { x, y });
243
260
 
244
261
  await delay(1000); // wait for the mouse to move
245
262
 
246
- if (!config.TD_VM && platform()== "darwin" && action === "right-click") {
247
- robot.keyToggle('control', 'down', 'control');
263
+ if (!config.TD_VM && platform() == "darwin" && action === "right-click") {
264
+ robot.keyToggle("control", "down", "control");
248
265
  await delay(250);
249
266
  }
250
267
 
251
268
  if (action !== "hover") {
252
269
  if (config.TD_VM) {
253
270
  if (action === "click" || action === "left-click") {
254
- await sandbox.send({type: "leftClick" })
271
+ await sandbox.send({ type: "leftClick" });
255
272
  } else if (action === "right-click") {
256
- await sandbox.send({type: "rightClick" })
273
+ await sandbox.send({ type: "rightClick" });
257
274
  } else if (action === "middle-click") {
258
- await sandbox.send({type: "middleClick" })
275
+ await sandbox.send({ type: "middleClick" });
259
276
  } else if (action === "double-click") {
260
- await sandbox.send({type: "doubleClick" })
261
- }else if (action === "drag-start") {
262
- await sandbox.send({type: "mousePress", button: "left" })
263
- }else if (action === "drag-end") {
264
- await sandbox.send({type: "mouseRelease", button: "left" })
277
+ await sandbox.send({ type: "doubleClick" });
278
+ } else if (action === "drag-start") {
279
+ await sandbox.send({ type: "mousePress", button: "left" });
280
+ } else if (action === "drag-end") {
281
+ await sandbox.send({ type: "mouseRelease", button: "left" });
265
282
  }
266
283
  } else {
267
-
268
284
  if (action === "drag-start") {
269
285
  robot.mouseToggle("down", button);
270
- } else if( action === "drag-end") {
286
+ } else if (action === "drag-end") {
271
287
  robot.mouseToggle("up", button);
272
288
  } else {
273
289
  robot.mouseClick(button, double);
274
290
  }
275
-
276
291
  }
277
292
 
278
293
  emitter.emit(events.mouseClick, { x, y, button, click });
279
-
280
294
  }
281
295
 
282
- if (!config.TD_VM && platform()== "darwin" && action === "right-click") {
296
+ if (!config.TD_VM && platform() == "darwin" && action === "right-click") {
283
297
  await delay(250);
284
- robot.keyToggle('control', 'up', 'control');
298
+ robot.keyToggle("control", "up", "control");
285
299
  }
286
300
 
287
301
  await redraw.wait(5000);
@@ -294,7 +308,7 @@ const hover = async (x, y) => {
294
308
  x = parseInt(x);
295
309
  y = parseInt(y);
296
310
 
297
- await sandbox.send({type: "moveMouse", x, y });
311
+ await sandbox.send({ type: "moveMouse", x, y });
298
312
 
299
313
  await redraw.wait(2500);
300
314
 
@@ -350,10 +364,7 @@ let commands = {
350
364
  }
351
365
  },
352
366
  // uses our api to find all images on screen
353
- "hover-image": async (
354
- description,
355
- action = "click",
356
- ) => {
367
+ "hover-image": async (description, action = "click") => {
357
368
  // take a screenshot
358
369
  logger.info("");
359
370
  logger.info(chalk.dim("thinking..."), true);
@@ -384,10 +395,7 @@ let commands = {
384
395
  return response.data;
385
396
  }
386
397
  },
387
- "match-image": async (
388
- relativePath,
389
- action = "click"
390
- ) => {
398
+ "match-image": async (relativePath, action = "click") => {
391
399
  let image = await captureScreenPNG();
392
400
 
393
401
  let result = await findImageOnScreen(relativePath, image);
@@ -405,20 +413,18 @@ let commands = {
405
413
  // type a string
406
414
  type: async (string, delay = 500) => {
407
415
  await redraw.start();
408
-
416
+
409
417
  string = string.toString();
410
418
 
411
419
  if (config.TD_VM) {
412
- await sandbox.send({type: "write", text: string });
420
+ await sandbox.send({ type: "write", text: string });
413
421
  } else {
414
-
415
- // there is a bug in robotjs that causes repeated characters to only be typed once
416
- // so we need to check for repeated characters and type them slowly if so
417
- const hasRepeatedChars = /(.)\1/.test(string);
418
- if (delay > 0 && hasRepeatedChars)
419
- await robot.typeStringDelayed(string, delay);
420
- else
421
- await robot.typeString(string);
422
+ // there is a bug in robotjs that causes repeated characters to only be typed once
423
+ // so we need to check for repeated characters and type them slowly if so
424
+ const hasRepeatedChars = /(.)\1/.test(string);
425
+ if (delay > 0 && hasRepeatedChars)
426
+ await robot.typeStringDelayed(string, delay);
427
+ else await robot.typeString(string);
422
428
  }
423
429
  // await redraw.wait(5000);
424
430
  return;
@@ -439,7 +445,7 @@ let commands = {
439
445
  // remove any modifier keys from the inputKeys array and put them in a new array
440
446
  inputKeys.forEach((key) => {
441
447
  // change command to control on windows
442
- if (key === "command" && platform()== "win32") {
448
+ if (key === "command" && platform() == "win32") {
443
449
  key = "control";
444
450
  }
445
451
 
@@ -467,7 +473,7 @@ let commands = {
467
473
 
468
474
  // make sure modifier keys are valid, multiple are allowed
469
475
  let modsToPress = [];
470
-
476
+
471
477
  if (!config.TD_VM) {
472
478
  modifierKeysPressed.map((key) => {
473
479
  if (keymap[key] === undefined) {
@@ -476,10 +482,10 @@ let commands = {
476
482
  } else {
477
483
  return keymap[key];
478
484
  }
479
- });
485
+ });
480
486
  robot.keyTap(keysPressed[0], modsToPress);
481
487
  } else {
482
- await sandbox.send({type: "press", keys: keysPressed });
488
+ await sandbox.send({ type: "press", keys: keysPressed });
483
489
  }
484
490
 
485
491
  // finally, press the keys
@@ -514,8 +520,11 @@ let commands = {
514
520
  let passed = false;
515
521
 
516
522
  while (durationPassed < timeout && !passed) {
517
-
518
- passed = await assert(`An image matching the description "${description}" appears on screen.`, false, false);
523
+ passed = await assert(
524
+ `An image matching the description "${description}" appears on screen.`,
525
+ false,
526
+ false,
527
+ );
519
528
 
520
529
  durationPassed = new Date().getTime() - startTime;
521
530
  if (!passed) {
@@ -525,6 +534,7 @@ let commands = {
525
534
  ),
526
535
  true,
527
536
  );
537
+ await delay(2500);
528
538
  }
529
539
  }
530
540
 
@@ -568,14 +578,14 @@ let commands = {
568
578
 
569
579
  passed = response.data;
570
580
  durationPassed = new Date().getTime() - startTime;
571
- if (!passed && durationPassed > timeout) {
581
+ if (!passed) {
572
582
  logger.info(
573
583
  chalk.dim(
574
584
  `${niceSeconds(durationPassed)} seconds have passed without finding "${text}"`,
575
585
  ),
576
586
  true,
577
587
  );
578
- await redraw.wait(5000);
588
+ await delay(2500);
579
589
  }
580
590
  }
581
591
 
@@ -594,7 +604,7 @@ let commands = {
594
604
  direction = "down",
595
605
  maxDistance = 1200,
596
606
  textMatchMethod = "turbo",
597
- method = "keyboard"
607
+ method = "keyboard",
598
608
  ) => {
599
609
  await redraw.start();
600
610
 
@@ -602,18 +612,16 @@ let commands = {
602
612
 
603
613
  if (method === "keyboard") {
604
614
  try {
605
-
606
615
  if (!config.TD_VM) {
607
- await robot.keyTap("f", commandOrControl);;
616
+ await robot.keyTap("f", commandOrControl);
608
617
  robot.keyToggle(commandOrControl, "up");
609
618
  await robot.typeStringDelayed(text, 500);
610
619
  } else {
611
- await sandbox.send({type: "press", keys: ["f", commandOrControl] })
612
- await sandbox.send({type: "write", text });
620
+ await sandbox.send({ type: "press", keys: ["f", commandOrControl] });
621
+ await sandbox.send({ type: "write", text });
613
622
  await redraw.wait(5000);
614
- await sandbox.send({type: "press", keys: ["escape"] });
623
+ await sandbox.send({ type: "press", keys: ["escape"] });
615
624
  }
616
-
617
625
  } catch (e) {
618
626
  logger.error("%s", e);
619
627
  throw new AiError(
@@ -684,8 +692,11 @@ let commands = {
684
692
  let passed = false;
685
693
 
686
694
  while (scrollDistance <= maxDistance && !passed) {
687
-
688
- passed = await assert(`An image matching the description "${description}" appears on screen.`, false, false);
695
+ passed = await assert(
696
+ `An image matching the description "${description}" appears on screen.`,
697
+ false,
698
+ false,
699
+ );
689
700
 
690
701
  if (!passed) {
691
702
  logger.info(
@@ -724,90 +735,99 @@ let commands = {
724
735
  return await assert(assertion, true, async);
725
736
  },
726
737
  exec: async (language, mac_code, windows_code, linux_code) => {
727
-
728
- logger.info(chalk.dim(`calling exec...`), true,);
738
+ logger.info(chalk.dim(`calling exec...`), true);
729
739
 
730
740
  let plat = platform();
731
-
732
- const scriptCode = plat == "linux" ? linux_code : plat == "windows" ? windows_code : plat == "mac" ? mac_code : (() => { throw new AiError(`Unsupported plat: ${plat}`); })();
741
+
742
+ const scriptCode =
743
+ plat == "linux"
744
+ ? linux_code
745
+ : plat == "windows"
746
+ ? windows_code
747
+ : plat == "mac"
748
+ ? mac_code
749
+ : (() => {
750
+ throw new AiError(`Unsupported plat: ${plat}`);
751
+ })();
733
752
 
734
753
  if (!scriptCode) {
735
754
  logger.warn(`No code provided for ${plat}`);
736
755
  return;
737
756
  }
738
757
 
739
- if (language == 'shell') {
740
-
741
- logger.info(chalk.dim(`running in shell...`), true,);
758
+ if (language == "shell") {
759
+ logger.info(chalk.dim(`running in shell...`), true);
742
760
 
743
761
  if (plat == "linux") {
744
-
745
762
  if (config.TD_VM) {
746
-
747
- logger.info(chalk.dim(`sending value of \`linux\` to vm...`), true,);
763
+ logger.info(chalk.dim(`sending value of \`linux\` to vm...`), true);
748
764
 
749
765
  return await sandbox.send({
750
766
  type: "commands.run",
751
767
  command: linux_code,
752
768
  });
753
-
754
769
  } else {
755
-
756
770
  if (!linux_code) {
757
771
  throw new AiError(`No code provided for linux`, true);
758
772
  }
759
773
 
760
- logger.info(chalk.dim(`running value of \`${plat}\` on this machine...`), true);
774
+ logger.info(
775
+ chalk.dim(`running value of \`${plat}\` on this machine...`),
776
+ true,
777
+ );
761
778
  return await exec(mac_code, { cwd: cwd() });
762
779
  }
763
780
  } else if (plat == "windows") {
764
- logger.info(chalk.dim(`running value of \`${plat}\` on this machine...`), true);
781
+ logger.info(
782
+ chalk.dim(`running value of \`${plat}\` on this machine...`),
783
+ true,
784
+ );
765
785
  return await exec(windows_code, { cwd: cwd() });
766
786
  } else if (plat == "mac") {
767
- logger.info(chalk.dim(`running value of \`${plat}\` on this machine...`), true);
787
+ logger.info(
788
+ chalk.dim(`running value of \`${plat}\` on this machine...`),
789
+ true,
790
+ );
768
791
  return await exec(mac_code, { cwd: cwd() });
769
-
770
792
  }
793
+ } else if (language == "js") {
794
+ logger.info(chalk.dim(`running js...`), true);
771
795
 
772
- } else if (language == 'js') {
773
-
774
- logger.info(chalk.dim(`running js...`), true,);
775
-
776
796
  // must be assigned to `result`
777
797
  // do not overwrite `result`
778
798
  // must install locally via npm install
779
799
 
780
- if (config.TD_VM) {
781
- logger.info(chalk.dim(`running value of \`linux\` on vm...`), true);
782
- return await sandbox.send({
783
- type: "js.run",
784
- js: linux_code,
785
- });
786
- } else {
787
-
788
- logger.info(chalk.dim(`running value of \`${plat}\` in local JS vm...`), true);
800
+ // if (config.TD_VM) {
801
+ // logger.info(chalk.dim(`running value of \`linux\` on vm...`), true);
802
+ // return await sandbox.send({
803
+ // type: "js.run",
804
+ // js: linux_code,
805
+ // });
806
+ // } else {
807
+ logger.info(
808
+ chalk.dim(`running value of \`${plat}\` in local JS vm...`),
809
+ true,
810
+ );
789
811
 
790
- const context = vm.createContext({ require, console, fs, process });
812
+ const context = vm.createContext({ require, console, fs, process });
791
813
 
792
- const script = new vm.Script(`
814
+ const script = new vm.Script(`
793
815
  (async () => {
794
816
  ${scriptCode}
795
817
  })();
796
818
  `);
797
819
 
798
- await script.runInContext(context);
799
-
800
- // wait for context.result to resolve
801
- const stepResult = await context.result;
820
+ await script.runInContext(context);
802
821
 
803
- return stepResult;
804
- }
822
+ // wait for context.result to resolve
823
+ const stepResult = await context.result;
805
824
 
825
+ return stepResult;
826
+ // }
806
827
  } else {
807
828
  throw new AiError(`Language not supported: ${language}`);
808
829
  }
809
-
810
- }
830
+ },
811
831
  };
812
832
 
813
833
  module.exports = { commands, assert };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testdriverai",
3
- "version": "5.3.7",
3
+ "version": "5.3.9",
4
4
  "description": "Next generation autonomous AI agent for end-to-end testing of web & desktop",
5
5
  "main": "index.js",
6
6
  "bin": {