testdriverai 4.0.73 → 4.0.75

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/index.js CHANGED
@@ -57,7 +57,8 @@ let executionHistory = [];
57
57
  let errorCounts = {};
58
58
  let errorLimit = 3;
59
59
  let checkCount = 0;
60
- let checkLimit = 10;
60
+ let checkLimit = 3;
61
+ let lastScreenshot = null;
61
62
  let rl;
62
63
 
63
64
  // list of prompts that the user has given us
@@ -279,11 +280,17 @@ const check = async () => {
279
280
 
280
281
  console.log("");
281
282
  log.log("info", chalk.dim("checking..."), "testdriver");
282
- let image = await system.captureScreenBase64();
283
+
284
+ let thisScreenshot =await system.captureScreenBase64();
285
+ let images = [lastScreenshot, thisScreenshot];
283
286
  let mousePosition = await system.getMousePosition();
284
287
  let activeWindow = await system.activeWin();
285
288
 
286
- return await sdk.req("check", { tasks, image, mousePosition, activeWindow });
289
+ let response = await sdk.req("check", { tasks, images, mousePosition, activeWindow });
290
+
291
+ lastScreenshot = thisScreenshot;
292
+
293
+ return response;
287
294
  };
288
295
 
289
296
  // command is transformed from a single yml entry generated by the AI into a JSON object
