testdriverai 4.2.0-test.0 → 4.2.0-test.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.
@@ -0,0 +1,11 @@
1
+ # To get started with Dependabot version updates, you'll need to specify which
2
+ # package ecosystems to update and where the package manifests are located.
3
+ # Please see the documentation for all configuration options:
4
+ # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
5
+
6
+ version: 2
7
+ updates:
8
+ - package-ecosystem: "npm" # See documentation for possible values
9
+ directory: "/" # Location of package manifests
10
+ schedule:
11
+ interval: "weekly"
@@ -20,6 +20,7 @@ jobs:
20
20
  1. /run test.yml
21
21
  prerun: |
22
22
  Start-Process "C:/Program Files/Google/Chrome/Application/chrome.exe" -ArgumentList "--start-maximized", "${{ env.WEBSITE_URL }}"
23
+ version: test
23
24
 
24
25
  env:
25
26
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
package/agent.js CHANGED
@@ -202,8 +202,11 @@ if (!commandHistory.length) {
202
202
  ];
203
203
  }
204
204
 
205
- const exit = async (failed = true) => {
206
- await save();
205
+ const exit = async (failed = true, shouldSave = false) => {
206
+
207
+ if (shouldSave) {
208
+ await save();
209
+ }
207
210
 
208
211
  analytics.track("exit", { failed });
209
212
 
@@ -641,6 +644,16 @@ const actOnMarkdown = async (content, depth, pushToHistory = false) => {
641
644
  // simple function to backfill the chat history with a prompt and
642
645
  // then call `promptUser()` to get the user input
643
646
  const firstPrompt = async () => {
647
+
648
+ // should be start of new session
649
+ const sessionRes = await sdk.req("session/start", {
650
+ systemInformationOsInfo: await system.getSystemInformationOsInfo(),
651
+ mousePosition: await system.getMousePosition(),
652
+ activeWindow: await system.activeWin(),
653
+ });
654
+
655
+ session.set(sessionRes.data.id);
656
+
644
657
  // readline is what allows us to get user input
645
658
  rl = readline.createInterface({
646
659
  terminal: true,
@@ -681,7 +694,7 @@ const firstPrompt = async () => {
681
694
  if (input.indexOf("/summarize") == 0) {
682
695
  await summarize();
683
696
  } else if (input.indexOf("/quit") == 0) {
684
- await exit();
697
+ await exit(false, true);
685
698
  } else if (input.indexOf("/save") == 0) {
686
699
  await save({ filepath: commands[1] });
687
700
  } else if (input.indexOf("/undo") == 0) {
@@ -691,7 +704,7 @@ const firstPrompt = async () => {
691
704
  } else if (input.indexOf("/manual") == 0) {
692
705
  await manualInput(commands.slice(1).join(" "));
693
706
  } else if (input.indexOf("/run") == 0) {
694
- await run(commands[1], commands[2], commands[3]);
707
+ await run(commands[1], commands[2] == "true", commands[3] == "true");
695
708
  } else if (input.indexOf("/generate") == 0) {
696
709
  await generate(commands[1], commands[2]);
697
710
  } else {
@@ -705,7 +718,7 @@ const firstPrompt = async () => {
705
718
  // if file exists, load it
706
719
  if (fs.existsSync(thisFile)) {
707
720
  analytics.track("load");
708
- let object = await generator.ymlToHistory(
721
+ let object = await generator.hydrateFromYML(
709
722
  fs.readFileSync(thisFile, "utf-8"),
710
723
  );
711
724
 
@@ -835,7 +848,7 @@ let save = async ({ filepath = thisFile, silent = false } = {}) => {
835
848
  }
836
849
 
837
850
  // write reply to /tmp/oiResult.log.log
838
- let regression = await generator.historyToYml(executionHistory);
851
+ let regression = await generator.dumpToYML(executionHistory);
839
852
  try {
840
853
  fs.writeFileSync(filepath, regression);
841
854
  } catch (e) {
@@ -862,9 +875,10 @@ ${regression}
862
875
  // this will load a regression test from a file location
863
876
  // it parses the markdown file and executes the codeblocks exactly as if they were
864
877
  // generated by the AI in a single prompt
865
- let run = async (file, overwrite = false, shouldExit = true) => {
878
+ let run = async (file, shouldSave = false, shouldExit = true) => {
866
879
 
867
880
  setTerminalWindowTransparency(true);
881
+ emitter.emit(events.interactive, false);
868
882
 
869
883
  log.log("info", chalk.cyan(`running ${file}...`));
870
884
 
@@ -884,10 +898,10 @@ let run = async (file, overwrite = false, shouldExit = true) => {
884
898
  await exit(true);
885
899
  }
886
900
 
887
- console.log(yml)
888
- console.log(process.env)
901
+ let interpolationVars = JSON.parse(process.env["TD_INTERPOLATION_VARS"] || '{}');
902
+
889
903
  // Inject environment variables into any ${VAR} strings
890
- yml = parser.interpolate(yml, process.env);
904
+ yml = parser.interpolate(yml, interpolationVars);
891
905
 
892
906
  console.log(yml)
893
907
  let ymlObj = null;
@@ -937,13 +951,14 @@ ${yaml.dump(step)}
937
951
  await actOnMarkdown(markdown, 0, true);
938
952
  }
939
953
 
940
- if (overwrite || overwrite == "true") {
954
+ if (shouldSave) {
941
955
  await save({ filepath: file });
942
956
  }
943
957
 
944
958
  setTerminalWindowTransparency(false);
959
+ emitter.emit(events.interactive, true);
945
960
 
946
- if (shouldExit || shouldExit == "true") {
961
+ if (shouldExit) {
947
962
  await summarize();
948
963
  await exit(false);
949
964
  }
@@ -1059,15 +1074,6 @@ const start = async () => {
1059
1074
  console.log("");
1060
1075
  }
1061
1076
 
1062
- // should be start of new session
1063
- const sessionRes = await sdk.req("session/start", {
1064
- systemInformationOsInfo: await system.getSystemInformationOsInfo(),
1065
- mousePosition: await system.getMousePosition(),
1066
- activeWindow: await system.activeWin(),
1067
- });
1068
-
1069
- session.set(sessionRes.data);
1070
-
1071
1077
  analytics.track("command", { command: thisCommand, file: thisFile });
1072
1078
 
1073
1079
  if (thisCommand == "edit") {
@@ -246,7 +246,7 @@
246
246
  screenshotElement.classList.add('screenshot');
247
247
  setTimeout(() => {
248
248
  container.style.opacity = 1
249
- }, 300)
249
+ }, 2000)
250
250
  });
251
251
 
252
252
  ipcRenderer.on(events.mouseClick,
@@ -305,4 +305,4 @@
305
305
  </script>
306
306
  </body>
307
307
 
308
- </html>
308
+ </html>
package/lib/commands.js CHANGED
@@ -160,15 +160,12 @@ const assert = async (assertion, shouldThrow = false, async = false) => {
160
160
  return handleAssertResponse(response.data);
161
161
  }
162
162
  };
163
- const scroll = async (direction = "down", amount = 300, method = "keyboard") => {
163
+ const scroll = async (direction = "down", amount = 300, method = "mouse") => {
164
164
  await redraw.start();
165
165
 
166
166
  amount = parseInt(amount);
167
167
 
168
168
  if (method === "mouse") {
169
- // after experimenting, 200 is a good default for mouse, mostly as mouse will be called only when the user asks for it
170
- // and that happens when keyboard scrolling cannot do things when there's a pop up that needs to be scrolled over and
171
- // pop ups are usually smaller and needs a smaller amount of scrolling
172
169
  amount = 200;
173
170
  }
174
171
 
package/lib/generator.js CHANGED
@@ -2,6 +2,7 @@
2
2
  const yaml = require("js-yaml");
3
3
  const chalk = require("chalk");
4
4
  const package = require("../package.json");
5
+ const session = require("./session");
5
6
  // do the actual parsing
6
7
  // this library is very strict
7
8
  // note that errors are sent to the AI will it may self-heal
@@ -52,25 +53,30 @@ const jsonToManual = function (json, colors = true) {
52
53
  return params;
53
54
  };
54
55
 
55
- const historyToYml = async function (inputArray) {
56
+ const dumpToYML = async function (inputArray) {
57
+
56
58
  // use yml dump to convert json to yml
57
59
  let yml = await yaml.dump({
58
60
  version: package.version,
61
+ session: session.get(),
59
62
  steps: inputArray,
60
63
  });
61
64
 
62
65
  return yml;
63
66
  };
64
67
 
65
- const ymlToHistory = async function (yml) {
68
+ const hydrateFromYML = async function (yml) {
66
69
  // use yml load to convert yml to json
67
70
  let json = await yaml.load(yml);
71
+
72
+ session.set(json.session);
73
+
68
74
  return json;
69
75
  };
70
76
 
71
77
  module.exports = {
72
78
  manualToYml,
73
- historyToYml,
74
- ymlToHistory,
79
+ dumpToYML,
80
+ hydrateFromYML,
75
81
  jsonToManual,
76
82
  };
package/lib/sdk.js CHANGED
@@ -106,7 +106,7 @@ const req = async (path, data, onChunk) => {
106
106
  responseType: typeof onChunk === "function" ? "stream" : "json",
107
107
  data: {
108
108
  ...data,
109
- session: session.get()?.id,
109
+ session: session.get(),
110
110
  stream: typeof onChunk === "function",
111
111
  },
112
112
  };
package/lib/session.js CHANGED
@@ -5,6 +5,8 @@ module.exports = {
5
5
  return session;
6
6
  },
7
7
  set: (s) => {
8
- session = s;
8
+ if (s) {
9
+ session = s;
10
+ }
9
11
  },
10
12
  };
package/lib/system.js CHANGED
@@ -2,12 +2,11 @@
2
2
  const fs = require("fs");
3
3
  const os = require("os");
4
4
  const path = require("path");
5
- const screenshot = require("screenshot-desktop");
6
5
  const si = require("systeminformation");
7
- const activeWindow = require("active-win");
8
6
  const robot = require("robotjs");
9
7
  const sharp = require("sharp");
10
8
  const { emitter, events } = require("./events.js");
9
+ const { Monitor } = require("node-screenshots");
11
10
 
12
11
  let primaryDisplay = null;
13
12
 
@@ -48,7 +47,11 @@ const captureAndResize = async (scale = 1, silent = false, mouse = false) => {
48
47
  let step1 = tmpFilename();
49
48
  let step2 = tmpFilename();
50
49
 
51
- await screenshot({ filename: step1, format: "png" });
50
+ const monitors = Monitor.all();
51
+ const primaryMonitor = monitors.find(monitor => monitor.isPrimary);
52
+ const image = await primaryMonitor.captureImage(); // Capture the image asynchronously
53
+ const buffer = await image.toPng(); // Convert the image to PNG format
54
+ fs.writeFileSync(step1, buffer); // Save the image to a file
52
55
 
53
56
  // Fetch the mouse position
54
57
  const mousePos = robot.getMousePos();
@@ -111,9 +114,25 @@ const platform = () => {
111
114
  return platform;
112
115
  };
113
116
 
117
+ // Import get-windows using dynamic import for ES module compatibility
118
+ let activeWindowFn = null;
119
+ const initializeActiveWindow = async () => {
120
+ if (!activeWindowFn) {
121
+ const { activeWindow } = await import('get-windows');
122
+ activeWindowFn = activeWindow;
123
+ }
124
+ return activeWindowFn;
125
+ };
126
+
114
127
  // this is the focused window
115
128
  const activeWin = async () => {
116
- return await activeWindow();
129
+ try {
130
+ const activeWindow = await initializeActiveWindow();
131
+ return await activeWindow();
132
+ } catch (error) {
133
+ console.error('Error getting active window:', error);
134
+ return null;
135
+ }
117
136
  };
118
137
 
119
138
  const getMousePosition = async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testdriverai",
3
- "version": "4.2.0-test.0",
3
+ "version": "4.2.0-test.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": {
@@ -17,7 +17,6 @@
17
17
  "license": "ISC",
18
18
  "dependencies": {
19
19
  "@electerm/strip-ansi": "^1.0.0",
20
- "active-win": "^8.2.1",
21
20
  "axios": "^1.7.7",
22
21
  "chalk": "^4.1.2",
23
22
  "cli-progress": "^3.12.0",
@@ -25,6 +24,7 @@
25
24
  "decompress": "^4.2.1",
26
25
  "dotenv": "^16.4.5",
27
26
  "electron": "^33.0.2",
27
+ "get-windows": "^9.2.0",
28
28
  "jimp": "^0.22.12",
29
29
  "js-yaml": "^4.1.0",
30
30
  "mac-screen-capture-permissions": "^2.1.0",
@@ -34,14 +34,13 @@
34
34
  "marky": "^1.2.5",
35
35
  "node-ipc": "^12.0.0",
36
36
  "node-notifier": "^10.0.1",
37
+ "node-screenshots": "0.2.1",
37
38
  "odiff-bin": "^3.1.2",
38
39
  "prompts": "^2.4.2",
39
40
  "remark-parse": "^11.0.0",
40
- "rimraf": "^5.0.5",
41
41
  "robotjs": "^0.6.0",
42
42
  "sanitize-filename": "^1.6.3",
43
43
  "say": "^0.16.0",
44
- "screenshot-desktop": "^1.15.0",
45
44
  "semver": "^7.6.2",
46
45
  "sharp": "^0.33.5",
47
46
  "systeminformation": "^5.23.5",
@@ -49,16 +48,19 @@
49
48
  "uuid": "^10.0.0",
50
49
  "winston": "^3.13.0"
51
50
  },
51
+ "overrides": {
52
+ "glob": "^11.0.1",
53
+ "rimraf": "^5.0.10"
54
+ },
52
55
  "devDependencies": {
53
56
  "@eslint/js": "^9.10.0",
57
+ "chai": "^5.1.2",
54
58
  "esbuild": "0.20.2",
55
59
  "esbuild-plugin-fileloc": "^0.0.6",
56
60
  "eslint": "^9.10.0",
57
61
  "globals": "^15.9.0",
58
- "node-addon-api": "^8.0.0",
59
- "node-gyp": "^10.1.0",
60
62
  "mocha": "^10.8.2",
61
- "chai": "^5.1.2",
63
+ "node-addon-api": "^8.0.0",
62
64
  "prettier": "3.3.3"
63
65
  },
64
66
  "optionalDependencies": {