testdriverai 4.1.26 → 4.1.28
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/agent.js +17 -14
- package/lib/commander.js +10 -5
- package/lib/commands.js +48 -23
- package/package.json +1 -1
package/agent.js
CHANGED
|
@@ -215,11 +215,21 @@ const exit = async (failed = true) => {
|
|
|
215
215
|
});
|
|
216
216
|
};
|
|
217
217
|
|
|
218
|
+
const dieOnFatal = async (error) => {
|
|
219
|
+
console.log("");
|
|
220
|
+
log.log("info", chalk.red("Fatal Error") + `\n${error.message}`);
|
|
221
|
+
await summarize(error.message);
|
|
222
|
+
return await exit(true);
|
|
223
|
+
}
|
|
224
|
+
|
|
218
225
|
// creates a new "thread" in which the AI is given an error
|
|
219
226
|
// and responds. notice `actOnMarkdown` which will continue
|
|
220
227
|
// the thread until there are no more codeblocks to execute
|
|
221
228
|
const haveAIResolveError = async (error, markdown, depth = 0, undo = true) => {
|
|
222
|
-
|
|
229
|
+
|
|
230
|
+
if (thisCommand == "run" || error.fatal) {
|
|
231
|
+
return await dieOnFatal(error);
|
|
232
|
+
}
|
|
223
233
|
|
|
224
234
|
let eMessage = error.message ? error.message : error;
|
|
225
235
|
|
|
@@ -350,19 +360,12 @@ const runCommand = async (command, depth) => {
|
|
|
350
360
|
return await actOnMarkdown(response, depth);
|
|
351
361
|
}
|
|
352
362
|
} catch (error) {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
return await haveAIResolveError(
|
|
360
|
-
error,
|
|
361
|
-
yaml.dump({ commands: [yml] }),
|
|
362
|
-
depth,
|
|
363
|
-
true,
|
|
364
|
-
);
|
|
365
|
-
}
|
|
363
|
+
return await haveAIResolveError(
|
|
364
|
+
error,
|
|
365
|
+
yaml.dump({ commands: [yml] }),
|
|
366
|
+
depth,
|
|
367
|
+
true,
|
|
368
|
+
);
|
|
366
369
|
}
|
|
367
370
|
};
|
|
368
371
|
|
package/lib/commander.js
CHANGED
|
@@ -12,7 +12,6 @@ const sdk = require("./sdk");
|
|
|
12
12
|
// object is a json representation of the individual yml command
|
|
13
13
|
// the process turns markdown -> yml -> json -> js function execution
|
|
14
14
|
const run = async (object, depth) => {
|
|
15
|
-
|
|
16
15
|
log("debug", { object, depth });
|
|
17
16
|
|
|
18
17
|
// success returns null
|
|
@@ -63,7 +62,11 @@ commands:
|
|
|
63
62
|
speak(`scrolling ${object.direction}`);
|
|
64
63
|
log("info", generator.jsonToManual(object));
|
|
65
64
|
notify(generator.jsonToManual(object, false));
|
|
66
|
-
response = await commands.scroll(
|
|
65
|
+
response = await commands.scroll(
|
|
66
|
+
object.direction,
|
|
67
|
+
object.amount,
|
|
68
|
+
object.method,
|
|
69
|
+
);
|
|
67
70
|
break;
|
|
68
71
|
case "wait":
|
|
69
72
|
speak(`waiting ${object.timeout} seconds`);
|
|
@@ -143,6 +146,7 @@ commands:
|
|
|
143
146
|
object.text,
|
|
144
147
|
object.direction,
|
|
145
148
|
object.distance,
|
|
149
|
+
object.textMatchMethod,
|
|
146
150
|
object.method,
|
|
147
151
|
);
|
|
148
152
|
break;
|
|
@@ -154,6 +158,7 @@ commands:
|
|
|
154
158
|
object.description,
|
|
155
159
|
object.direction,
|
|
156
160
|
object.distance,
|
|
161
|
+
object.method,
|
|
157
162
|
);
|
|
158
163
|
break;
|
|
159
164
|
case "focus-application":
|
|
@@ -179,10 +184,10 @@ commands:
|
|
|
179
184
|
}
|
|
180
185
|
|
|
181
186
|
let timing = marky.stop(object.command);
|
|
182
|
-
|
|
187
|
+
|
|
183
188
|
await Promise.all([
|
|
184
|
-
sdk.req(
|
|
185
|
-
analytics.track("command", { data: object, depth, timing })
|
|
189
|
+
sdk.req("ran", { command: object.command, data: object }),
|
|
190
|
+
analytics.track("command", { data: object, depth, timing }),
|
|
186
191
|
]);
|
|
187
192
|
|
|
188
193
|
return response;
|
package/lib/commands.js
CHANGED
|
@@ -129,7 +129,7 @@ const assert = async (assertion, shouldThrow = false, async = false) => {
|
|
|
129
129
|
return true;
|
|
130
130
|
} else {
|
|
131
131
|
if (shouldThrow) {
|
|
132
|
-
throw new AiError(`AI Assertion failed
|
|
132
|
+
throw new AiError(`AI Assertion failed`, true);
|
|
133
133
|
} else {
|
|
134
134
|
return false;
|
|
135
135
|
}
|
|
@@ -160,18 +160,33 @@ 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) => {
|
|
163
|
+
const scroll = async (direction = "down", amount = 300, method = "keyboard") => {
|
|
164
164
|
await redraw.start();
|
|
165
165
|
|
|
166
166
|
amount = parseInt(amount);
|
|
167
167
|
|
|
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
|
+
amount = 200;
|
|
173
|
+
}
|
|
174
|
+
|
|
168
175
|
switch (direction) {
|
|
169
176
|
case "up":
|
|
170
|
-
|
|
177
|
+
if (method === "mouse") {
|
|
178
|
+
await robot.scrollMouse(0, amount );
|
|
179
|
+
} else {
|
|
180
|
+
await robot.keyTap("pageup");
|
|
181
|
+
}
|
|
171
182
|
await redraw.wait(2500);
|
|
172
183
|
break;
|
|
173
184
|
case "down":
|
|
174
|
-
|
|
185
|
+
if (method === "mouse") {
|
|
186
|
+
await robot.scrollMouse(0, amount * -1);
|
|
187
|
+
} else {
|
|
188
|
+
await robot.keyTap("pagedown");
|
|
189
|
+
}
|
|
175
190
|
await redraw.wait(2500);
|
|
176
191
|
break;
|
|
177
192
|
case "left":
|
|
@@ -321,7 +336,7 @@ let commands = {
|
|
|
321
336
|
mdStream.end();
|
|
322
337
|
|
|
323
338
|
if (!response?.data) {
|
|
324
|
-
throw new AiError("No
|
|
339
|
+
throw new AiError("No image or icon on screen matches description");
|
|
325
340
|
} else {
|
|
326
341
|
return response.data;
|
|
327
342
|
}
|
|
@@ -335,7 +350,7 @@ let commands = {
|
|
|
335
350
|
let result = await findImageOnScreen(relativePath, image);
|
|
336
351
|
|
|
337
352
|
if (!result) {
|
|
338
|
-
throw new AiError(`Image not found: ${relativePath}
|
|
353
|
+
throw new AiError(`Image not found: ${relativePath}`, true);
|
|
339
354
|
} else {
|
|
340
355
|
if (action === "click") {
|
|
341
356
|
await click(result.centerX, result.centerY, action);
|
|
@@ -521,29 +536,38 @@ let commands = {
|
|
|
521
536
|
text,
|
|
522
537
|
direction = "down",
|
|
523
538
|
maxDistance = 1200,
|
|
524
|
-
|
|
539
|
+
textMatchMethod = "turbo",
|
|
540
|
+
method = "keyboard"
|
|
525
541
|
) => {
|
|
526
542
|
await redraw.start();
|
|
527
543
|
|
|
528
544
|
log("info", chalk.dim(`scrolling for text: "${text}"...`), true);
|
|
529
545
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
546
|
+
if (method === "keyboard") {
|
|
547
|
+
try {
|
|
548
|
+
// use robot to press CMD+F
|
|
549
|
+
await robot.keyTap("f", commandOrControl);
|
|
550
|
+
// keyTap will release the normal keys, but will not release modifier keys
|
|
551
|
+
// so we need to release the modifier keys manually
|
|
552
|
+
robot.keyToggle(commandOrControl, "up");
|
|
553
|
+
// type the text
|
|
554
|
+
await robot.typeString(text);
|
|
555
|
+
await redraw.wait(5000);
|
|
556
|
+
await robot.keyTap("escape");
|
|
557
|
+
} catch (e) {
|
|
558
|
+
console.log(e);
|
|
559
|
+
throw new AiError(
|
|
560
|
+
"Could not find element using browser text search",
|
|
561
|
+
true,
|
|
562
|
+
);
|
|
563
|
+
}
|
|
543
564
|
}
|
|
544
565
|
|
|
545
566
|
let scrollDistance = 0;
|
|
546
567
|
let incrementDistance = 300;
|
|
568
|
+
if (method === "mouse") {
|
|
569
|
+
incrementDistance = 200;
|
|
570
|
+
}
|
|
547
571
|
let passed = false;
|
|
548
572
|
|
|
549
573
|
while (scrollDistance <= maxDistance && !passed) {
|
|
@@ -551,7 +575,7 @@ let commands = {
|
|
|
551
575
|
"assert/text",
|
|
552
576
|
{
|
|
553
577
|
needle: text,
|
|
554
|
-
method:
|
|
578
|
+
method: textMatchMethod,
|
|
555
579
|
image: await captureScreenBase64(),
|
|
556
580
|
},
|
|
557
581
|
(chunk) => {
|
|
@@ -570,7 +594,7 @@ let commands = {
|
|
|
570
594
|
),
|
|
571
595
|
true,
|
|
572
596
|
);
|
|
573
|
-
await scroll(direction);
|
|
597
|
+
await scroll(direction, incrementDistance, method);
|
|
574
598
|
scrollDistance = scrollDistance + incrementDistance;
|
|
575
599
|
}
|
|
576
600
|
}
|
|
@@ -589,6 +613,7 @@ let commands = {
|
|
|
589
613
|
description,
|
|
590
614
|
direction = "down",
|
|
591
615
|
maxDistance = 10000,
|
|
616
|
+
method = "keyboard",
|
|
592
617
|
) => {
|
|
593
618
|
log(
|
|
594
619
|
"info",
|
|
@@ -613,7 +638,7 @@ let commands = {
|
|
|
613
638
|
chalk.dim(`scrolling ${direction} ${incrementDistance} pixels...`),
|
|
614
639
|
true,
|
|
615
640
|
);
|
|
616
|
-
await scroll(direction);
|
|
641
|
+
await scroll(direction, incrementDistance, method);
|
|
617
642
|
scrollDistance = scrollDistance + incrementDistance;
|
|
618
643
|
}
|
|
619
644
|
}
|