@@ -458,7 +465,8 @@ const humanInput = async (currentTask, validateAndLoop = false) => {
458
465
 
459
466
  log.log("info", "");
460
467
 
461
- let image = await system.captureScreenBase64();
468
+ lastScreenshot = await system.captureScreenBase64();
469
+
462
470
  const mdStream = log.createMarkdownStreamLogger();
463
471
  let message = await sdk.req(
464
472
  "input",
@@ -466,7 +474,7 @@ const humanInput = async (currentTask, validateAndLoop = false) => {
466
474
  input: currentTask,
467
475
  mousePosition: await system.getMousePosition(),
468
476
  activeWindow: await system.activeWin(),
469
- image,
477
+ image: lastScreenshot,
470
478
  },
471
479
  (chunk) => mdStream.log(chunk),
472
480
  );
package/lib/commands.js CHANGED
@@ -167,19 +167,19 @@ const scroll = async (direction = "down", amount = 300) => {
167
167
  switch (direction) {
168
168
  case "up":
169
169
  await robot.keyTap("pageup");
170
- await redraw.wait(2000);
170
+ await redraw.wait(10000);
171
171
  break;
172
172
  case "down":
173
173
  await robot.keyTap("pagedown");
174
- await redraw.wait(2000);
174
+ await redraw.wait(10000);
175
175
  break;
176
176
  case "left":
177
177
  await robot.scrollMouse(amount * -1, 0);
178
- await redraw.wait(2000);
178
+ await redraw.wait(10000);
179
179
  break;
180
180
  case "right":
181
181
  await robot.scrollMouse(amount, 0);
182
- await redraw.wait(2000);
182
+ await redraw.wait(10000);
183
183
  break;
184
184
  default:
185
185
  throw new AiError("Direction not found");
@@ -199,7 +199,7 @@ const click = async (x, y, button = "left", click = "single") => {
199
199
  robot.moveMouseSmooth(x, y, 0.1);
200
200
  await delay(1000); // wait for the mouse to move
201
201
  robot.mouseClick(button, double);
202
- await redraw.wait(2000);
202
+ await redraw.wait(10000);
203
203
  return;
204
204
  };
205
205
 
@@ -210,7 +210,7 @@ const hover = async (x, y) => {
210
210
  y = parseInt(y);
211
211
 
212
212
  await robot.moveMouseSmooth(x, y, 0.1);
213
- await redraw.wait(2000);
213
+ await redraw.wait(10000);
214
214
 
215
215
  return;
216
216
  };
@@ -236,6 +236,7 @@ let commands = {
236
236
 
237
237
  log("info", "");
238
238
  log("info", chalk.dim("thinking..."), true);
239
+ log("info", "");
239
240
 
240
241
  const mdStream = logger.createMarkdownStreamLogger();
241
242
  let response = await sdk.req(
@@ -270,6 +271,7 @@ let commands = {
270
271
  // take a screenshot
271
272
  log("info", "");
272
273
  log("info", chalk.dim("thinking..."), true);
274
+ log("info", "");
273
275
 
274
276
  let response = await sdk.req("hover/image", {
275
277
  needle: description,
@@ -313,7 +315,7 @@ let commands = {
313
315
  await redraw.start();
314
316
  string = string.toString();
315
317
  await robot.typeString(string);
316
- await redraw.wait(1000);
318
+ await redraw.wait(10000);
317
319
  return;
318
320
  },
319
321
  // press keys
@@ -371,7 +373,7 @@ let commands = {
371
373
  // finally, press the keys
372
374
  robot.keyTap(keysPressed[0], modsToPress);
373
375
 
374
- await redraw.wait(2000);
376
+ await redraw.wait(10000);
375
377
 
376
378
  // keyTap will release the normal keys, but will not release modifier keys
377
379
  // so we need to release the modifier keys manually
@@ -457,7 +459,7 @@ let commands = {
457
459
  ),
458
460
  true,
459
461
  );
460
- await redraw.wait(2000);
462
+ await redraw.wait(10000);
461
463
  }
462
464
  }
463
465
 
@@ -486,7 +488,7 @@ let commands = {
486
488
  await robot.keyTap("f", commandOrControl);
487
489
  // type the text
488
490
  await robot.typeString(text);
489
- await redraw.wait(2000);
491
+ await redraw.wait(10000);
490
492
  await robot.keyTap("escape");
491
493
  } catch (e) {
492
494
  console.log(e);
package/lib/network.js ADDED
@@ -0,0 +1,3 @@
1
+
2
+
3
+
package/lib/redraw.js CHANGED
@@ -3,6 +3,80 @@ const os = require("os");
3
3
  const path = require("path");
4
4
  const { compare } = require("odiff-bin");
5
5
 
6
+ // network
7
+ const si = require('systeminformation');
8
+ const chalk = require('chalk');
9
+ let lastTxBytes = null;
10
+ let lastRxBytes = null;
11
+ let measurements = [];
12
+ let networkSettled = true;
13
+ let lastUnsettled = null;
14
+ let watchNetwork = null;
15
+ let screenHasRedrawn = null;
16
+
17
+ async function resetState() {
18
+ lastTxBytes = null;
19
+ lastRxBytes = null;
20
+ measurements = [];
21
+ networkSettled = true;
22
+ lastUnsettled = null;
23
+ }
24
+
25
+ async function updateNetwork() {
26
+ si.networkStats().then(data => {
27
+ let thisRxBytes = data[0].rx_bytes;
28
+ let thisTxBytes = data[0].tx_bytes;
29
+
30
+ let diffRxBytes = lastRxBytes !== null ? thisRxBytes - lastRxBytes : 0;
31
+ let diffTxBytes = lastTxBytes !== null ? thisTxBytes - lastTxBytes : 0;
32
+
33
+ lastRxBytes = thisRxBytes;
34
+ lastTxBytes = thisTxBytes;
35
+
36
+ measurements.push({ rx: diffRxBytes, tx: diffTxBytes });
37
+
38
+ if (measurements.length > 60) {
39
+ measurements.shift();
40
+ }
41
+
42
+ let avgRx = measurements.reduce((acc, m) => acc + m.rx, 0) / measurements.length;
43
+ let avgTx = measurements.reduce((acc, m) => acc + m.tx, 0) / measurements.length;
44
+
45
+ let stdDevRx = Math.sqrt(measurements.reduce((acc, m) => acc + Math.pow(m.rx - avgRx, 2), 0) / measurements.length);
46
+ let stdDevTx = Math.sqrt(measurements.reduce((acc, m) => acc + Math.pow(m.tx - avgTx, 2), 0) / measurements.length);
47
+
48
+ let zIndexRx = stdDevRx !== 0 ? (diffRxBytes - avgRx) / stdDevRx : 0;
49
+ let zIndexTx = stdDevTx !== 0 ? (diffTxBytes - avgTx) / stdDevTx : 0;
50
+
51
+ // log time since unsettlement
52
+
53
+ if ((new Date().getTime() - lastUnsettled) < 2000) {
54
+ networkSettled = false;
55
+ } else {
56
+
57
+ if ((zIndexRx < 0 && zIndexTx < 0) ) {
58
+ lastUnsettled = null;
59
+ networkSettled = true;
60
+ } else {
61
+ lastUnsettled = new Date().getTime();
62
+ networkSettled = false;
63
+ }
64
+
65
+ }
66
+
67
+ if (process.env["DEV"]) {
68
+
69
+ if (!networkSettled) {
70
+ console.log(chalk.red(new Date().getTime(), `,${zIndexRx}`, `,${zIndexTx}`));
71
+ } else {
72
+ console.log(new Date().getTime(), `,${zIndexRx}`, `,${zIndexTx}`);
73
+ }
74
+
75
+ }
76
+
77
+ });
78
+ }
79
+
6
80
  async function imageIsDifferent(image1Url, image2Url) {
7
81
 
8
82
  // generate a temporary file path
@@ -14,7 +88,7 @@ async function imageIsDifferent(image1Url, image2Url) {
14
88
  tmpImage,
15
89
  {
16
90
  failOnLayoutDiff: false,
17
- outputDiffMask: false,
91
+ outputDiffMask: false
18
92
  },
19
93
  );
20
94
 
@@ -22,7 +96,7 @@ async function imageIsDifferent(image1Url, image2Url) {
22
96
  return false;
23
97
  } else {
24
98
  if (reason === "pixel-diff") {
25
- if (diffPercentage > 15) {
99
+ if (diffPercentage > 5) {
26
100
  return true;
27
101
  } else {
28
102
  return false;
@@ -36,22 +110,43 @@ async function imageIsDifferent(image1Url, image2Url) {
36
110
  let startImage = null;
37
111
 
38
112
  async function start() {
113
+ resetState();
114
+ watchNetwork = setInterval(updateNetwork, 500);
39
115
  startImage = await captureScreenPNG();
40
116
  return startImage;
41
117
  }
42
118
 
43
119
  async function checkCondition(resolve, startTime, timeoutMs) {
120
+
44
121
  let nowImage = await captureScreenPNG();
45
- let result = await imageIsDifferent(startImage, nowImage);
122
+ let timeElapsed = Date.now() - startTime;
123
+
124
+ if (!screenHasRedrawn) {
125
+ screenHasRedrawn = await imageIsDifferent(startImage, nowImage);
126
+ }
46
127
 
47
- if (result) {
128
+ if (screenHasRedrawn && networkSettled) {
129
+ clearInterval(watchNetwork);
48
130
  resolve("Condition met");
49
- } else if (Date.now() - startTime >= timeoutMs) {
131
+ } else if (Date.now() - timeElapsed > timeoutMs) {
132
+ clearInterval(watchNetwork);
50
133
  resolve("Timeout reached");
51
134
  } else {
135
+
136
+ if (timeElapsed > 3000) {
137
+
138
+ if (!screenHasRedrawn) {
139
+ console.log(chalk.dim(` waiting for screen redraw...`));
140
+ }
141
+ if (!networkSettled) {
142
+ console.log(chalk.dim(` waiting for network to settle...`));
143
+ }
144
+
145
+ }
146
+
52
147
  setTimeout(() => {
53
148
  checkCondition(resolve, startTime, timeoutMs);
54
- }, 250);
149
+ }, 1000);
55
150
  }
56
151
  }
57
152
 
package/lib/system.js CHANGED
@@ -37,6 +37,10 @@ const captureAndResize = async (scale = 1) => {
37
37
  let step1 = tmpFilename();
38
38
  let step2 = tmpFilename();
39
39
 
40
+ if (process.env["DEV"]) {
41
+ console.log(step2)
42
+ }
43
+
40
44
  await screenshot({ filename: step1, format: "png" });
41
45
 
42
46
  // resize to 1:1 px ratio
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testdriverai",
3
- "version": "4.0.73",
3
+ "version": "4.0.75",
4
4
  "description": "Next generation autonomous AI agent for end-to-end testing of web & desktop",
5
5
  "main": "index.js",
6
6
  "bin": {