testdriverai 4.0.72 → 4.0.74
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 +1 -1
- package/index.js +3 -5
- package/lib/commands.js +12 -10
- package/lib/network.js +3 -0
- package/lib/redraw.js +79 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -81,7 +81,7 @@ If you have multiple monitors, make sure you do this on your primary display.
|
|
|
81
81
|
|
|
82
82
|
Now, just tell TestDriver what you want it to do. For now, stick with single commands like "click sign up" and "scroll down."
|
|
83
83
|
|
|
84
|
-
Later, try
|
|
84
|
+
Later, try to perform higher level objectives like "complete the onboarding."
|
|
85
85
|
|
|
86
86
|
```yaml
|
|
87
87
|
> Click on sign up
|
package/index.js
CHANGED
|
@@ -163,7 +163,7 @@ function fileCompleter(line) {
|
|
|
163
163
|
|
|
164
164
|
function completer(line) {
|
|
165
165
|
let completions =
|
|
166
|
-
"/summarize /save /run /quit /
|
|
166
|
+
"/summarize /save /run /quit /assert /undo /manual".split(" ");
|
|
167
167
|
if (line.startsWith("/run ")) {
|
|
168
168
|
return fileCompleter(line);
|
|
169
169
|
} else {
|
|
@@ -524,7 +524,7 @@ const generate = async (type, count) => {
|
|
|
524
524
|
let list = testPrompt.listsOrdered[0];
|
|
525
525
|
|
|
526
526
|
let contents = list
|
|
527
|
-
.map((item, index) => `${index + 1}.
|
|
527
|
+
.map((item, index) => `${index + 1}. ${item}`)
|
|
528
528
|
.join("\n");
|
|
529
529
|
fs.writeFileSync(path1, contents);
|
|
530
530
|
}
|
|
@@ -635,8 +635,6 @@ const firstPrompt = async () => {
|
|
|
635
635
|
await exit();
|
|
636
636
|
} else if (input.indexOf("/save") == 0) {
|
|
637
637
|
await save({ filepath: commands[1] });
|
|
638
|
-
} else if (input.indexOf("/explore") == 0) {
|
|
639
|
-
await humanInput(commands.slice(1).join(" "), true);
|
|
640
638
|
} else if (input.indexOf("/undo") == 0) {
|
|
641
639
|
await undo();
|
|
642
640
|
} else if (input.indexOf("/assert") == 0) {
|
|
@@ -648,7 +646,7 @@ const firstPrompt = async () => {
|
|
|
648
646
|
} else if (input.indexOf("/generate") == 0) {
|
|
649
647
|
await generate(commands[1], commands[2]);
|
|
650
648
|
} else {
|
|
651
|
-
await humanInput(input,
|
|
649
|
+
await humanInput(input, true);
|
|
652
650
|
}
|
|
653
651
|
|
|
654
652
|
setTerminalWindowTransparency(false);
|
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(
|
|
170
|
+
await redraw.wait(10000);
|
|
171
171
|
break;
|
|
172
172
|
case "down":
|
|
173
173
|
await robot.keyTap("pagedown");
|
|
174
|
-
await redraw.wait(
|
|
174
|
+
await redraw.wait(10000);
|
|
175
175
|
break;
|
|
176
176
|
case "left":
|
|
177
177
|
await robot.scrollMouse(amount * -1, 0);
|
|
178
|
-
await redraw.wait(
|
|
178
|
+
await redraw.wait(10000);
|
|
179
179
|
break;
|
|
180
180
|
case "right":
|
|
181
181
|
await robot.scrollMouse(amount, 0);
|
|
182
|
-
await redraw.wait(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
package/lib/redraw.js
CHANGED
|
@@ -3,6 +3,79 @@ 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
|
+
|
|
16
|
+
async function resetNetwork() {
|
|
17
|
+
lastTxBytes = null;
|
|
18
|
+
lastRxBytes = null;
|
|
19
|
+
measurements = [];
|
|
20
|
+
networkSettled = true;
|
|
21
|
+
lastUnsettled = null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function updateNetwork() {
|
|
25
|
+
si.networkStats().then(data => {
|
|
26
|
+
let thisRxBytes = data[0].rx_bytes;
|
|
27
|
+
let thisTxBytes = data[0].tx_bytes;
|
|
28
|
+
|
|
29
|
+
let diffRxBytes = lastRxBytes !== null ? thisRxBytes - lastRxBytes : 0;
|
|
30
|
+
let diffTxBytes = lastTxBytes !== null ? thisTxBytes - lastTxBytes : 0;
|
|
31
|
+
|
|
32
|
+
lastRxBytes = thisRxBytes;
|
|
33
|
+
lastTxBytes = thisTxBytes;
|
|
34
|
+
|
|
35
|
+
measurements.push({ rx: diffRxBytes, tx: diffTxBytes });
|
|
36
|
+
|
|
37
|
+
if (measurements.length > 60) {
|
|
38
|
+
measurements.shift();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let avgRx = measurements.reduce((acc, m) => acc + m.rx, 0) / measurements.length;
|
|
42
|
+
let avgTx = measurements.reduce((acc, m) => acc + m.tx, 0) / measurements.length;
|
|
43
|
+
|
|
44
|
+
let stdDevRx = Math.sqrt(measurements.reduce((acc, m) => acc + Math.pow(m.rx - avgRx, 2), 0) / measurements.length);
|
|
45
|
+
let stdDevTx = Math.sqrt(measurements.reduce((acc, m) => acc + Math.pow(m.tx - avgTx, 2), 0) / measurements.length);
|
|
46
|
+
|
|
47
|
+
let zIndexRx = stdDevRx !== 0 ? (diffRxBytes - avgRx) / stdDevRx : 0;
|
|
48
|
+
let zIndexTx = stdDevTx !== 0 ? (diffTxBytes - avgTx) / stdDevTx : 0;
|
|
49
|
+
|
|
50
|
+
// log time since unsettlement
|
|
51
|
+
|
|
52
|
+
if ((new Date().getTime() - lastUnsettled) < 2000) {
|
|
53
|
+
networkSettled = false;
|
|
54
|
+
} else {
|
|
55
|
+
|
|
56
|
+
if ((zIndexRx < 0 && zIndexTx < 0) ) {
|
|
57
|
+
lastUnsettled = null;
|
|
58
|
+
networkSettled = true;
|
|
59
|
+
} else {
|
|
60
|
+
lastUnsettled = new Date().getTime();
|
|
61
|
+
networkSettled = false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (process.env["DEV"]) {
|
|
67
|
+
|
|
68
|
+
if (!networkSettled) {
|
|
69
|
+
console.log(chalk.red(new Date().getTime(), `,${zIndexRx}`, `,${zIndexTx}`));
|
|
70
|
+
} else {
|
|
71
|
+
console.log(new Date().getTime(), `,${zIndexRx}`, `,${zIndexTx}`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
6
79
|
async function imageIsDifferent(image1Url, image2Url) {
|
|
7
80
|
|
|
8
81
|
// generate a temporary file path
|
|
@@ -36,17 +109,21 @@ async function imageIsDifferent(image1Url, image2Url) {
|
|
|
36
109
|
let startImage = null;
|
|
37
110
|
|
|
38
111
|
async function start() {
|
|
112
|
+
resetNetwork();
|
|
113
|
+
watchNetwork = setInterval(updateNetwork, 500);
|
|
39
114
|
startImage = await captureScreenPNG();
|
|
40
115
|
return startImage;
|
|
41
116
|
}
|
|
42
117
|
|
|
43
118
|
async function checkCondition(resolve, startTime, timeoutMs) {
|
|
44
119
|
let nowImage = await captureScreenPNG();
|
|
45
|
-
let
|
|
120
|
+
let screenDiff = await imageIsDifferent(startImage, nowImage);
|
|
46
121
|
|
|
47
|
-
if (
|
|
122
|
+
if (screenDiff && networkSettled) {
|
|
123
|
+
clearInterval(watchNetwork);
|
|
48
124
|
resolve("Condition met");
|
|
49
125
|
} else if (Date.now() - startTime >= timeoutMs) {
|
|
126
|
+
clearInterval(watchNetwork);
|
|
50
127
|
resolve("Timeout reached");
|
|
51
128
|
} else {
|
|
52
129
|
setTimeout(() => {
|