momentic 0.0.10 → 0.0.11
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/bin/cli.js +1315 -1170
- package/dist/index.js +1085 -982
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -1,4 +1,55 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __defProps = Object.defineProperties;
|
|
4
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
5
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
8
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
9
|
+
var __spreadValues = (a, b) => {
|
|
10
|
+
for (var prop in b || (b = {}))
|
|
11
|
+
if (__hasOwnProp.call(b, prop))
|
|
12
|
+
__defNormalProp(a, prop, b[prop]);
|
|
13
|
+
if (__getOwnPropSymbols)
|
|
14
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
15
|
+
if (__propIsEnum.call(b, prop))
|
|
16
|
+
__defNormalProp(a, prop, b[prop]);
|
|
17
|
+
}
|
|
18
|
+
return a;
|
|
19
|
+
};
|
|
20
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
21
|
+
var __objRest = (source, exclude) => {
|
|
22
|
+
var target = {};
|
|
23
|
+
for (var prop in source)
|
|
24
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
25
|
+
target[prop] = source[prop];
|
|
26
|
+
if (source != null && __getOwnPropSymbols)
|
|
27
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
28
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
29
|
+
target[prop] = source[prop];
|
|
30
|
+
}
|
|
31
|
+
return target;
|
|
32
|
+
};
|
|
33
|
+
var __async = (__this, __arguments, generator) => {
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
var fulfilled = (value) => {
|
|
36
|
+
try {
|
|
37
|
+
step(generator.next(value));
|
|
38
|
+
} catch (e) {
|
|
39
|
+
reject(e);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
var rejected = (value) => {
|
|
43
|
+
try {
|
|
44
|
+
step(generator.throw(value));
|
|
45
|
+
} catch (e) {
|
|
46
|
+
reject(e);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
50
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
51
|
+
});
|
|
52
|
+
};
|
|
2
53
|
|
|
3
54
|
// src/cli.ts
|
|
4
55
|
import exec from "@actions/exec";
|
|
@@ -383,11 +434,10 @@ function parseCookieString(cookie) {
|
|
|
383
434
|
if (!parsedCookie.path && parsedCookie.domain) {
|
|
384
435
|
parsedCookie.path = "/";
|
|
385
436
|
}
|
|
386
|
-
const result = {
|
|
387
|
-
...parsedCookie,
|
|
437
|
+
const result = __spreadProps(__spreadValues({}, parsedCookie), {
|
|
388
438
|
expires: parsedCookie.expires ? parsedCookie.expires.getTime() / 1e3 : void 0,
|
|
389
439
|
sameSite
|
|
390
|
-
};
|
|
440
|
+
});
|
|
391
441
|
return result;
|
|
392
442
|
}
|
|
393
443
|
|
|
@@ -724,18 +774,6 @@ var defaultA11yNodeSerializeParams = {
|
|
|
724
774
|
noProperties: false
|
|
725
775
|
};
|
|
726
776
|
var ProcessedA11yNode = class {
|
|
727
|
-
id;
|
|
728
|
-
role;
|
|
729
|
-
name;
|
|
730
|
-
content;
|
|
731
|
-
properties;
|
|
732
|
-
// css-like selector from the root of the tree to the current node
|
|
733
|
-
pathFromRoot;
|
|
734
|
-
parent;
|
|
735
|
-
// md5 hash - set lazily in most cases (not used at the moment)
|
|
736
|
-
// md5Sum: string;
|
|
737
|
-
children;
|
|
738
|
-
backendNodeID;
|
|
739
777
|
constructor(params) {
|
|
740
778
|
this.id = params.id;
|
|
741
779
|
this.role = params.role;
|
|
@@ -747,10 +785,11 @@ var ProcessedA11yNode = class {
|
|
|
747
785
|
this.backendNodeID = params.backendNodeID;
|
|
748
786
|
}
|
|
749
787
|
getLogForm() {
|
|
788
|
+
var _a, _b;
|
|
750
789
|
return JSON.stringify({
|
|
751
790
|
id: this.id,
|
|
752
|
-
name: this.name
|
|
753
|
-
role: this.role
|
|
791
|
+
name: (_a = this.name) != null ? _a : "",
|
|
792
|
+
role: (_b = this.role) != null ? _b : "",
|
|
754
793
|
backendNodeId: this.backendNodeID
|
|
755
794
|
});
|
|
756
795
|
}
|
|
@@ -843,7 +882,7 @@ function getNodePathIdentifier(node) {
|
|
|
843
882
|
return `"${node.nodeId}"`;
|
|
844
883
|
}
|
|
845
884
|
function processA11yTreeDFS(node, parent, inputNodeMap, outputNodeMap) {
|
|
846
|
-
var _a, _b, _c, _d, _e, _f;
|
|
885
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
847
886
|
if (!parent && node.parentId) {
|
|
848
887
|
throw new Error(
|
|
849
888
|
`Got no parent for accessibility node ${node.nodeId}: ${JSON.stringify(
|
|
@@ -871,7 +910,7 @@ function processA11yTreeDFS(node, parent, inputNodeMap, outputNodeMap) {
|
|
|
871
910
|
});
|
|
872
911
|
}
|
|
873
912
|
outputNodeMap.set(processedNode.id, processedNode);
|
|
874
|
-
const children = node.childIds
|
|
913
|
+
const children = (_f = node.childIds) != null ? _f : [];
|
|
875
914
|
for (const childId of children) {
|
|
876
915
|
if (!childId) {
|
|
877
916
|
continue;
|
|
@@ -896,7 +935,7 @@ function processA11yTreeDFS(node, parent, inputNodeMap, outputNodeMap) {
|
|
|
896
935
|
}
|
|
897
936
|
if (processedNode.children.length === 1 && processedNode.children[0].role === "StaticText") {
|
|
898
937
|
const currentName = processedNode.name;
|
|
899
|
-
const childName = (
|
|
938
|
+
const childName = (_g = processedNode.children[0]) == null ? void 0 : _g.name;
|
|
900
939
|
if (currentName === childName || !childName) {
|
|
901
940
|
processedNode.children = [];
|
|
902
941
|
}
|
|
@@ -1099,20 +1138,14 @@ function isRequestRelevantForPageLoad(request, currentURL) {
|
|
|
1099
1138
|
}
|
|
1100
1139
|
|
|
1101
1140
|
// ../../packages/web-agent/src/browsers/chrome.ts
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1141
|
+
function initCDPSession(cdpClient) {
|
|
1142
|
+
return __async(this, null, function* () {
|
|
1143
|
+
yield cdpClient.send("Accessibility.enable");
|
|
1144
|
+
yield cdpClient.send("DOM.enable");
|
|
1145
|
+
yield cdpClient.send("Overlay.enable");
|
|
1146
|
+
});
|
|
1106
1147
|
}
|
|
1107
|
-
var
|
|
1108
|
-
browser;
|
|
1109
|
-
context;
|
|
1110
|
-
page;
|
|
1111
|
-
// key is nodeId, according to the a11y tree
|
|
1112
|
-
nodeMap = /* @__PURE__ */ new Map();
|
|
1113
|
-
cdpClient;
|
|
1114
|
-
logger;
|
|
1115
|
-
baseURL;
|
|
1148
|
+
var _ChromeBrowser = class _ChromeBrowser {
|
|
1116
1149
|
constructor({
|
|
1117
1150
|
browser,
|
|
1118
1151
|
context,
|
|
@@ -1121,6 +1154,8 @@ var ChromeBrowser = class _ChromeBrowser {
|
|
|
1121
1154
|
cdpClient,
|
|
1122
1155
|
logger
|
|
1123
1156
|
}) {
|
|
1157
|
+
// key is nodeId, according to the a11y tree
|
|
1158
|
+
this.nodeMap = /* @__PURE__ */ new Map();
|
|
1124
1159
|
this.browser = browser;
|
|
1125
1160
|
this.context = context;
|
|
1126
1161
|
this.page = page;
|
|
@@ -1128,106 +1163,117 @@ var ChromeBrowser = class _ChromeBrowser {
|
|
|
1128
1163
|
this.cdpClient = cdpClient;
|
|
1129
1164
|
this.logger = logger;
|
|
1130
1165
|
}
|
|
1131
|
-
static USER_AGENT = devices["Desktop Chrome"].userAgent;
|
|
1132
1166
|
/**
|
|
1133
1167
|
* Creates a new browser and waits for navigation to the given test URL.
|
|
1134
1168
|
*/
|
|
1135
|
-
static
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1169
|
+
static init(_0, _1, _2) {
|
|
1170
|
+
return __async(this, arguments, function* (baseURL, logger, onScreenshot, timeout = MAX_LOAD_TIMEOUT_MS) {
|
|
1171
|
+
const browser = yield chromium.launch({ headless: true });
|
|
1172
|
+
const context = yield browser.newContext({
|
|
1173
|
+
viewport: {
|
|
1174
|
+
width: 1920,
|
|
1175
|
+
height: 1080
|
|
1176
|
+
},
|
|
1177
|
+
// comment out the below if you are on Mac OS but you're using a monitor
|
|
1178
|
+
deviceScaleFactor: process.platform === "darwin" ? RETINA_WINDOW_SCALE_FACTOR : 1,
|
|
1179
|
+
userAgent: devices["Desktop Chrome"].userAgent,
|
|
1180
|
+
geolocation: { latitude: 37.7749, longitude: -122.4194 },
|
|
1181
|
+
// san francisco
|
|
1182
|
+
locale: "en-US",
|
|
1183
|
+
timezoneId: "America/Los_Angeles"
|
|
1184
|
+
});
|
|
1185
|
+
const page = yield context.newPage();
|
|
1186
|
+
const cdpClient = yield context.newCDPSession(page);
|
|
1187
|
+
const chrome = new _ChromeBrowser({
|
|
1188
|
+
browser,
|
|
1189
|
+
context,
|
|
1190
|
+
page,
|
|
1191
|
+
baseURL,
|
|
1192
|
+
cdpClient,
|
|
1193
|
+
logger
|
|
1194
|
+
});
|
|
1195
|
+
let completed = false;
|
|
1196
|
+
const navigateAndInitCDP = () => __async(this, null, function* () {
|
|
1197
|
+
try {
|
|
1198
|
+
yield chrome.navigate(baseURL, false);
|
|
1199
|
+
yield initCDPSession(cdpClient);
|
|
1200
|
+
} catch (err) {
|
|
1201
|
+
logger.error({ err }, "Failed to initialize chrome browser");
|
|
1202
|
+
} finally {
|
|
1203
|
+
completed = true;
|
|
1204
|
+
}
|
|
1205
|
+
});
|
|
1206
|
+
void navigateAndInitCDP();
|
|
1207
|
+
const sendScreenshot = () => __async(this, null, function* () {
|
|
1208
|
+
if (!onScreenshot) {
|
|
1209
|
+
return;
|
|
1210
|
+
}
|
|
1211
|
+
try {
|
|
1212
|
+
onScreenshot({
|
|
1213
|
+
viewport: chrome.viewport,
|
|
1214
|
+
buffer: yield chrome.screenshot()
|
|
1215
|
+
});
|
|
1216
|
+
} catch (err) {
|
|
1217
|
+
logger.error({ err }, "Failed to take screenshot");
|
|
1218
|
+
}
|
|
1219
|
+
});
|
|
1220
|
+
void sendScreenshot();
|
|
1221
|
+
const screenshotInterval = setInterval(() => {
|
|
1222
|
+
void sendScreenshot();
|
|
1223
|
+
}, 250);
|
|
1224
|
+
const startTime = Date.now();
|
|
1225
|
+
while (!completed && Date.now() - startTime < timeout) {
|
|
1226
|
+
yield sleep(CHECK_INTERVAL_MS);
|
|
1175
1227
|
}
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
} catch (err) {
|
|
1182
|
-
logger.error({ err }, "Failed to take screenshot");
|
|
1228
|
+
clearInterval(screenshotInterval);
|
|
1229
|
+
if (!completed) {
|
|
1230
|
+
logger.warn(
|
|
1231
|
+
"Timeout elapsed waiting for browser to initialize - are you sure this page is accessible?"
|
|
1232
|
+
);
|
|
1183
1233
|
}
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
const screenshotInterval = setInterval(() => {
|
|
1187
|
-
void sendScreenshot();
|
|
1188
|
-
}, 250);
|
|
1189
|
-
const startTime = Date.now();
|
|
1190
|
-
while (!completed && Date.now() - startTime < timeout) {
|
|
1191
|
-
await sleep(CHECK_INTERVAL_MS);
|
|
1192
|
-
}
|
|
1193
|
-
clearInterval(screenshotInterval);
|
|
1194
|
-
if (!completed) {
|
|
1195
|
-
logger.warn(
|
|
1196
|
-
"Timeout elapsed waiting for browser to initialize - are you sure this page is accessible?"
|
|
1197
|
-
);
|
|
1198
|
-
}
|
|
1199
|
-
return chrome;
|
|
1234
|
+
return chrome;
|
|
1235
|
+
});
|
|
1200
1236
|
}
|
|
1201
1237
|
// Things to do on every page load
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1238
|
+
pageSetup() {
|
|
1239
|
+
return __async(this, null, function* () {
|
|
1240
|
+
yield this.page.evaluate(addCursorScript);
|
|
1241
|
+
yield this.page.evaluate(addIDsScript);
|
|
1242
|
+
});
|
|
1205
1243
|
}
|
|
1206
|
-
|
|
1207
|
-
|
|
1244
|
+
wait(timeoutMs) {
|
|
1245
|
+
return __async(this, null, function* () {
|
|
1246
|
+
yield this.page.waitForTimeout(timeoutMs);
|
|
1247
|
+
});
|
|
1208
1248
|
}
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1249
|
+
cleanup() {
|
|
1250
|
+
return __async(this, null, function* () {
|
|
1251
|
+
yield this.page.close();
|
|
1252
|
+
yield this.context.close();
|
|
1253
|
+
yield this.browser.close();
|
|
1254
|
+
});
|
|
1213
1255
|
}
|
|
1214
1256
|
get closed() {
|
|
1215
1257
|
return this.page.isClosed() || !this.browser.isConnected();
|
|
1216
1258
|
}
|
|
1217
|
-
|
|
1218
|
-
return
|
|
1259
|
+
html() {
|
|
1260
|
+
return __async(this, null, function* () {
|
|
1261
|
+
return yield this.page.content();
|
|
1262
|
+
});
|
|
1219
1263
|
}
|
|
1220
1264
|
get url() {
|
|
1221
1265
|
return this.page.url();
|
|
1222
1266
|
}
|
|
1223
|
-
|
|
1224
|
-
return
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1267
|
+
screenshot(quality = 100, scale = "device") {
|
|
1268
|
+
return __async(this, null, function* () {
|
|
1269
|
+
return yield this.page.screenshot({
|
|
1270
|
+
fullPage: false,
|
|
1271
|
+
quality,
|
|
1272
|
+
scale,
|
|
1273
|
+
type: "jpeg",
|
|
1274
|
+
// allow the blinking text cursor thing to remain there
|
|
1275
|
+
caret: "initial"
|
|
1276
|
+
});
|
|
1231
1277
|
});
|
|
1232
1278
|
}
|
|
1233
1279
|
get viewport() {
|
|
@@ -1237,539 +1283,595 @@ var ChromeBrowser = class _ChromeBrowser {
|
|
|
1237
1283
|
}
|
|
1238
1284
|
return viewport;
|
|
1239
1285
|
}
|
|
1240
|
-
|
|
1241
|
-
this
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1286
|
+
navigate(url, wrapPossibleNavigation = true) {
|
|
1287
|
+
return __async(this, null, function* () {
|
|
1288
|
+
this.logger.debug(`Navigating to ${url}`);
|
|
1289
|
+
const startTime = Date.now();
|
|
1290
|
+
const doNav = () => __async(this, null, function* () {
|
|
1291
|
+
try {
|
|
1292
|
+
yield this.page.goto(url, {
|
|
1293
|
+
timeout: MAX_LOAD_TIMEOUT_MS
|
|
1294
|
+
});
|
|
1295
|
+
this.logger.debug(
|
|
1296
|
+
{ url },
|
|
1297
|
+
`Got load event in ${Math.floor(Date.now() - startTime)}ms`
|
|
1298
|
+
);
|
|
1299
|
+
} catch (e) {
|
|
1300
|
+
this.logger.warn(
|
|
1301
|
+
{ url, type: "navigate", err: e },
|
|
1302
|
+
"Timeout elapsed waiting for page to load, continuing anyways..."
|
|
1303
|
+
);
|
|
1304
|
+
}
|
|
1305
|
+
});
|
|
1306
|
+
if (wrapPossibleNavigation) {
|
|
1307
|
+
yield this.wrapPossibleNavigation(doNav);
|
|
1308
|
+
} else {
|
|
1309
|
+
yield doNav();
|
|
1310
|
+
}
|
|
1311
|
+
if (CHROME_INTERNAL_URLS.has(this.url) && process.env.NODE_ENV === "production") {
|
|
1312
|
+
throw new Error(
|
|
1313
|
+
`${url} took too long to load \u{1F61E}. Please ensure the site and your internet are working.`
|
|
1256
1314
|
);
|
|
1257
1315
|
}
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
} else {
|
|
1262
|
-
await doNav();
|
|
1263
|
-
}
|
|
1264
|
-
if (CHROME_INTERNAL_URLS.has(this.url) && process.env.NODE_ENV === "production") {
|
|
1265
|
-
throw new Error(
|
|
1266
|
-
`${url} took too long to load \u{1F61E}. Please ensure the site and your internet are working.`
|
|
1267
|
-
);
|
|
1268
|
-
}
|
|
1269
|
-
await this.pageSetup();
|
|
1270
|
-
this.logger.debug({ url }, "Navigation complete");
|
|
1271
|
-
}
|
|
1272
|
-
async fill(target, text, options = {}) {
|
|
1273
|
-
const element = await this.click(target, {
|
|
1274
|
-
doubleClick: false,
|
|
1275
|
-
rightClick: false
|
|
1276
|
-
});
|
|
1277
|
-
await this.type(text, options);
|
|
1278
|
-
return element;
|
|
1279
|
-
}
|
|
1280
|
-
async type(text, options = {}) {
|
|
1281
|
-
const { clearContent = true, pressKeysSequentially = false } = options;
|
|
1282
|
-
if (clearContent) {
|
|
1283
|
-
await this.page.keyboard.press("Meta+A");
|
|
1284
|
-
await this.page.keyboard.press("Backspace");
|
|
1285
|
-
}
|
|
1286
|
-
if (pressKeysSequentially) {
|
|
1287
|
-
await this.page.keyboard.type(text);
|
|
1288
|
-
} else {
|
|
1289
|
-
await this.page.keyboard.insertText(text);
|
|
1290
|
-
}
|
|
1316
|
+
yield this.pageSetup();
|
|
1317
|
+
this.logger.debug({ url }, "Navigation complete");
|
|
1318
|
+
});
|
|
1291
1319
|
}
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
}
|
|
1301
|
-
async selectOptionByA11yID(index, option) {
|
|
1302
|
-
const node = this.nodeMap.get(`${index}`);
|
|
1303
|
-
if (!node) {
|
|
1304
|
-
throw new Error(`Could not find node in DOM with index: ${index}`);
|
|
1305
|
-
}
|
|
1306
|
-
if (!node.backendNodeID) {
|
|
1307
|
-
throw new Error(
|
|
1308
|
-
`Select target missing backend node id: ${node.getLogForm()}`
|
|
1309
|
-
);
|
|
1310
|
-
}
|
|
1311
|
-
const locator = await this.getLocatorFromBackendID(node.backendNodeID);
|
|
1312
|
-
await locator.selectOption(option, {
|
|
1313
|
-
timeout: COMPLICATED_BROWSER_ACTION_TIMEOUT_MS
|
|
1320
|
+
fill(_0, _1) {
|
|
1321
|
+
return __async(this, arguments, function* (target, text, options = {}) {
|
|
1322
|
+
const element = yield this.click(target, {
|
|
1323
|
+
doubleClick: false,
|
|
1324
|
+
rightClick: false
|
|
1325
|
+
});
|
|
1326
|
+
yield this.type(text, options);
|
|
1327
|
+
return element;
|
|
1314
1328
|
});
|
|
1315
|
-
await this.highlightNode(node);
|
|
1316
|
-
return node.serialize({ noChildren: true, noProperties: true, noID: true });
|
|
1317
1329
|
}
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1330
|
+
type(_0) {
|
|
1331
|
+
return __async(this, arguments, function* (text, options = {}) {
|
|
1332
|
+
const { clearContent = true, pressKeysSequentially = false } = options;
|
|
1333
|
+
if (clearContent) {
|
|
1334
|
+
yield this.page.keyboard.press("Meta+A");
|
|
1335
|
+
yield this.page.keyboard.press("Backspace");
|
|
1336
|
+
}
|
|
1337
|
+
if (pressKeysSequentially) {
|
|
1338
|
+
yield this.page.keyboard.type(text);
|
|
1339
|
+
} else {
|
|
1340
|
+
yield this.page.keyboard.insertText(text);
|
|
1341
|
+
}
|
|
1342
|
+
});
|
|
1324
1343
|
}
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
);
|
|
1334
|
-
}
|
|
1335
|
-
await this.highlightNode(node);
|
|
1344
|
+
clickByA11yID(_0) {
|
|
1345
|
+
return __async(this, arguments, function* (index, options = {}) {
|
|
1346
|
+
const node = this.nodeMap.get(`${index}`);
|
|
1347
|
+
if (!node) {
|
|
1348
|
+
throw new Error(`Could not find node in DOM with index: ${index}`);
|
|
1349
|
+
}
|
|
1350
|
+
const nodeClicked = yield this.clickUsingCDP(node, options);
|
|
1351
|
+
yield this.highlightNode(nodeClicked);
|
|
1352
|
+
return node.serialize({ noChildren: true, noProperties: true, noID: true });
|
|
1353
|
+
});
|
|
1336
1354
|
}
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1355
|
+
selectOptionByA11yID(index, option) {
|
|
1356
|
+
return __async(this, null, function* () {
|
|
1357
|
+
const node = this.nodeMap.get(`${index}`);
|
|
1358
|
+
if (!node) {
|
|
1359
|
+
throw new Error(`Could not find node in DOM with index: ${index}`);
|
|
1360
|
+
}
|
|
1361
|
+
if (!node.backendNodeID) {
|
|
1362
|
+
throw new Error(
|
|
1363
|
+
`Select target missing backend node id: ${node.getLogForm()}`
|
|
1364
|
+
);
|
|
1365
|
+
}
|
|
1366
|
+
const locator = yield this.getLocatorFromBackendID(node.backendNodeID);
|
|
1367
|
+
yield locator.selectOption(option, {
|
|
1368
|
+
timeout: COMPLICATED_BROWSER_ACTION_TIMEOUT_MS
|
|
1342
1369
|
});
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
}
|
|
1346
|
-
|
|
1370
|
+
yield this.highlightNode(node);
|
|
1371
|
+
return node.serialize({ noChildren: true, noProperties: true, noID: true });
|
|
1372
|
+
});
|
|
1373
|
+
}
|
|
1374
|
+
highlight(target) {
|
|
1375
|
+
return __async(this, null, function* () {
|
|
1376
|
+
try {
|
|
1377
|
+
yield this.highlightByA11yID(target.id);
|
|
1378
|
+
} catch (err) {
|
|
1379
|
+
this.logger.warn({ err, target }, "Failed to highlight target");
|
|
1380
|
+
}
|
|
1381
|
+
});
|
|
1382
|
+
}
|
|
1383
|
+
highlightByA11yID(index) {
|
|
1384
|
+
return __async(this, null, function* () {
|
|
1385
|
+
const node = this.nodeMap.get(`${index}`);
|
|
1386
|
+
if (!node) {
|
|
1387
|
+
throw new Error(`Could not find node in DOM with index: ${index}`);
|
|
1388
|
+
}
|
|
1389
|
+
if (!node.backendNodeID) {
|
|
1390
|
+
throw new Error(
|
|
1391
|
+
`Select target missing backend node id: ${node.getLogForm()}`
|
|
1392
|
+
);
|
|
1393
|
+
}
|
|
1394
|
+
yield this.highlightNode(node);
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
highlightNode(node) {
|
|
1398
|
+
return __async(this, null, function* () {
|
|
1347
1399
|
try {
|
|
1348
|
-
|
|
1400
|
+
yield this.cdpClient.send("Overlay.highlightNode", {
|
|
1401
|
+
highlightConfig: NODE_HIGHLIGHT_CONFIG,
|
|
1349
1402
|
backendNodeId: node.backendNodeID
|
|
1350
1403
|
});
|
|
1351
1404
|
} catch (err) {
|
|
1352
|
-
this.logger.
|
|
1405
|
+
this.logger.warn({ err }, "Failed to add node highlight");
|
|
1353
1406
|
}
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1407
|
+
const hideHighlight = () => __async(this, null, function* () {
|
|
1408
|
+
try {
|
|
1409
|
+
yield this.cdpClient.send("Overlay.hideHighlight", {
|
|
1410
|
+
backendNodeId: node.backendNodeID
|
|
1411
|
+
});
|
|
1412
|
+
} catch (err) {
|
|
1413
|
+
this.logger.debug({ err }, "Failed to remove node highlight");
|
|
1414
|
+
}
|
|
1415
|
+
});
|
|
1416
|
+
setTimeout(() => {
|
|
1417
|
+
void hideHighlight();
|
|
1418
|
+
}, HIGHLIGHT_DURATION_MS);
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1421
|
+
wrapPossibleNavigation(_0) {
|
|
1422
|
+
return __async(this, arguments, function* (fn, timeoutMS = MAX_LOAD_TIMEOUT_MS) {
|
|
1423
|
+
const startTime = Date.now();
|
|
1424
|
+
const startURL = this.url;
|
|
1425
|
+
let lastRequestReceived = Date.now();
|
|
1426
|
+
const firedRequests = /* @__PURE__ */ new Map();
|
|
1427
|
+
const finishedRequests = /* @__PURE__ */ new Map();
|
|
1428
|
+
const requestFinishedListener = (request) => {
|
|
1429
|
+
var _a;
|
|
1430
|
+
const key = serializeRequest(request);
|
|
1431
|
+
finishedRequests.set(key, ((_a = finishedRequests.get(key)) != null ? _a : 0) + 1);
|
|
1432
|
+
};
|
|
1433
|
+
const requestFiredListener = (request) => {
|
|
1434
|
+
var _a;
|
|
1435
|
+
if (!isRequestRelevantForPageLoad(request, this.url)) {
|
|
1436
|
+
this.logger.debug(
|
|
1437
|
+
{
|
|
1438
|
+
uri: serializeRequest(request)
|
|
1439
|
+
},
|
|
1440
|
+
"Ignoring request for page load network stability"
|
|
1441
|
+
);
|
|
1442
|
+
return;
|
|
1443
|
+
}
|
|
1444
|
+
const key = serializeRequest(request);
|
|
1371
1445
|
this.logger.debug(
|
|
1372
1446
|
{
|
|
1373
|
-
uri:
|
|
1447
|
+
uri: key
|
|
1374
1448
|
},
|
|
1375
|
-
"
|
|
1449
|
+
"Request fired on page load, delaying network stability"
|
|
1376
1450
|
);
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
this.
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
if (e instanceof Error)
|
|
1395
|
-
return e;
|
|
1396
|
-
return new Error(`${e}`);
|
|
1397
|
-
});
|
|
1398
|
-
await sleep(CHECK_INTERVAL_MS);
|
|
1399
|
-
const unwrapAndThrowError = async (p) => {
|
|
1400
|
-
const v = await p;
|
|
1401
|
-
if (v instanceof Error) {
|
|
1402
|
-
throw v;
|
|
1403
|
-
}
|
|
1404
|
-
return v;
|
|
1405
|
-
};
|
|
1406
|
-
let unfinishedRequests = /* @__PURE__ */ new Set();
|
|
1407
|
-
const waitForNetworkIdle = async () => {
|
|
1408
|
-
while (!rejected && Date.now() - startTime < timeoutMS) {
|
|
1409
|
-
unfinishedRequests = /* @__PURE__ */ new Set();
|
|
1410
|
-
await sleep(CHECK_INTERVAL_MS);
|
|
1411
|
-
if (Date.now() - lastRequestReceived <= NETWORK_STABLE_DURATION_MS) {
|
|
1412
|
-
continue;
|
|
1451
|
+
firedRequests.set(key, ((_a = firedRequests.get(key)) != null ? _a : 0) + 1);
|
|
1452
|
+
lastRequestReceived = Date.now();
|
|
1453
|
+
};
|
|
1454
|
+
this.page.on("requestfinished", requestFinishedListener);
|
|
1455
|
+
this.page.on("request", requestFiredListener);
|
|
1456
|
+
let rejected = false;
|
|
1457
|
+
const retPromise = fn().catch((e) => {
|
|
1458
|
+
rejected = true;
|
|
1459
|
+
if (e instanceof Error)
|
|
1460
|
+
return e;
|
|
1461
|
+
return new Error(`${e}`);
|
|
1462
|
+
});
|
|
1463
|
+
yield sleep(CHECK_INTERVAL_MS);
|
|
1464
|
+
const unwrapAndThrowError = (p) => __async(this, null, function* () {
|
|
1465
|
+
const v = yield p;
|
|
1466
|
+
if (v instanceof Error) {
|
|
1467
|
+
throw v;
|
|
1413
1468
|
}
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1469
|
+
return v;
|
|
1470
|
+
});
|
|
1471
|
+
let unfinishedRequests = /* @__PURE__ */ new Set();
|
|
1472
|
+
const waitForNetworkIdle = () => __async(this, null, function* () {
|
|
1473
|
+
while (!rejected && Date.now() - startTime < timeoutMS) {
|
|
1474
|
+
unfinishedRequests = /* @__PURE__ */ new Set();
|
|
1475
|
+
yield sleep(CHECK_INTERVAL_MS);
|
|
1476
|
+
if (Date.now() - lastRequestReceived <= NETWORK_STABLE_DURATION_MS) {
|
|
1477
|
+
continue;
|
|
1478
|
+
}
|
|
1479
|
+
let anyDifference = false;
|
|
1480
|
+
for (const key of firedRequests.keys()) {
|
|
1481
|
+
if (firedRequests.get(key) !== finishedRequests.get(key)) {
|
|
1482
|
+
this.logger.debug({ uri: key }, "Waiting on request to finish");
|
|
1483
|
+
anyDifference = true;
|
|
1484
|
+
unfinishedRequests.add(key);
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
if (!anyDifference) {
|
|
1488
|
+
this.logger.debug(
|
|
1489
|
+
{
|
|
1490
|
+
url: this.url,
|
|
1491
|
+
requests: JSON.stringify(Array.from(firedRequests.entries()))
|
|
1492
|
+
},
|
|
1493
|
+
`Network idle in ${Math.floor(Date.now() - startTime)}ms`
|
|
1494
|
+
);
|
|
1495
|
+
return true;
|
|
1420
1496
|
}
|
|
1421
1497
|
}
|
|
1422
|
-
if (!
|
|
1423
|
-
this.logger.
|
|
1498
|
+
if (!rejected) {
|
|
1499
|
+
this.logger.warn(
|
|
1424
1500
|
{
|
|
1425
1501
|
url: this.url,
|
|
1426
|
-
requests: JSON.stringify(Array.from(
|
|
1502
|
+
requests: JSON.stringify(Array.from(unfinishedRequests.entries()))
|
|
1427
1503
|
},
|
|
1428
|
-
|
|
1504
|
+
"Timeout elapsed waiting for network idle, continuing anyways..."
|
|
1429
1505
|
);
|
|
1430
|
-
return true;
|
|
1431
1506
|
}
|
|
1507
|
+
return false;
|
|
1508
|
+
});
|
|
1509
|
+
const waitResult = yield waitForNetworkIdle();
|
|
1510
|
+
this.page.off("requestfinished", requestFinishedListener);
|
|
1511
|
+
this.page.off("request", requestFiredListener);
|
|
1512
|
+
if (!waitResult) {
|
|
1513
|
+
return unwrapAndThrowError(retPromise);
|
|
1432
1514
|
}
|
|
1433
|
-
if (!rejected) {
|
|
1434
|
-
this.logger.
|
|
1435
|
-
|
|
1436
|
-
url: this.url,
|
|
1437
|
-
requests: JSON.stringify(Array.from(unfinishedRequests.entries()))
|
|
1438
|
-
},
|
|
1439
|
-
"Timeout elapsed waiting for network idle, continuing anyways..."
|
|
1515
|
+
if (!rejected && urlChanged(this.url, startURL)) {
|
|
1516
|
+
this.logger.debug(
|
|
1517
|
+
`Detected url change in wrapPossibleNavigation, waiting for load state`
|
|
1440
1518
|
);
|
|
1519
|
+
try {
|
|
1520
|
+
yield this.page.waitForLoadState("load", {
|
|
1521
|
+
timeout: timeoutMS - (Date.now() - startTime)
|
|
1522
|
+
});
|
|
1523
|
+
} catch (e) {
|
|
1524
|
+
this.logger.warn(
|
|
1525
|
+
{ url: this.url },
|
|
1526
|
+
"Timeout elapsed waiting for load state to fire, continuing anyways..."
|
|
1527
|
+
);
|
|
1528
|
+
}
|
|
1441
1529
|
}
|
|
1442
|
-
return false;
|
|
1443
|
-
};
|
|
1444
|
-
const waitResult = await waitForNetworkIdle();
|
|
1445
|
-
this.page.off("requestfinished", requestFinishedListener);
|
|
1446
|
-
this.page.off("request", requestFiredListener);
|
|
1447
|
-
if (!waitResult) {
|
|
1448
1530
|
return unwrapAndThrowError(retPromise);
|
|
1449
|
-
}
|
|
1450
|
-
if (!rejected && urlChanged(this.url, startURL)) {
|
|
1451
|
-
this.logger.debug(
|
|
1452
|
-
`Detected url change in wrapPossibleNavigation, waiting for load state`
|
|
1453
|
-
);
|
|
1454
|
-
try {
|
|
1455
|
-
await this.page.waitForLoadState("load", {
|
|
1456
|
-
timeout: timeoutMS - (Date.now() - startTime)
|
|
1457
|
-
});
|
|
1458
|
-
} catch (e) {
|
|
1459
|
-
this.logger.warn(
|
|
1460
|
-
{ url: this.url },
|
|
1461
|
-
"Timeout elapsed waiting for load state to fire, continuing anyways..."
|
|
1462
|
-
);
|
|
1463
|
-
}
|
|
1464
|
-
}
|
|
1465
|
-
return unwrapAndThrowError(retPromise);
|
|
1531
|
+
});
|
|
1466
1532
|
}
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1533
|
+
click(_0) {
|
|
1534
|
+
return __async(this, arguments, function* (target, options = {}) {
|
|
1535
|
+
const elementInteracted = yield this.wrapPossibleNavigation(
|
|
1536
|
+
() => this.clickByA11yID(target.id, options)
|
|
1537
|
+
);
|
|
1538
|
+
return elementInteracted;
|
|
1539
|
+
});
|
|
1472
1540
|
}
|
|
1473
|
-
|
|
1474
|
-
return this
|
|
1541
|
+
selectOption(target, option) {
|
|
1542
|
+
return __async(this, null, function* () {
|
|
1543
|
+
return this.selectOptionByA11yID(target.id, option);
|
|
1544
|
+
});
|
|
1475
1545
|
}
|
|
1476
|
-
|
|
1477
|
-
|
|
1546
|
+
press(key) {
|
|
1547
|
+
return __async(this, null, function* () {
|
|
1548
|
+
yield this.wrapPossibleNavigation(() => this.page.keyboard.press(key));
|
|
1549
|
+
});
|
|
1478
1550
|
}
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1551
|
+
refresh() {
|
|
1552
|
+
return __async(this, null, function* () {
|
|
1553
|
+
yield this.page.reload();
|
|
1554
|
+
yield this.pageSetup();
|
|
1555
|
+
});
|
|
1482
1556
|
}
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1557
|
+
getA11yTree() {
|
|
1558
|
+
return __async(this, null, function* () {
|
|
1559
|
+
let processedTree = null;
|
|
1560
|
+
let attempt = 0;
|
|
1561
|
+
const url = this.url;
|
|
1562
|
+
while (!processedTree) {
|
|
1563
|
+
try {
|
|
1564
|
+
this.logger.debug(`Getting a11y tree at ${url}`);
|
|
1565
|
+
const graph = yield this.getRawA11yTree();
|
|
1566
|
+
if (!graph.root || graph.allNodes.length === 0) {
|
|
1567
|
+
throw new Error("No a11y tree found on page");
|
|
1568
|
+
}
|
|
1569
|
+
processedTree = processA11yTree(graph);
|
|
1570
|
+
} catch (e) {
|
|
1571
|
+
this.logger.error({ err: e, url }, "Error fetching a11y tree");
|
|
1572
|
+
if (attempt === 0) {
|
|
1573
|
+
yield sleep(1e3);
|
|
1574
|
+
attempt++;
|
|
1575
|
+
} else {
|
|
1576
|
+
throw new Error(`Max retries exceeded fetching a11y tree: ${e}`);
|
|
1577
|
+
}
|
|
1502
1578
|
}
|
|
1503
1579
|
}
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
this.logger.warn("A11y tree was pruned entirely");
|
|
1507
|
-
}
|
|
1508
|
-
this.nodeMap = processedTree.nodeMap;
|
|
1509
|
-
return processedTree;
|
|
1510
|
-
}
|
|
1511
|
-
async getRawA11yTree() {
|
|
1512
|
-
const url = this.page.url();
|
|
1513
|
-
let lastTreeUpdateTimestamp = Date.now();
|
|
1514
|
-
const treeUpdateListener = () => {
|
|
1515
|
-
lastTreeUpdateTimestamp = Date.now();
|
|
1516
|
-
};
|
|
1517
|
-
this.cdpClient.addListener(
|
|
1518
|
-
"Accessibility.nodesUpdated",
|
|
1519
|
-
treeUpdateListener
|
|
1520
|
-
);
|
|
1521
|
-
let accessibilityTreeLoadFired = false;
|
|
1522
|
-
const accessibilityLoadListener = () => {
|
|
1523
|
-
this.logger.info({ url }, `A11y tree load event fired`);
|
|
1524
|
-
accessibilityTreeLoadFired = true;
|
|
1525
|
-
};
|
|
1526
|
-
this.cdpClient.addListener(
|
|
1527
|
-
"Accessibility.loadComplete",
|
|
1528
|
-
accessibilityLoadListener
|
|
1529
|
-
);
|
|
1530
|
-
const a11yLoadStart = Date.now();
|
|
1531
|
-
let timeoutTriggered = true;
|
|
1532
|
-
while (Date.now() - a11yLoadStart < A11Y_STABLE_TIMEOUT_MS) {
|
|
1533
|
-
await sleep(CHECK_INTERVAL_MS);
|
|
1534
|
-
if (!accessibilityTreeLoadFired && Date.now() - a11yLoadStart < A11Y_LOAD_TIMEOUT_MS) {
|
|
1535
|
-
this.logger.debug({ url }, `A11y tree not loaded yet, waiting...`);
|
|
1536
|
-
continue;
|
|
1537
|
-
}
|
|
1538
|
-
if (Date.now() - lastTreeUpdateTimestamp >= A11Y_STABLE_DURATION_MS) {
|
|
1539
|
-
this.logger.debug({ url }, `A11y tree not stable yet, waiting...`);
|
|
1540
|
-
continue;
|
|
1580
|
+
if (!processedTree.root) {
|
|
1581
|
+
this.logger.warn("A11y tree was pruned entirely");
|
|
1541
1582
|
}
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
}
|
|
1545
|
-
this.logger.debug(
|
|
1546
|
-
{
|
|
1547
|
-
duration: Date.now() - a11yLoadStart,
|
|
1548
|
-
eventReceived: accessibilityTreeLoadFired,
|
|
1549
|
-
timeoutTriggered
|
|
1550
|
-
},
|
|
1551
|
-
"A11y wait phase completed"
|
|
1552
|
-
);
|
|
1553
|
-
const { node: root } = await this.cdpClient.send(
|
|
1554
|
-
"Accessibility.getRootAXNode"
|
|
1555
|
-
);
|
|
1556
|
-
const { nodes } = await this.cdpClient.send("Accessibility.queryAXTree", {
|
|
1557
|
-
backendNodeId: root.backendDOMNodeId
|
|
1583
|
+
this.nodeMap = processedTree.nodeMap;
|
|
1584
|
+
return processedTree;
|
|
1558
1585
|
});
|
|
1559
|
-
this.cdpClient.removeListener(
|
|
1560
|
-
"Accessibility.loadComplete",
|
|
1561
|
-
accessibilityLoadListener
|
|
1562
|
-
);
|
|
1563
|
-
this.cdpClient.removeListener(
|
|
1564
|
-
"Accessibility.nodesUpdated",
|
|
1565
|
-
treeUpdateListener
|
|
1566
|
-
);
|
|
1567
|
-
return {
|
|
1568
|
-
root,
|
|
1569
|
-
allNodes: nodes
|
|
1570
|
-
};
|
|
1571
1586
|
}
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1587
|
+
getRawA11yTree() {
|
|
1588
|
+
return __async(this, null, function* () {
|
|
1589
|
+
const url = this.page.url();
|
|
1590
|
+
let lastTreeUpdateTimestamp = Date.now();
|
|
1591
|
+
const treeUpdateListener = () => {
|
|
1592
|
+
lastTreeUpdateTimestamp = Date.now();
|
|
1593
|
+
};
|
|
1594
|
+
this.cdpClient.addListener(
|
|
1595
|
+
"Accessibility.nodesUpdated",
|
|
1596
|
+
treeUpdateListener
|
|
1577
1597
|
);
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
objectId
|
|
1587
|
-
});
|
|
1588
|
-
const attrResult = await this.cdpClient.send("DOM.getAttributes", {
|
|
1589
|
-
nodeId: cdpNodeResult.nodeId
|
|
1590
|
-
});
|
|
1591
|
-
const attributes = attrResult.attributes;
|
|
1592
|
-
const indexAttr = attributes.findIndex((s) => s === "data-momentic-id");
|
|
1593
|
-
if (indexAttr === -1) {
|
|
1594
|
-
return "";
|
|
1595
|
-
}
|
|
1596
|
-
return attributes[indexAttr + 1] || "";
|
|
1597
|
-
}
|
|
1598
|
-
async getLocatorFromBackendID(backendNodeId) {
|
|
1599
|
-
await this.page.evaluate(addIDsScript);
|
|
1600
|
-
const cdpResolveResult = await this.cdpClient.send("DOM.resolveNode", {
|
|
1601
|
-
backendNodeId
|
|
1602
|
-
});
|
|
1603
|
-
if (!cdpResolveResult || !cdpResolveResult.object.objectId) {
|
|
1604
|
-
throw new Error(`Could not resolve backend node ${backendNodeId}`);
|
|
1605
|
-
}
|
|
1606
|
-
try {
|
|
1607
|
-
const id = await this.getIDAttributeUsingCDP(
|
|
1608
|
-
cdpResolveResult.object.objectId
|
|
1598
|
+
let accessibilityTreeLoadFired = false;
|
|
1599
|
+
const accessibilityLoadListener = () => {
|
|
1600
|
+
this.logger.info({ url }, `A11y tree load event fired`);
|
|
1601
|
+
accessibilityTreeLoadFired = true;
|
|
1602
|
+
};
|
|
1603
|
+
this.cdpClient.addListener(
|
|
1604
|
+
"Accessibility.loadComplete",
|
|
1605
|
+
accessibilityLoadListener
|
|
1609
1606
|
);
|
|
1610
|
-
|
|
1611
|
-
|
|
1607
|
+
const a11yLoadStart = Date.now();
|
|
1608
|
+
let timeoutTriggered = true;
|
|
1609
|
+
while (Date.now() - a11yLoadStart < A11Y_STABLE_TIMEOUT_MS) {
|
|
1610
|
+
yield sleep(CHECK_INTERVAL_MS);
|
|
1611
|
+
if (!accessibilityTreeLoadFired && Date.now() - a11yLoadStart < A11Y_LOAD_TIMEOUT_MS) {
|
|
1612
|
+
this.logger.debug({ url }, `A11y tree not loaded yet, waiting...`);
|
|
1613
|
+
continue;
|
|
1614
|
+
}
|
|
1615
|
+
if (Date.now() - lastTreeUpdateTimestamp >= A11Y_STABLE_DURATION_MS) {
|
|
1616
|
+
this.logger.debug({ url }, `A11y tree not stable yet, waiting...`);
|
|
1617
|
+
continue;
|
|
1618
|
+
}
|
|
1619
|
+
timeoutTriggered = false;
|
|
1620
|
+
break;
|
|
1612
1621
|
}
|
|
1613
|
-
|
|
1614
|
-
} catch (err) {
|
|
1615
|
-
this.logger.error(
|
|
1622
|
+
this.logger.debug(
|
|
1616
1623
|
{
|
|
1617
|
-
|
|
1624
|
+
duration: Date.now() - a11yLoadStart,
|
|
1625
|
+
eventReceived: accessibilityTreeLoadFired,
|
|
1626
|
+
timeoutTriggered
|
|
1618
1627
|
},
|
|
1619
|
-
"
|
|
1628
|
+
"A11y wait phase completed"
|
|
1620
1629
|
);
|
|
1621
|
-
|
|
1622
|
-
|
|
1630
|
+
const { node: root } = yield this.cdpClient.send(
|
|
1631
|
+
"Accessibility.getRootAXNode"
|
|
1632
|
+
);
|
|
1633
|
+
const { nodes } = yield this.cdpClient.send("Accessibility.queryAXTree", {
|
|
1634
|
+
backendNodeId: root.backendDOMNodeId
|
|
1635
|
+
});
|
|
1636
|
+
this.cdpClient.removeListener(
|
|
1637
|
+
"Accessibility.loadComplete",
|
|
1638
|
+
accessibilityLoadListener
|
|
1639
|
+
);
|
|
1640
|
+
this.cdpClient.removeListener(
|
|
1641
|
+
"Accessibility.nodesUpdated",
|
|
1642
|
+
treeUpdateListener
|
|
1643
|
+
);
|
|
1644
|
+
return {
|
|
1645
|
+
root,
|
|
1646
|
+
allNodes: nodes
|
|
1647
|
+
};
|
|
1648
|
+
});
|
|
1623
1649
|
}
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
if (!candidateNode || candidateNode.role === "RootWebArea") {
|
|
1650
|
+
clickUsingVisualCoordinates(backendNodeId) {
|
|
1651
|
+
return __async(this, null, function* () {
|
|
1652
|
+
const location = yield this.getElementLocation(backendNodeId);
|
|
1653
|
+
if (!location) {
|
|
1629
1654
|
throw new Error(
|
|
1630
|
-
`
|
|
1655
|
+
`Could not find element location with backend node id: ${backendNodeId}`
|
|
1631
1656
|
);
|
|
1632
1657
|
}
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1658
|
+
this.logger.debug({ location }, "Executing mouse click");
|
|
1659
|
+
yield this.page.mouse.click(location.centerX, location.centerY);
|
|
1660
|
+
});
|
|
1661
|
+
}
|
|
1662
|
+
// Get the "id" attribute value from an HTML element.
|
|
1663
|
+
getIDAttributeUsingCDP(objectId) {
|
|
1664
|
+
return __async(this, null, function* () {
|
|
1665
|
+
yield this.cdpClient.send("DOM.getDocument", { depth: 0 });
|
|
1666
|
+
const cdpNodeResult = yield this.cdpClient.send("DOM.requestNode", {
|
|
1667
|
+
objectId
|
|
1668
|
+
});
|
|
1669
|
+
const attrResult = yield this.cdpClient.send("DOM.getAttributes", {
|
|
1670
|
+
nodeId: cdpNodeResult.nodeId
|
|
1671
|
+
});
|
|
1672
|
+
const attributes = attrResult.attributes;
|
|
1673
|
+
const indexAttr = attributes.findIndex((s) => s === "data-momentic-id");
|
|
1674
|
+
if (indexAttr === -1) {
|
|
1675
|
+
return "";
|
|
1636
1676
|
}
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1677
|
+
return attributes[indexAttr + 1] || "";
|
|
1678
|
+
});
|
|
1679
|
+
}
|
|
1680
|
+
getLocatorFromBackendID(backendNodeId) {
|
|
1681
|
+
return __async(this, null, function* () {
|
|
1682
|
+
yield this.page.evaluate(addIDsScript);
|
|
1683
|
+
const cdpResolveResult = yield this.cdpClient.send("DOM.resolveNode", {
|
|
1684
|
+
backendNodeId
|
|
1685
|
+
});
|
|
1686
|
+
if (!cdpResolveResult || !cdpResolveResult.object.objectId) {
|
|
1687
|
+
throw new Error(`Could not resolve backend node ${backendNodeId}`);
|
|
1645
1688
|
}
|
|
1646
1689
|
try {
|
|
1647
|
-
const
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
} else {
|
|
1653
|
-
await locator.click({
|
|
1654
|
-
timeout: BROWSER_ACTION_TIMEOUT_MS,
|
|
1655
|
-
button: options.rightClick ? "right" : "left"
|
|
1656
|
-
});
|
|
1657
|
-
}
|
|
1658
|
-
if (candidateNode.id !== originalNode.id) {
|
|
1659
|
-
this.logger.info(
|
|
1660
|
-
{
|
|
1661
|
-
oldNode: originalNode.getLogForm(),
|
|
1662
|
-
newNode: candidateNode.getLogForm()
|
|
1663
|
-
},
|
|
1664
|
-
`Redirected click successfully to new element`
|
|
1665
|
-
);
|
|
1690
|
+
const id = yield this.getIDAttributeUsingCDP(
|
|
1691
|
+
cdpResolveResult.object.objectId
|
|
1692
|
+
);
|
|
1693
|
+
if (!id) {
|
|
1694
|
+
throw new Error("Failed getting data-momentic-id attribute using CDP");
|
|
1666
1695
|
}
|
|
1667
|
-
return
|
|
1696
|
+
return this.page.locator(`[data-momentic-id="${id}"]`);
|
|
1668
1697
|
} catch (err) {
|
|
1669
1698
|
this.logger.error(
|
|
1670
|
-
{
|
|
1671
|
-
|
|
1699
|
+
{
|
|
1700
|
+
err
|
|
1701
|
+
},
|
|
1702
|
+
"Failed to get ID attribute"
|
|
1672
1703
|
);
|
|
1673
|
-
|
|
1674
|
-
candidateNode = candidateNode.parent;
|
|
1704
|
+
throw err;
|
|
1675
1705
|
}
|
|
1676
|
-
}
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
)
|
|
1706
|
+
});
|
|
1707
|
+
}
|
|
1708
|
+
clickUsingCDP(_0) {
|
|
1709
|
+
return __async(this, arguments, function* (originalNode, options = {}) {
|
|
1710
|
+
let clickAttempts = 0;
|
|
1711
|
+
let candidateNode = originalNode;
|
|
1712
|
+
while (clickAttempts < MAX_BROWSER_ACTION_ATTEMPTS) {
|
|
1713
|
+
if (!candidateNode || candidateNode.role === "RootWebArea") {
|
|
1714
|
+
throw new Error(
|
|
1715
|
+
`Attempted to click node with no clickable surrounding elements: ${originalNode.getLogForm()}`
|
|
1716
|
+
);
|
|
1717
|
+
}
|
|
1718
|
+
if (candidateNode.role === "StaticText") {
|
|
1719
|
+
candidateNode = candidateNode.parent;
|
|
1720
|
+
continue;
|
|
1721
|
+
}
|
|
1722
|
+
const candidateNodeID = candidateNode.backendNodeID;
|
|
1723
|
+
if (!candidateNodeID) {
|
|
1724
|
+
this.logger.warn(
|
|
1725
|
+
{ node: candidateNode.getLogForm() },
|
|
1726
|
+
"Click candidate had no backend node ID"
|
|
1727
|
+
);
|
|
1728
|
+
candidateNode = candidateNode.parent;
|
|
1729
|
+
continue;
|
|
1730
|
+
}
|
|
1731
|
+
try {
|
|
1732
|
+
const locator = yield this.getLocatorFromBackendID(candidateNodeID);
|
|
1733
|
+
if (options.doubleClick) {
|
|
1734
|
+
yield locator.dblclick({
|
|
1735
|
+
timeout: BROWSER_ACTION_TIMEOUT_MS
|
|
1736
|
+
});
|
|
1737
|
+
} else {
|
|
1738
|
+
yield locator.click({
|
|
1739
|
+
timeout: BROWSER_ACTION_TIMEOUT_MS,
|
|
1740
|
+
button: options.rightClick ? "right" : "left"
|
|
1741
|
+
});
|
|
1742
|
+
}
|
|
1743
|
+
if (candidateNode.id !== originalNode.id) {
|
|
1744
|
+
this.logger.info(
|
|
1745
|
+
{
|
|
1746
|
+
oldNode: originalNode.getLogForm(),
|
|
1747
|
+
newNode: candidateNode.getLogForm()
|
|
1748
|
+
},
|
|
1749
|
+
`Redirected click successfully to new element`
|
|
1750
|
+
);
|
|
1751
|
+
}
|
|
1752
|
+
return candidateNode;
|
|
1753
|
+
} catch (err) {
|
|
1754
|
+
this.logger.error(
|
|
1755
|
+
{ err, node: candidateNode.getLogForm() },
|
|
1756
|
+
"Failed click or click timed out"
|
|
1757
|
+
);
|
|
1758
|
+
clickAttempts++;
|
|
1759
|
+
candidateNode = candidateNode.parent;
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
throw new Error(
|
|
1763
|
+
`Max click redirection attempts exhausted on original element: ${originalNode.getLogForm()}`
|
|
1764
|
+
);
|
|
1765
|
+
});
|
|
1680
1766
|
}
|
|
1681
1767
|
/**
|
|
1682
1768
|
* Currently unused, but could be useful for vision model integration.
|
|
1683
1769
|
* Gets x/y position of an a11y node.
|
|
1684
1770
|
*/
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
if (process.platform === "darwin" && devicePixelRatio === 1) {
|
|
1695
|
-
devicePixelRatio = RETINA_WINDOW_SCALE_FACTOR;
|
|
1696
|
-
}
|
|
1697
|
-
const document2 = tree["documents"][0];
|
|
1698
|
-
const layout = document2["layout"];
|
|
1699
|
-
const nodes = document2["nodes"];
|
|
1700
|
-
const nodeNames = nodes["nodeName"] || [];
|
|
1701
|
-
const backendNodeIds = nodes["backendNodeId"] || [];
|
|
1702
|
-
const layoutNodeIndex = layout["nodeIndex"];
|
|
1703
|
-
const bounds = layout["bounds"];
|
|
1704
|
-
let cursor2 = -1;
|
|
1705
|
-
for (let i = 0; i < nodeNames.length; i++) {
|
|
1706
|
-
if (backendNodeIds[i] === backendNodeId) {
|
|
1707
|
-
cursor2 = layoutNodeIndex.indexOf(i);
|
|
1708
|
-
break;
|
|
1709
|
-
}
|
|
1710
|
-
}
|
|
1711
|
-
if (cursor2 === -1) {
|
|
1712
|
-
throw new Error(
|
|
1713
|
-
`Could not find any backend node with ID ${backendNodeId}`
|
|
1771
|
+
getElementLocation(backendNodeId) {
|
|
1772
|
+
return __async(this, null, function* () {
|
|
1773
|
+
const tree = yield this.cdpClient.send("DOMSnapshot.captureSnapshot", {
|
|
1774
|
+
computedStyles: [],
|
|
1775
|
+
includeDOMRects: true,
|
|
1776
|
+
includePaintOrder: true
|
|
1777
|
+
});
|
|
1778
|
+
let devicePixelRatio = yield this.page.evaluate(
|
|
1779
|
+
() => window.devicePixelRatio
|
|
1714
1780
|
);
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1781
|
+
if (process.platform === "darwin" && devicePixelRatio === 1) {
|
|
1782
|
+
devicePixelRatio = RETINA_WINDOW_SCALE_FACTOR;
|
|
1783
|
+
}
|
|
1784
|
+
const document2 = tree["documents"][0];
|
|
1785
|
+
const layout = document2["layout"];
|
|
1786
|
+
const nodes = document2["nodes"];
|
|
1787
|
+
const nodeNames = nodes["nodeName"] || [];
|
|
1788
|
+
const backendNodeIds = nodes["backendNodeId"] || [];
|
|
1789
|
+
const layoutNodeIndex = layout["nodeIndex"];
|
|
1790
|
+
const bounds = layout["bounds"];
|
|
1791
|
+
let cursor2 = -1;
|
|
1792
|
+
for (let i = 0; i < nodeNames.length; i++) {
|
|
1793
|
+
if (backendNodeIds[i] === backendNodeId) {
|
|
1794
|
+
cursor2 = layoutNodeIndex.indexOf(i);
|
|
1795
|
+
break;
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
if (cursor2 === -1) {
|
|
1799
|
+
throw new Error(
|
|
1800
|
+
`Could not find any backend node with ID ${backendNodeId}`
|
|
1801
|
+
);
|
|
1802
|
+
}
|
|
1803
|
+
let [x = 0, y = 0, width = 0, height = 0] = bounds[cursor2];
|
|
1804
|
+
x /= devicePixelRatio;
|
|
1805
|
+
y /= devicePixelRatio;
|
|
1806
|
+
width /= devicePixelRatio;
|
|
1807
|
+
height /= devicePixelRatio;
|
|
1808
|
+
const centerX = x + width / 2;
|
|
1809
|
+
const centerY = y + height / 2;
|
|
1810
|
+
return { centerX, centerY };
|
|
1811
|
+
});
|
|
1724
1812
|
}
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1813
|
+
scrollUp() {
|
|
1814
|
+
return __async(this, null, function* () {
|
|
1815
|
+
yield this.page.evaluate(() => {
|
|
1816
|
+
(document.scrollingElement || document.body).scrollTop = (document.scrollingElement || document.body).scrollTop - window.innerHeight;
|
|
1817
|
+
});
|
|
1818
|
+
yield this.page.evaluate(() => {
|
|
1819
|
+
(document.scrollingElement || document.body).scrollTop = (document.scrollingElement || document.body).scrollTop + window.innerHeight;
|
|
1820
|
+
});
|
|
1728
1821
|
});
|
|
1729
|
-
|
|
1730
|
-
|
|
1822
|
+
}
|
|
1823
|
+
scrollDown() {
|
|
1824
|
+
return __async(this, null, function* () {
|
|
1825
|
+
yield this.page.evaluate(() => {
|
|
1826
|
+
(document.scrollingElement || document.body).scrollTop = (document.scrollingElement || document.body).scrollTop + window.innerHeight;
|
|
1827
|
+
});
|
|
1731
1828
|
});
|
|
1732
1829
|
}
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1830
|
+
goForward() {
|
|
1831
|
+
return __async(this, null, function* () {
|
|
1832
|
+
yield this.wrapPossibleNavigation(
|
|
1833
|
+
() => this.page.goForward({ timeout: MAX_LOAD_TIMEOUT_MS })
|
|
1834
|
+
);
|
|
1835
|
+
yield this.pageSetup();
|
|
1736
1836
|
});
|
|
1737
1837
|
}
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1838
|
+
goBack() {
|
|
1839
|
+
return __async(this, null, function* () {
|
|
1840
|
+
yield this.wrapPossibleNavigation(
|
|
1841
|
+
() => this.page.goBack({ timeout: MAX_LOAD_TIMEOUT_MS })
|
|
1842
|
+
);
|
|
1843
|
+
yield this.pageSetup();
|
|
1844
|
+
});
|
|
1743
1845
|
}
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
this.cdpClient = await this.context.newCDPSession(page);
|
|
1761
|
-
await initCDPSession(this.cdpClient);
|
|
1762
|
-
this.logger.info(`Switching to tab ${i} with url ${page.url()}`);
|
|
1763
|
-
return;
|
|
1846
|
+
switchToPage(urlSubstring) {
|
|
1847
|
+
return __async(this, null, function* () {
|
|
1848
|
+
const allPages = yield this.context.pages();
|
|
1849
|
+
for (let i = 0; i < allPages.length; i++) {
|
|
1850
|
+
const page = allPages[i];
|
|
1851
|
+
if (page.url().includes(urlSubstring)) {
|
|
1852
|
+
this.page = page;
|
|
1853
|
+
yield page.waitForLoadState("load", {
|
|
1854
|
+
timeout: MAX_LOAD_TIMEOUT_MS
|
|
1855
|
+
});
|
|
1856
|
+
yield this.pageSetup();
|
|
1857
|
+
this.cdpClient = yield this.context.newCDPSession(page);
|
|
1858
|
+
yield initCDPSession(this.cdpClient);
|
|
1859
|
+
this.logger.info(`Switching to tab ${i} with url ${page.url()}`);
|
|
1860
|
+
return;
|
|
1861
|
+
}
|
|
1764
1862
|
}
|
|
1765
|
-
|
|
1766
|
-
|
|
1863
|
+
throw new Error(`Could not find page with url containing ${urlSubstring}`);
|
|
1864
|
+
});
|
|
1767
1865
|
}
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1866
|
+
setCookie(cookie) {
|
|
1867
|
+
return __async(this, null, function* () {
|
|
1868
|
+
const cookieSettings = parseCookieString(cookie);
|
|
1869
|
+
yield this.context.addCookies([cookieSettings]);
|
|
1870
|
+
});
|
|
1771
1871
|
}
|
|
1772
1872
|
};
|
|
1873
|
+
_ChromeBrowser.USER_AGENT = devices["Desktop Chrome"].userAgent;
|
|
1874
|
+
var ChromeBrowser = _ChromeBrowser;
|
|
1773
1875
|
|
|
1774
1876
|
// ../../packages/web-agent/src/configs/controller.ts
|
|
1775
1877
|
var A11Y_CONTROLLER_CONFIG = {
|
|
@@ -1785,18 +1887,6 @@ import dedent2 from "dedent";
|
|
|
1785
1887
|
import diffLines from "diff-lines";
|
|
1786
1888
|
var MAX_HISTORY_CHAR_LENGTH = 1e4;
|
|
1787
1889
|
var AgentController = class {
|
|
1788
|
-
// Instance of browser to interact with
|
|
1789
|
-
browser;
|
|
1790
|
-
// Stack of queued-up instructions
|
|
1791
|
-
pendingInstructions;
|
|
1792
|
-
// manager for all AI generation
|
|
1793
|
-
generator;
|
|
1794
|
-
// Stack of commands previously executed.
|
|
1795
|
-
// Top of stack can be a pending command that hasn't been executed yet.
|
|
1796
|
-
// Should not contain intermediate successes due to granular commands.
|
|
1797
|
-
commandHistory;
|
|
1798
|
-
config;
|
|
1799
|
-
logger;
|
|
1800
1890
|
constructor({ browser, config, generator, logger }) {
|
|
1801
1891
|
this.browser = browser;
|
|
1802
1892
|
this.generator = generator;
|
|
@@ -1831,16 +1921,20 @@ var AgentController = class {
|
|
|
1831
1921
|
/**
|
|
1832
1922
|
* Reset controller and browser state.
|
|
1833
1923
|
*/
|
|
1834
|
-
|
|
1835
|
-
this
|
|
1836
|
-
|
|
1924
|
+
resetState() {
|
|
1925
|
+
return __async(this, null, function* () {
|
|
1926
|
+
this.resetHistory();
|
|
1927
|
+
yield this.browser.navigate(this.browser.baseURL);
|
|
1928
|
+
});
|
|
1837
1929
|
}
|
|
1838
1930
|
/**
|
|
1839
1931
|
* Get the browser state as a string
|
|
1840
1932
|
*/
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1933
|
+
getBrowserState() {
|
|
1934
|
+
return __async(this, null, function* () {
|
|
1935
|
+
const a11yTree = yield this.browser.getA11yTree();
|
|
1936
|
+
return a11yTree.serialize();
|
|
1937
|
+
});
|
|
1844
1938
|
}
|
|
1845
1939
|
getSerializedHistory(url, currentBrowserState) {
|
|
1846
1940
|
let history;
|
|
@@ -1851,99 +1945,105 @@ var AgentController = class {
|
|
|
1851
1945
|
}
|
|
1852
1946
|
return history;
|
|
1853
1947
|
}
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1948
|
+
splitUserGoal(type, goal, disableCache) {
|
|
1949
|
+
return __async(this, null, function* () {
|
|
1950
|
+
if (type === "AI_ACTION" /* AI_ACTION */ && goal.match(/[,!;.]|(?:and)|(?:then)/) && this.config.useGoalSplitter) {
|
|
1951
|
+
const granularInstructions = yield this.generator.getGranularGoals(
|
|
1952
|
+
{ goal, url: this.browser.url },
|
|
1953
|
+
disableCache
|
|
1954
|
+
);
|
|
1955
|
+
this.pendingInstructions = granularInstructions.reverse();
|
|
1956
|
+
} else {
|
|
1957
|
+
this.pendingInstructions = [goal];
|
|
1958
|
+
}
|
|
1959
|
+
});
|
|
1864
1960
|
}
|
|
1865
1961
|
/**
|
|
1866
1962
|
* Given previously executed commands, generate command for the current prompt.
|
|
1867
1963
|
* Should only be used for AI action.
|
|
1868
1964
|
*/
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
{
|
|
1880
|
-
duration: Date.now() - getBrowserStateStart,
|
|
1881
|
-
url
|
|
1882
|
-
},
|
|
1883
|
-
"Got browser state"
|
|
1884
|
-
);
|
|
1885
|
-
const numPrevious = this.commandHistory.length;
|
|
1886
|
-
this.commandHistory.push({
|
|
1887
|
-
state: "PENDING",
|
|
1888
|
-
browserStateBeforeCommand: browserState,
|
|
1889
|
-
urlBeforeCommand: url,
|
|
1890
|
-
type
|
|
1891
|
-
});
|
|
1892
|
-
const history = this.getSerializedHistory(url, browserState);
|
|
1893
|
-
const getCommandProposalStart = Date.now();
|
|
1894
|
-
const proposedCommand = await this.generator.getProposedCommand(
|
|
1895
|
-
{
|
|
1896
|
-
url,
|
|
1897
|
-
numPrevious,
|
|
1898
|
-
browserState,
|
|
1899
|
-
history,
|
|
1900
|
-
goal: currInstruction,
|
|
1901
|
-
lastCommand: this.lastExecutedCommand
|
|
1902
|
-
},
|
|
1903
|
-
disableCache
|
|
1904
|
-
);
|
|
1905
|
-
this.logger.info(
|
|
1906
|
-
{ duration: Date.now() - getCommandProposalStart },
|
|
1907
|
-
"Got proposed command"
|
|
1908
|
-
);
|
|
1909
|
-
if (proposedCommand.type === "SUCCESS" /* SUCCESS */) {
|
|
1910
|
-
const finishedInstruction = this.pendingInstructions.pop();
|
|
1965
|
+
promptToCommand(type, goal, disableCache) {
|
|
1966
|
+
return __async(this, null, function* () {
|
|
1967
|
+
if (this.pendingInstructions.length === 0) {
|
|
1968
|
+
yield this.splitUserGoal(type, goal, disableCache);
|
|
1969
|
+
}
|
|
1970
|
+
const currInstruction = this.pendingInstructions[this.pendingInstructions.length - 1];
|
|
1971
|
+
this.logger.info({ goal: currInstruction }, "Starting prompt translation");
|
|
1972
|
+
const getBrowserStateStart = Date.now();
|
|
1973
|
+
const url = this.browser.url;
|
|
1974
|
+
const browserState = yield this.getBrowserState();
|
|
1911
1975
|
this.logger.info(
|
|
1912
1976
|
{
|
|
1913
|
-
|
|
1914
|
-
|
|
1977
|
+
duration: Date.now() - getBrowserStateStart,
|
|
1978
|
+
url
|
|
1915
1979
|
},
|
|
1916
|
-
"
|
|
1980
|
+
"Got browser state"
|
|
1917
1981
|
);
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1982
|
+
const numPrevious = this.commandHistory.length;
|
|
1983
|
+
this.commandHistory.push({
|
|
1984
|
+
state: "PENDING",
|
|
1985
|
+
browserStateBeforeCommand: browserState,
|
|
1986
|
+
urlBeforeCommand: url,
|
|
1987
|
+
type
|
|
1988
|
+
});
|
|
1989
|
+
const history = this.getSerializedHistory(url, browserState);
|
|
1990
|
+
const getCommandProposalStart = Date.now();
|
|
1991
|
+
const proposedCommand = yield this.generator.getProposedCommand(
|
|
1927
1992
|
{
|
|
1928
|
-
|
|
1993
|
+
url,
|
|
1994
|
+
numPrevious,
|
|
1995
|
+
browserState,
|
|
1996
|
+
history,
|
|
1997
|
+
goal: currInstruction,
|
|
1998
|
+
lastCommand: this.lastExecutedCommand
|
|
1929
1999
|
},
|
|
1930
|
-
|
|
2000
|
+
disableCache
|
|
1931
2001
|
);
|
|
1932
|
-
this.
|
|
1933
|
-
|
|
1934
|
-
|
|
2002
|
+
this.logger.info(
|
|
2003
|
+
{ duration: Date.now() - getCommandProposalStart },
|
|
2004
|
+
"Got proposed command"
|
|
2005
|
+
);
|
|
2006
|
+
if (proposedCommand.type === "SUCCESS" /* SUCCESS */) {
|
|
2007
|
+
const finishedInstruction = this.pendingInstructions.pop();
|
|
2008
|
+
this.logger.info(
|
|
2009
|
+
{
|
|
2010
|
+
finishedInstruction,
|
|
2011
|
+
remainingInstructions: this.pendingInstructions
|
|
2012
|
+
},
|
|
2013
|
+
"Removing pending instruction due to SUCCESS"
|
|
2014
|
+
);
|
|
2015
|
+
if (this.pendingInstructions.length !== 0) {
|
|
2016
|
+
this.commandHistory.pop();
|
|
2017
|
+
return this.promptToCommand(type, "", disableCache);
|
|
2018
|
+
}
|
|
2019
|
+
} else if (
|
|
2020
|
+
// on failure, we don't continue to execute
|
|
2021
|
+
proposedCommand.type === "FAILURE"
|
|
2022
|
+
) {
|
|
2023
|
+
this.logger.info(
|
|
2024
|
+
{
|
|
2025
|
+
remainingInstructions: this.pendingInstructions
|
|
2026
|
+
},
|
|
2027
|
+
"Removing pending instructions due to FAILURE"
|
|
2028
|
+
);
|
|
2029
|
+
this.pendingInstructions = [];
|
|
2030
|
+
}
|
|
2031
|
+
return proposedCommand;
|
|
2032
|
+
});
|
|
1935
2033
|
}
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
if (locator.id < 0) {
|
|
1942
|
-
throw new Error(
|
|
1943
|
-
`Unable to locate element with description: ${description}`
|
|
2034
|
+
locateElement(description, disableCache) {
|
|
2035
|
+
return __async(this, null, function* () {
|
|
2036
|
+
const locator = yield this.generator.getElementLocation(
|
|
2037
|
+
{ browserState: yield this.getBrowserState(), goal: description },
|
|
2038
|
+
disableCache
|
|
1944
2039
|
);
|
|
1945
|
-
|
|
1946
|
-
|
|
2040
|
+
if (locator.id < 0) {
|
|
2041
|
+
throw new Error(
|
|
2042
|
+
`Unable to locate element with description: ${description}`
|
|
2043
|
+
);
|
|
2044
|
+
}
|
|
2045
|
+
return locator;
|
|
2046
|
+
});
|
|
1947
2047
|
}
|
|
1948
2048
|
/**
|
|
1949
2049
|
* Construct a detailed history that can be passed to the LLM.
|
|
@@ -2001,104 +2101,108 @@ var AgentController = class {
|
|
|
2001
2101
|
* @param [stateless=false] Execute this command in a stateless fashion, without modifying any controller state such as
|
|
2002
2102
|
* pending instructions. Useful when executing cached instructions.
|
|
2003
2103
|
*/
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
if (!
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2104
|
+
executeCommand(command, disableCache, stateless = false) {
|
|
2105
|
+
return __async(this, null, function* () {
|
|
2106
|
+
const pendingHistory = this.commandHistory[this.commandHistory.length - 1];
|
|
2107
|
+
if (!stateless) {
|
|
2108
|
+
if (!pendingHistory || pendingHistory.state !== "PENDING") {
|
|
2109
|
+
throw new Error(
|
|
2110
|
+
"Executing command but there is no pending entry in the history"
|
|
2111
|
+
);
|
|
2112
|
+
}
|
|
2113
|
+
} else {
|
|
2114
|
+
yield this.browser.getA11yTree();
|
|
2011
2115
|
}
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2116
|
+
let result;
|
|
2117
|
+
try {
|
|
2118
|
+
const executionStart = Date.now();
|
|
2119
|
+
result = yield this.executePresetStep(
|
|
2120
|
+
command,
|
|
2121
|
+
disableCache
|
|
2122
|
+
);
|
|
2123
|
+
this.logger.info(
|
|
2124
|
+
{ result, duration: Date.now() - executionStart },
|
|
2125
|
+
"Got execution result"
|
|
2126
|
+
);
|
|
2127
|
+
} catch (e) {
|
|
2128
|
+
if (e instanceof Error) {
|
|
2129
|
+
throw new BrowserExecutionError(`Failed to execute command: ${e}`, {
|
|
2130
|
+
cause: e
|
|
2131
|
+
});
|
|
2132
|
+
}
|
|
2133
|
+
throw new BrowserExecutionError(
|
|
2134
|
+
`Unexpected throw from executing command`,
|
|
2135
|
+
{
|
|
2136
|
+
cause: new Error(`${e}`)
|
|
2137
|
+
}
|
|
2138
|
+
);
|
|
2031
2139
|
}
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
{
|
|
2035
|
-
|
|
2140
|
+
if (result.succeedImmediately && !stateless) {
|
|
2141
|
+
this.pendingInstructions.pop();
|
|
2142
|
+
if (this.pendingInstructions.length > 0) {
|
|
2143
|
+
result.succeedImmediately = false;
|
|
2036
2144
|
}
|
|
2037
|
-
);
|
|
2038
|
-
}
|
|
2039
|
-
if (result.succeedImmediately && !stateless) {
|
|
2040
|
-
this.pendingInstructions.pop();
|
|
2041
|
-
if (this.pendingInstructions.length > 0) {
|
|
2042
|
-
result.succeedImmediately = false;
|
|
2043
2145
|
}
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2146
|
+
if (result.elementInteracted && "target" in command && !command.target.elementDescriptor) {
|
|
2147
|
+
command.target.elementDescriptor = result.elementInteracted.trim();
|
|
2148
|
+
}
|
|
2149
|
+
if (!stateless) {
|
|
2150
|
+
pendingHistory.generatedStep = command;
|
|
2151
|
+
pendingHistory.serializedCommand = serializeCommand(command);
|
|
2152
|
+
pendingHistory.state = "DONE";
|
|
2153
|
+
}
|
|
2154
|
+
return result;
|
|
2155
|
+
});
|
|
2054
2156
|
}
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
if (assertionEval.relevantElements) {
|
|
2088
|
-
void Promise.all(
|
|
2089
|
-
assertionEval.relevantElements.map(
|
|
2090
|
-
(id) => this.browser.highlight({ id })
|
|
2091
|
-
)
|
|
2157
|
+
executeAssertion(urlBeforeCommand, command) {
|
|
2158
|
+
return __async(this, null, function* () {
|
|
2159
|
+
let params;
|
|
2160
|
+
if (command.useVision) {
|
|
2161
|
+
params = {
|
|
2162
|
+
goal: command.assertion,
|
|
2163
|
+
url: urlBeforeCommand,
|
|
2164
|
+
// used for vision only
|
|
2165
|
+
screenshot: yield this.browser.screenshot(),
|
|
2166
|
+
// unused for visual assertion
|
|
2167
|
+
browserState: "",
|
|
2168
|
+
history: "",
|
|
2169
|
+
numPrevious: -1,
|
|
2170
|
+
lastCommand: null
|
|
2171
|
+
};
|
|
2172
|
+
} else {
|
|
2173
|
+
const browserState = yield this.getBrowserState();
|
|
2174
|
+
const history = this.getSerializedHistory(urlBeforeCommand, browserState);
|
|
2175
|
+
params = {
|
|
2176
|
+
goal: command.assertion,
|
|
2177
|
+
url: urlBeforeCommand,
|
|
2178
|
+
// used for text only
|
|
2179
|
+
browserState,
|
|
2180
|
+
history,
|
|
2181
|
+
lastCommand: this.lastExecutedCommand,
|
|
2182
|
+
numPrevious: this.commandHistory.length
|
|
2183
|
+
};
|
|
2184
|
+
}
|
|
2185
|
+
const assertionEval = yield this.generator.getAssertionResult(
|
|
2186
|
+
params,
|
|
2187
|
+
command.useVision,
|
|
2188
|
+
command.disableCache
|
|
2092
2189
|
);
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2190
|
+
if (assertionEval.relevantElements) {
|
|
2191
|
+
void Promise.all(
|
|
2192
|
+
assertionEval.relevantElements.map(
|
|
2193
|
+
(id) => this.browser.highlight({ id })
|
|
2194
|
+
)
|
|
2195
|
+
);
|
|
2196
|
+
}
|
|
2197
|
+
if (!assertionEval.result) {
|
|
2198
|
+
throw new Error(assertionEval.thoughts);
|
|
2199
|
+
}
|
|
2200
|
+
return {
|
|
2201
|
+
succeedImmediately: false,
|
|
2202
|
+
thoughts: assertionEval.thoughts,
|
|
2203
|
+
urlAfterCommand: urlBeforeCommand
|
|
2204
|
+
};
|
|
2205
|
+
});
|
|
2102
2206
|
}
|
|
2103
2207
|
/**
|
|
2104
2208
|
* Executes a preset command.
|
|
@@ -2106,157 +2210,159 @@ var AgentController = class {
|
|
|
2106
2210
|
* For assertions, an AssertionResult with thoughts is returned.
|
|
2107
2211
|
* Throws on failure.
|
|
2108
2212
|
*/
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2213
|
+
executePresetStep(command, disableCache) {
|
|
2214
|
+
return __async(this, null, function* () {
|
|
2215
|
+
var _a, _b, _c;
|
|
2216
|
+
const urlBeforeCommand = this.browser.url;
|
|
2217
|
+
switch (command.type) {
|
|
2218
|
+
case "SUCCESS" /* SUCCESS */:
|
|
2219
|
+
if ((_a = command.condition) == null ? void 0 : _a.assertion.trim()) {
|
|
2220
|
+
return this.executeAssertion(urlBeforeCommand, command.condition);
|
|
2221
|
+
}
|
|
2222
|
+
return {
|
|
2223
|
+
succeedImmediately: false,
|
|
2224
|
+
urlAfterCommand: this.browser.url
|
|
2225
|
+
};
|
|
2226
|
+
case "AI_ASSERTION" /* AI_ASSERTION */: {
|
|
2227
|
+
return this.executeAssertion(urlBeforeCommand, command);
|
|
2116
2228
|
}
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2229
|
+
case "NAVIGATE" /* NAVIGATE */:
|
|
2230
|
+
yield this.browser.navigate(command.url);
|
|
2231
|
+
break;
|
|
2232
|
+
case "GO_BACK" /* GO_BACK */:
|
|
2233
|
+
yield this.browser.goBack();
|
|
2234
|
+
break;
|
|
2235
|
+
case "GO_FORWARD" /* GO_FORWARD */:
|
|
2236
|
+
yield this.browser.goForward();
|
|
2237
|
+
break;
|
|
2238
|
+
case "SCROLL_DOWN" /* SCROLL_DOWN */:
|
|
2239
|
+
yield this.browser.scrollDown();
|
|
2240
|
+
break;
|
|
2241
|
+
case "SCROLL_UP" /* SCROLL_UP */:
|
|
2242
|
+
yield this.browser.scrollUp();
|
|
2243
|
+
break;
|
|
2244
|
+
case "WAIT" /* WAIT */:
|
|
2245
|
+
yield this.browser.wait(command.delay * 1e3);
|
|
2246
|
+
break;
|
|
2247
|
+
case "REFRESH" /* REFRESH */:
|
|
2248
|
+
yield this.browser.refresh();
|
|
2249
|
+
break;
|
|
2250
|
+
case "CLICK" /* CLICK */: {
|
|
2251
|
+
let id;
|
|
2252
|
+
if (command.target.a11yData) {
|
|
2253
|
+
id = (_b = command.target.a11yData) == null ? void 0 : _b.id;
|
|
2254
|
+
} else {
|
|
2255
|
+
const locator = yield this.locateElement(
|
|
2256
|
+
command.target.elementDescriptor,
|
|
2257
|
+
disableCache
|
|
2258
|
+
);
|
|
2259
|
+
id = locator.id;
|
|
2260
|
+
}
|
|
2261
|
+
const elementInteracted = yield this.browser.click(
|
|
2262
|
+
{
|
|
2263
|
+
id
|
|
2264
|
+
},
|
|
2265
|
+
{
|
|
2266
|
+
doubleClick: command.doubleClick,
|
|
2267
|
+
rightClick: command.rightClick
|
|
2268
|
+
}
|
|
2153
2269
|
);
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
rightClick: command.rightClick
|
|
2270
|
+
const result2 = {
|
|
2271
|
+
urlAfterCommand: this.browser.url,
|
|
2272
|
+
succeedImmediately: false,
|
|
2273
|
+
elementInteracted
|
|
2274
|
+
};
|
|
2275
|
+
if (urlChanged(urlBeforeCommand, result2.urlAfterCommand)) {
|
|
2276
|
+
result2.succeedImmediately = true;
|
|
2277
|
+
result2.succeedImmediatelyReason = "URL changed";
|
|
2163
2278
|
}
|
|
2164
|
-
|
|
2165
|
-
const result2 = {
|
|
2166
|
-
urlAfterCommand: this.browser.url,
|
|
2167
|
-
succeedImmediately: false,
|
|
2168
|
-
elementInteracted
|
|
2169
|
-
};
|
|
2170
|
-
if (urlChanged(urlBeforeCommand, result2.urlAfterCommand)) {
|
|
2171
|
-
result2.succeedImmediately = true;
|
|
2172
|
-
result2.succeedImmediatelyReason = "URL changed";
|
|
2279
|
+
return result2;
|
|
2173
2280
|
}
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2281
|
+
case "SELECT_OPTION" /* SELECT_OPTION */: {
|
|
2282
|
+
let id;
|
|
2283
|
+
if (command.target.a11yData) {
|
|
2284
|
+
id = (_c = command.target.a11yData) == null ? void 0 : _c.id;
|
|
2285
|
+
} else {
|
|
2286
|
+
const locator = yield this.locateElement(
|
|
2287
|
+
command.target.elementDescriptor,
|
|
2288
|
+
disableCache
|
|
2289
|
+
);
|
|
2290
|
+
id = locator.id;
|
|
2291
|
+
}
|
|
2292
|
+
const elementInteracted = yield this.browser.selectOption(
|
|
2293
|
+
{
|
|
2294
|
+
id
|
|
2295
|
+
},
|
|
2296
|
+
command.option
|
|
2184
2297
|
);
|
|
2185
|
-
|
|
2298
|
+
return {
|
|
2299
|
+
succeedImmediately: false,
|
|
2300
|
+
urlAfterCommand: this.browser.url,
|
|
2301
|
+
elementInteracted
|
|
2302
|
+
};
|
|
2186
2303
|
}
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
command.
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
} else if (target.elementDescriptor.length > 0) {
|
|
2213
|
-
const locator = await this.locateElement(
|
|
2214
|
-
command.target.elementDescriptor,
|
|
2215
|
-
disableCache
|
|
2216
|
-
);
|
|
2217
|
-
elementInteracted = await this.browser.click({
|
|
2218
|
-
id: locator.id
|
|
2304
|
+
case "TAB" /* TAB */:
|
|
2305
|
+
yield this.browser.switchToPage(command.url);
|
|
2306
|
+
break;
|
|
2307
|
+
case "COOKIE" /* COOKIE */:
|
|
2308
|
+
yield this.browser.setCookie(command.value);
|
|
2309
|
+
break;
|
|
2310
|
+
case "TYPE" /* TYPE */: {
|
|
2311
|
+
let elementInteracted;
|
|
2312
|
+
const target = command.target;
|
|
2313
|
+
if (target.a11yData) {
|
|
2314
|
+
elementInteracted = yield this.browser.click({
|
|
2315
|
+
id: target.a11yData.id
|
|
2316
|
+
});
|
|
2317
|
+
} else if (target.elementDescriptor.length > 0) {
|
|
2318
|
+
const locator = yield this.locateElement(
|
|
2319
|
+
command.target.elementDescriptor,
|
|
2320
|
+
disableCache
|
|
2321
|
+
);
|
|
2322
|
+
elementInteracted = yield this.browser.click({
|
|
2323
|
+
id: locator.id
|
|
2324
|
+
});
|
|
2325
|
+
}
|
|
2326
|
+
yield this.browser.type(command.value, {
|
|
2327
|
+
clearContent: command.clearContent,
|
|
2328
|
+
pressKeysSequentially: command.pressKeysSequentially
|
|
2219
2329
|
});
|
|
2330
|
+
if (command.pressEnter) {
|
|
2331
|
+
yield this.browser.press("Enter");
|
|
2332
|
+
}
|
|
2333
|
+
const result2 = {
|
|
2334
|
+
urlAfterCommand: this.browser.url,
|
|
2335
|
+
succeedImmediately: false,
|
|
2336
|
+
elementInteracted
|
|
2337
|
+
};
|
|
2338
|
+
if (urlChanged(urlBeforeCommand, result2.urlAfterCommand)) {
|
|
2339
|
+
result2.succeedImmediately = true;
|
|
2340
|
+
result2.succeedImmediatelyReason = "URL changed";
|
|
2341
|
+
}
|
|
2342
|
+
return result2;
|
|
2220
2343
|
}
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
return result2;
|
|
2344
|
+
case "PRESS" /* PRESS */:
|
|
2345
|
+
yield this.browser.press(command.value);
|
|
2346
|
+
const result = {
|
|
2347
|
+
urlAfterCommand: this.browser.url,
|
|
2348
|
+
succeedImmediately: false
|
|
2349
|
+
};
|
|
2350
|
+
if (urlChanged(urlBeforeCommand, result.urlAfterCommand)) {
|
|
2351
|
+
result.succeedImmediately = true;
|
|
2352
|
+
result.succeedImmediatelyReason = "URL changed";
|
|
2353
|
+
}
|
|
2354
|
+
return result;
|
|
2355
|
+
default:
|
|
2356
|
+
const assertUnreachable = (_x) => {
|
|
2357
|
+
throw "If Typescript complains about the line below, you missed a case or break in the switch above";
|
|
2358
|
+
};
|
|
2359
|
+
return assertUnreachable(command);
|
|
2238
2360
|
}
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
};
|
|
2245
|
-
if (urlChanged(urlBeforeCommand, result.urlAfterCommand)) {
|
|
2246
|
-
result.succeedImmediately = true;
|
|
2247
|
-
result.succeedImmediatelyReason = "URL changed";
|
|
2248
|
-
}
|
|
2249
|
-
return result;
|
|
2250
|
-
default:
|
|
2251
|
-
const assertUnreachable = (_x) => {
|
|
2252
|
-
throw "If Typescript complains about the line below, you missed a case or break in the switch above";
|
|
2253
|
-
};
|
|
2254
|
-
return assertUnreachable(command);
|
|
2255
|
-
}
|
|
2256
|
-
return {
|
|
2257
|
-
succeedImmediately: false,
|
|
2258
|
-
urlAfterCommand: this.browser.url
|
|
2259
|
-
};
|
|
2361
|
+
return {
|
|
2362
|
+
succeedImmediately: false,
|
|
2363
|
+
urlAfterCommand: this.browser.url
|
|
2364
|
+
};
|
|
2365
|
+
});
|
|
2260
2366
|
}
|
|
2261
2367
|
};
|
|
2262
2368
|
|
|
@@ -2265,96 +2371,104 @@ import fetchRetry from "fetch-retry";
|
|
|
2265
2371
|
var fetch2 = fetchRetry(global.fetch);
|
|
2266
2372
|
var API_VERSION = "v1";
|
|
2267
2373
|
var APIGenerator = class {
|
|
2268
|
-
baseURL;
|
|
2269
|
-
apiKey;
|
|
2270
2374
|
constructor(params) {
|
|
2271
2375
|
this.baseURL = params.baseURL;
|
|
2272
2376
|
this.apiKey = params.apiKey;
|
|
2273
2377
|
}
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2378
|
+
getElementLocation(context, disableCache) {
|
|
2379
|
+
return __async(this, null, function* () {
|
|
2380
|
+
const result = yield this.sendRequest(
|
|
2381
|
+
`/${API_VERSION}/web-agent/locate-element`,
|
|
2382
|
+
{
|
|
2383
|
+
browserState: context.browserState,
|
|
2384
|
+
goal: context.goal,
|
|
2385
|
+
disableCache
|
|
2386
|
+
}
|
|
2387
|
+
);
|
|
2388
|
+
return LocateResponseSchema.parse(result);
|
|
2389
|
+
});
|
|
2284
2390
|
}
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2391
|
+
getAssertionResult(context, useVision, disableCache) {
|
|
2392
|
+
return __async(this, null, function* () {
|
|
2393
|
+
var _a;
|
|
2394
|
+
if (useVision) {
|
|
2395
|
+
const result2 = yield this.sendRequest(
|
|
2396
|
+
`/${API_VERSION}/web-agent/assertion`,
|
|
2397
|
+
{
|
|
2398
|
+
url: context.url,
|
|
2399
|
+
goal: context.goal,
|
|
2400
|
+
screenshot: (_a = context.screenshot) == null ? void 0 : _a.toString("base64"),
|
|
2401
|
+
disableCache,
|
|
2402
|
+
vision: true
|
|
2403
|
+
}
|
|
2404
|
+
);
|
|
2405
|
+
return GetAssertionResponseSchema.parse(result2);
|
|
2406
|
+
}
|
|
2407
|
+
const result = yield this.sendRequest(
|
|
2289
2408
|
`/${API_VERSION}/web-agent/assertion`,
|
|
2290
2409
|
{
|
|
2291
2410
|
url: context.url,
|
|
2411
|
+
browserState: context.browserState,
|
|
2292
2412
|
goal: context.goal,
|
|
2293
|
-
|
|
2413
|
+
history: context.history,
|
|
2414
|
+
numPrevious: context.numPrevious,
|
|
2415
|
+
lastCommand: context.lastCommand,
|
|
2294
2416
|
disableCache,
|
|
2295
|
-
vision:
|
|
2417
|
+
vision: false
|
|
2296
2418
|
}
|
|
2297
2419
|
);
|
|
2298
|
-
return GetAssertionResponseSchema.parse(
|
|
2299
|
-
}
|
|
2300
|
-
const result = await this.sendRequest(
|
|
2301
|
-
`/${API_VERSION}/web-agent/assertion`,
|
|
2302
|
-
{
|
|
2303
|
-
url: context.url,
|
|
2304
|
-
browserState: context.browserState,
|
|
2305
|
-
goal: context.goal,
|
|
2306
|
-
history: context.history,
|
|
2307
|
-
numPrevious: context.numPrevious,
|
|
2308
|
-
lastCommand: context.lastCommand,
|
|
2309
|
-
disableCache,
|
|
2310
|
-
vision: false
|
|
2311
|
-
}
|
|
2312
|
-
);
|
|
2313
|
-
return GetAssertionResponseSchema.parse(result);
|
|
2314
|
-
}
|
|
2315
|
-
async getProposedCommand(context, disableCache) {
|
|
2316
|
-
const result = await this.sendRequest(
|
|
2317
|
-
`/${API_VERSION}/web-agent/next-command`,
|
|
2318
|
-
{
|
|
2319
|
-
url: context.url,
|
|
2320
|
-
browserState: context.browserState,
|
|
2321
|
-
goal: context.goal,
|
|
2322
|
-
history: context.history,
|
|
2323
|
-
numPrevious: context.numPrevious,
|
|
2324
|
-
lastCommand: context.lastCommand,
|
|
2325
|
-
disableCache
|
|
2326
|
-
}
|
|
2327
|
-
);
|
|
2328
|
-
return GetNextCommandResponseSchema.parse(result);
|
|
2329
|
-
}
|
|
2330
|
-
async getGranularGoals(context, disableCache) {
|
|
2331
|
-
const result = await this.sendRequest(
|
|
2332
|
-
`/${API_VERSION}/web-agent/split-goal`,
|
|
2333
|
-
{
|
|
2334
|
-
url: context.url,
|
|
2335
|
-
goal: context.goal,
|
|
2336
|
-
disableCache
|
|
2337
|
-
}
|
|
2338
|
-
);
|
|
2339
|
-
return SplitGoalResponseSchema.parse(result);
|
|
2340
|
-
}
|
|
2341
|
-
async sendRequest(path, body) {
|
|
2342
|
-
const response = await fetch2(`${this.baseURL}${path}`, {
|
|
2343
|
-
retries: 3,
|
|
2344
|
-
retryDelay: 1e3,
|
|
2345
|
-
method: "POST",
|
|
2346
|
-
body: JSON.stringify(body),
|
|
2347
|
-
headers: {
|
|
2348
|
-
"Content-Type": "application/json",
|
|
2349
|
-
Authorization: `Bearer ${this.apiKey}`
|
|
2350
|
-
}
|
|
2420
|
+
return GetAssertionResponseSchema.parse(result);
|
|
2351
2421
|
});
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2422
|
+
}
|
|
2423
|
+
getProposedCommand(context, disableCache) {
|
|
2424
|
+
return __async(this, null, function* () {
|
|
2425
|
+
const result = yield this.sendRequest(
|
|
2426
|
+
`/${API_VERSION}/web-agent/next-command`,
|
|
2427
|
+
{
|
|
2428
|
+
url: context.url,
|
|
2429
|
+
browserState: context.browserState,
|
|
2430
|
+
goal: context.goal,
|
|
2431
|
+
history: context.history,
|
|
2432
|
+
numPrevious: context.numPrevious,
|
|
2433
|
+
lastCommand: context.lastCommand,
|
|
2434
|
+
disableCache
|
|
2435
|
+
}
|
|
2355
2436
|
);
|
|
2356
|
-
|
|
2357
|
-
|
|
2437
|
+
return GetNextCommandResponseSchema.parse(result);
|
|
2438
|
+
});
|
|
2439
|
+
}
|
|
2440
|
+
getGranularGoals(context, disableCache) {
|
|
2441
|
+
return __async(this, null, function* () {
|
|
2442
|
+
const result = yield this.sendRequest(
|
|
2443
|
+
`/${API_VERSION}/web-agent/split-goal`,
|
|
2444
|
+
{
|
|
2445
|
+
url: context.url,
|
|
2446
|
+
goal: context.goal,
|
|
2447
|
+
disableCache
|
|
2448
|
+
}
|
|
2449
|
+
);
|
|
2450
|
+
return SplitGoalResponseSchema.parse(result);
|
|
2451
|
+
});
|
|
2452
|
+
}
|
|
2453
|
+
sendRequest(path, body) {
|
|
2454
|
+
return __async(this, null, function* () {
|
|
2455
|
+
const response = yield fetch2(`${this.baseURL}${path}`, {
|
|
2456
|
+
retries: 3,
|
|
2457
|
+
retryDelay: 1e3,
|
|
2458
|
+
method: "POST",
|
|
2459
|
+
body: JSON.stringify(body),
|
|
2460
|
+
headers: {
|
|
2461
|
+
"Content-Type": "application/json",
|
|
2462
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
2463
|
+
}
|
|
2464
|
+
});
|
|
2465
|
+
if (!response.ok) {
|
|
2466
|
+
throw new Error(
|
|
2467
|
+
`Request to ${path} failed with status ${response.status}: ${yield response.text()}`
|
|
2468
|
+
);
|
|
2469
|
+
}
|
|
2470
|
+
return response.json();
|
|
2471
|
+
});
|
|
2358
2472
|
}
|
|
2359
2473
|
};
|
|
2360
2474
|
|
|
@@ -2364,62 +2478,72 @@ var version = "1.0.0";
|
|
|
2364
2478
|
// src/api-client.ts
|
|
2365
2479
|
var API_VERSION2 = "v1";
|
|
2366
2480
|
var APIClient = class {
|
|
2367
|
-
baseURL;
|
|
2368
|
-
apiKey;
|
|
2369
2481
|
constructor(params) {
|
|
2370
2482
|
this.baseURL = params.baseURL;
|
|
2371
2483
|
this.apiKey = params.apiKey;
|
|
2372
2484
|
}
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2485
|
+
getRun(runId) {
|
|
2486
|
+
return __async(this, null, function* () {
|
|
2487
|
+
const result = yield this.sendRequest(`/${API_VERSION2}/runs/${runId}`, {
|
|
2488
|
+
method: "GET"
|
|
2489
|
+
});
|
|
2490
|
+
return GetRunResponseSchema.parse(result);
|
|
2376
2491
|
});
|
|
2377
|
-
return GetRunResponseSchema.parse(result);
|
|
2378
2492
|
}
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2493
|
+
createRun(body) {
|
|
2494
|
+
return __async(this, null, function* () {
|
|
2495
|
+
const result = yield this.sendRequest(`/${API_VERSION2}/runs`, {
|
|
2496
|
+
method: "POST",
|
|
2497
|
+
body
|
|
2498
|
+
});
|
|
2499
|
+
return CreateRunResponseSchema.parse(result);
|
|
2383
2500
|
});
|
|
2384
|
-
return CreateRunResponseSchema.parse(result);
|
|
2385
2501
|
}
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2502
|
+
updateRun(runId, body) {
|
|
2503
|
+
return __async(this, null, function* () {
|
|
2504
|
+
yield this.sendRequest(`/${API_VERSION2}/runs/${runId}`, {
|
|
2505
|
+
method: "PATCH",
|
|
2506
|
+
body
|
|
2507
|
+
});
|
|
2390
2508
|
});
|
|
2391
2509
|
}
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2510
|
+
getTest(testId) {
|
|
2511
|
+
return __async(this, null, function* () {
|
|
2512
|
+
const result = yield this.sendRequest(`/${API_VERSION2}/tests/${testId}`, {
|
|
2513
|
+
method: "GET"
|
|
2514
|
+
});
|
|
2515
|
+
return GetTestResponseSchema.parse(result);
|
|
2395
2516
|
});
|
|
2396
|
-
return GetTestResponseSchema.parse(result);
|
|
2397
2517
|
}
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2518
|
+
uploadScreenshot(body) {
|
|
2519
|
+
return __async(this, null, function* () {
|
|
2520
|
+
const result = yield this.sendRequest(`/${API_VERSION2}/screenshots`, {
|
|
2521
|
+
method: "POST",
|
|
2522
|
+
body
|
|
2523
|
+
});
|
|
2524
|
+
return CreateScreenshotResponseSchema.parse(result);
|
|
2402
2525
|
});
|
|
2403
|
-
return CreateScreenshotResponseSchema.parse(result);
|
|
2404
2526
|
}
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2527
|
+
sendRequest(path, options) {
|
|
2528
|
+
return __async(this, null, function* () {
|
|
2529
|
+
const response = yield fetch(`${this.baseURL}${path}`, {
|
|
2530
|
+
method: options.method,
|
|
2531
|
+
body: options.body ? JSON.stringify(options.body) : void 0,
|
|
2532
|
+
headers: {
|
|
2533
|
+
"Content-Type": "application/json",
|
|
2534
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
2535
|
+
}
|
|
2536
|
+
});
|
|
2537
|
+
if (!response.ok) {
|
|
2538
|
+
throw new Error(
|
|
2539
|
+
`Request to ${path} failed with status ${response.status}: ${yield response.text()}`
|
|
2540
|
+
);
|
|
2541
|
+
}
|
|
2542
|
+
if (response.status === 204) {
|
|
2543
|
+
return response.text();
|
|
2412
2544
|
}
|
|
2545
|
+
return response.json();
|
|
2413
2546
|
});
|
|
2414
|
-
if (!response.ok) {
|
|
2415
|
-
throw new Error(
|
|
2416
|
-
`Request to ${path} failed with status ${response.status}: ${await response.text()}`
|
|
2417
|
-
);
|
|
2418
|
-
}
|
|
2419
|
-
if (response.status === 204) {
|
|
2420
|
-
return response.text();
|
|
2421
|
-
}
|
|
2422
|
-
return response.json();
|
|
2423
2547
|
}
|
|
2424
2548
|
};
|
|
2425
2549
|
|
|
@@ -2427,25 +2551,29 @@ var APIClient = class {
|
|
|
2427
2551
|
var MAX_COMMANDS_PER_STEP = 20;
|
|
2428
2552
|
|
|
2429
2553
|
// ../../packages/execute/src/steps/ai.ts
|
|
2430
|
-
var executeAIStep =
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
}
|
|
2437
|
-
|
|
2438
|
-
|
|
2554
|
+
var executeAIStep = (_a) => __async(void 0, null, function* () {
|
|
2555
|
+
var _b = _a, {
|
|
2556
|
+
controller,
|
|
2557
|
+
step,
|
|
2558
|
+
logger,
|
|
2559
|
+
advanced
|
|
2560
|
+
} = _b, callbacks = __objRest(_b, [
|
|
2561
|
+
"controller",
|
|
2562
|
+
"step",
|
|
2563
|
+
"logger",
|
|
2564
|
+
"advanced"
|
|
2565
|
+
]);
|
|
2566
|
+
var _a2, _b2, _c, _d, _e, _f, _g;
|
|
2567
|
+
(_a2 = callbacks.onStarted) == null ? void 0 : _a2.call(callbacks);
|
|
2439
2568
|
controller.resetHistory();
|
|
2440
|
-
const result = {
|
|
2441
|
-
...step,
|
|
2569
|
+
const result = __spreadProps(__spreadValues({}, step), {
|
|
2442
2570
|
startedAt: /* @__PURE__ */ new Date(),
|
|
2443
2571
|
userAgent: ChromeBrowser.USER_AGENT,
|
|
2444
2572
|
// placeholder values
|
|
2445
2573
|
finishedAt: /* @__PURE__ */ new Date(),
|
|
2446
2574
|
results: [],
|
|
2447
2575
|
status: "SUCCESS" /* SUCCESS */
|
|
2448
|
-
};
|
|
2576
|
+
});
|
|
2449
2577
|
try {
|
|
2450
2578
|
let commandIndex = 0;
|
|
2451
2579
|
let useSavedCommands = step.commands && step.commands.length > 0;
|
|
@@ -2457,8 +2585,8 @@ var executeAIStep = async ({
|
|
|
2457
2585
|
}
|
|
2458
2586
|
let command;
|
|
2459
2587
|
const startedAt = /* @__PURE__ */ new Date();
|
|
2460
|
-
const beforeScreenshotBuffer =
|
|
2461
|
-
const beforeScreenshot =
|
|
2588
|
+
const beforeScreenshotBuffer = yield controller.browser.screenshot();
|
|
2589
|
+
const beforeScreenshot = yield callbacks.onSaveScreenshot(
|
|
2462
2590
|
beforeScreenshotBuffer
|
|
2463
2591
|
);
|
|
2464
2592
|
if (useSavedCommands) {
|
|
@@ -2469,7 +2597,7 @@ var executeAIStep = async ({
|
|
|
2469
2597
|
);
|
|
2470
2598
|
}
|
|
2471
2599
|
} else {
|
|
2472
|
-
command =
|
|
2600
|
+
command = yield controller.promptToCommand(
|
|
2473
2601
|
step.type,
|
|
2474
2602
|
step.text,
|
|
2475
2603
|
advanced.disableAICaching
|
|
@@ -2481,7 +2609,7 @@ var executeAIStep = async ({
|
|
|
2481
2609
|
result.message = command.thoughts;
|
|
2482
2610
|
break;
|
|
2483
2611
|
}
|
|
2484
|
-
(
|
|
2612
|
+
(_b2 = callbacks.onCommandGenerated) == null ? void 0 : _b2.call(callbacks, {
|
|
2485
2613
|
commandIndex,
|
|
2486
2614
|
message: CARD_DISPLAY_NAMES[command.type] || `Unknown command (${command.type})`
|
|
2487
2615
|
});
|
|
@@ -2498,7 +2626,7 @@ var executeAIStep = async ({
|
|
|
2498
2626
|
`Executing command ${commandIndex}: ${serializeCommand(command)}`
|
|
2499
2627
|
);
|
|
2500
2628
|
try {
|
|
2501
|
-
const executionResult =
|
|
2629
|
+
const executionResult = yield controller.executeCommand(
|
|
2502
2630
|
command,
|
|
2503
2631
|
advanced.disableAICaching,
|
|
2504
2632
|
useSavedCommands
|
|
@@ -2509,8 +2637,8 @@ var executeAIStep = async ({
|
|
|
2509
2637
|
message: serializeCommand(command),
|
|
2510
2638
|
command
|
|
2511
2639
|
});
|
|
2512
|
-
const afterScreenshotBuffer =
|
|
2513
|
-
const afterScreenshot =
|
|
2640
|
+
const afterScreenshotBuffer = yield controller.browser.screenshot();
|
|
2641
|
+
const afterScreenshot = yield callbacks.onSaveScreenshot(
|
|
2514
2642
|
afterScreenshotBuffer
|
|
2515
2643
|
);
|
|
2516
2644
|
cmdResult.afterScreenshot = afterScreenshot;
|
|
@@ -2528,7 +2656,7 @@ var executeAIStep = async ({
|
|
|
2528
2656
|
if (command.type === "SUCCESS" /* SUCCESS */) {
|
|
2529
2657
|
result.finishedAt = /* @__PURE__ */ new Date();
|
|
2530
2658
|
result.status = "SUCCESS" /* SUCCESS */;
|
|
2531
|
-
result.message = executionResult.thoughts
|
|
2659
|
+
result.message = (_d = executionResult.thoughts) != null ? _d : "All commands completed.";
|
|
2532
2660
|
break;
|
|
2533
2661
|
}
|
|
2534
2662
|
if (executionResult.succeedImmediately && !useSavedCommands) {
|
|
@@ -2538,15 +2666,14 @@ var executeAIStep = async ({
|
|
|
2538
2666
|
command = {
|
|
2539
2667
|
type: "SUCCESS" /* SUCCESS */
|
|
2540
2668
|
};
|
|
2541
|
-
(
|
|
2669
|
+
(_e = callbacks.onCommandExecuted) == null ? void 0 : _e.call(callbacks, {
|
|
2542
2670
|
commandIndex: commandIndex + 1,
|
|
2543
2671
|
message: serializeCommand(command),
|
|
2544
2672
|
command
|
|
2545
2673
|
});
|
|
2546
|
-
result.results.push({
|
|
2547
|
-
...presetActionResult,
|
|
2674
|
+
result.results.push(__spreadProps(__spreadValues({}, presetActionResult), {
|
|
2548
2675
|
command
|
|
2549
|
-
});
|
|
2676
|
+
}));
|
|
2550
2677
|
break;
|
|
2551
2678
|
}
|
|
2552
2679
|
} catch (err) {
|
|
@@ -2583,54 +2710,57 @@ var executeAIStep = async ({
|
|
|
2583
2710
|
result.status = "FAILED" /* FAILED */;
|
|
2584
2711
|
}
|
|
2585
2712
|
if (result.status === "SUCCESS" /* SUCCESS */) {
|
|
2586
|
-
(
|
|
2713
|
+
(_f = callbacks.onSuccess) == null ? void 0 : _f.call(callbacks, {
|
|
2587
2714
|
message: result.message || "AI step succeeded.",
|
|
2588
2715
|
startedAt: result.startedAt.getTime(),
|
|
2589
2716
|
durationMs: result.finishedAt.getTime() - result.startedAt.getTime()
|
|
2590
2717
|
});
|
|
2591
2718
|
} else {
|
|
2592
|
-
(
|
|
2719
|
+
(_g = callbacks.onFailure) == null ? void 0 : _g.call(callbacks, {
|
|
2593
2720
|
message: result.message || "AI step errored.",
|
|
2594
2721
|
startedAt: result.startedAt.getTime(),
|
|
2595
2722
|
durationMs: result.finishedAt.getTime() - result.startedAt.getTime()
|
|
2596
2723
|
});
|
|
2597
2724
|
}
|
|
2598
2725
|
return result;
|
|
2599
|
-
};
|
|
2726
|
+
});
|
|
2600
2727
|
|
|
2601
2728
|
// ../../packages/execute/src/steps/preset.ts
|
|
2602
|
-
var executePresetStep =
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
}
|
|
2608
|
-
|
|
2609
|
-
|
|
2729
|
+
var executePresetStep = (_a) => __async(void 0, null, function* () {
|
|
2730
|
+
var _b = _a, {
|
|
2731
|
+
controller,
|
|
2732
|
+
step,
|
|
2733
|
+
advanced
|
|
2734
|
+
} = _b, callbacks = __objRest(_b, [
|
|
2735
|
+
"controller",
|
|
2736
|
+
"step",
|
|
2737
|
+
"advanced"
|
|
2738
|
+
]);
|
|
2739
|
+
var _a2, _b2, _c;
|
|
2740
|
+
(_a2 = callbacks.onStarted) == null ? void 0 : _a2.call(callbacks);
|
|
2610
2741
|
const startedAt = /* @__PURE__ */ new Date();
|
|
2611
2742
|
const beforeUrl = controller.browser.url;
|
|
2612
|
-
const beforeScreenshotBuffer =
|
|
2613
|
-
const beforeScreenshot =
|
|
2743
|
+
const beforeScreenshotBuffer = yield controller.browser.screenshot();
|
|
2744
|
+
const beforeScreenshot = yield callbacks.onSaveScreenshot(
|
|
2614
2745
|
beforeScreenshotBuffer
|
|
2615
2746
|
);
|
|
2616
2747
|
try {
|
|
2617
|
-
const execResult =
|
|
2748
|
+
const execResult = yield controller.executePresetStep(
|
|
2618
2749
|
step.command,
|
|
2619
2750
|
advanced.disableAICaching
|
|
2620
2751
|
);
|
|
2621
|
-
const afterScreenshotBuffer =
|
|
2622
|
-
const afterScreenshot =
|
|
2752
|
+
const afterScreenshotBuffer = yield controller.browser.screenshot();
|
|
2753
|
+
const afterScreenshot = yield callbacks.onSaveScreenshot(
|
|
2623
2754
|
afterScreenshotBuffer
|
|
2624
2755
|
);
|
|
2625
2756
|
const finishedAt = /* @__PURE__ */ new Date();
|
|
2626
|
-
const result = {
|
|
2627
|
-
...step,
|
|
2757
|
+
const result = __spreadProps(__spreadValues({}, step), {
|
|
2628
2758
|
startedAt,
|
|
2629
2759
|
finishedAt,
|
|
2630
2760
|
// placeholder values
|
|
2631
2761
|
status: "SUCCESS" /* SUCCESS */,
|
|
2632
2762
|
results: []
|
|
2633
|
-
};
|
|
2763
|
+
});
|
|
2634
2764
|
let message = "Successfully executed preset action.";
|
|
2635
2765
|
if (step.command.type === "AI_ASSERTION" /* AI_ASSERTION */) {
|
|
2636
2766
|
message = execResult.thoughts || "Assertion passed.";
|
|
@@ -2648,7 +2778,7 @@ var executePresetStep = async ({
|
|
|
2648
2778
|
result.status = "SUCCESS" /* SUCCESS */;
|
|
2649
2779
|
result.results = [cmdMetadata];
|
|
2650
2780
|
result.message = message;
|
|
2651
|
-
(
|
|
2781
|
+
(_b2 = callbacks.onSuccess) == null ? void 0 : _b2.call(callbacks, {
|
|
2652
2782
|
message,
|
|
2653
2783
|
startedAt: startedAt.getTime(),
|
|
2654
2784
|
durationMs: finishedAt.getTime() - startedAt.getTime()
|
|
@@ -2656,8 +2786,7 @@ var executePresetStep = async ({
|
|
|
2656
2786
|
return result;
|
|
2657
2787
|
} catch (err) {
|
|
2658
2788
|
const finishedAt = /* @__PURE__ */ new Date();
|
|
2659
|
-
const result = {
|
|
2660
|
-
...step,
|
|
2789
|
+
const result = __spreadProps(__spreadValues({}, step), {
|
|
2661
2790
|
startedAt,
|
|
2662
2791
|
finishedAt,
|
|
2663
2792
|
status: "FAILED" /* FAILED */,
|
|
@@ -2675,7 +2804,7 @@ var executePresetStep = async ({
|
|
|
2675
2804
|
message: `${err}`
|
|
2676
2805
|
}
|
|
2677
2806
|
]
|
|
2678
|
-
};
|
|
2807
|
+
});
|
|
2679
2808
|
(_c = callbacks.onFailure) == null ? void 0 : _c.call(callbacks, {
|
|
2680
2809
|
message: `${err}`,
|
|
2681
2810
|
startedAt: startedAt.getTime(),
|
|
@@ -2683,18 +2812,23 @@ var executePresetStep = async ({
|
|
|
2683
2812
|
});
|
|
2684
2813
|
return result;
|
|
2685
2814
|
}
|
|
2686
|
-
};
|
|
2815
|
+
});
|
|
2687
2816
|
|
|
2688
2817
|
// ../../packages/execute/src/steps/module.ts
|
|
2689
|
-
var executeModuleStep =
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
}
|
|
2696
|
-
|
|
2697
|
-
|
|
2818
|
+
var executeModuleStep = (_a) => __async(void 0, null, function* () {
|
|
2819
|
+
var _b = _a, {
|
|
2820
|
+
controller,
|
|
2821
|
+
step,
|
|
2822
|
+
advanced,
|
|
2823
|
+
logger
|
|
2824
|
+
} = _b, callbacks = __objRest(_b, [
|
|
2825
|
+
"controller",
|
|
2826
|
+
"step",
|
|
2827
|
+
"advanced",
|
|
2828
|
+
"logger"
|
|
2829
|
+
]);
|
|
2830
|
+
var _a2, _b2, _c;
|
|
2831
|
+
(_a2 = callbacks.onStarted) == null ? void 0 : _a2.call(callbacks);
|
|
2698
2832
|
const result = {
|
|
2699
2833
|
type: "MODULE" /* MODULE */,
|
|
2700
2834
|
moduleId: step.moduleId,
|
|
@@ -2711,19 +2845,19 @@ var executeModuleStep = async ({
|
|
|
2711
2845
|
let moduleStepResult;
|
|
2712
2846
|
switch (moduleStep.type) {
|
|
2713
2847
|
case "PRESET_ACTION" /* PRESET_ACTION */:
|
|
2714
|
-
moduleStepResult =
|
|
2848
|
+
moduleStepResult = yield executePresetStep({
|
|
2715
2849
|
controller,
|
|
2716
2850
|
step: moduleStep,
|
|
2717
2851
|
advanced,
|
|
2718
2852
|
logger,
|
|
2719
2853
|
onSaveScreenshot: callbacks.onSaveScreenshot,
|
|
2720
2854
|
onStarted() {
|
|
2721
|
-
var
|
|
2722
|
-
(
|
|
2855
|
+
var _a3;
|
|
2856
|
+
(_a3 = callbacks.onStepStarted) == null ? void 0 : _a3.call(callbacks, { index: i });
|
|
2723
2857
|
},
|
|
2724
2858
|
onSuccess({ message, startedAt, durationMs }) {
|
|
2725
|
-
var
|
|
2726
|
-
(
|
|
2859
|
+
var _a3;
|
|
2860
|
+
(_a3 = callbacks.onStepSuccess) == null ? void 0 : _a3.call(callbacks, {
|
|
2727
2861
|
index: i,
|
|
2728
2862
|
message,
|
|
2729
2863
|
startedAt,
|
|
@@ -2731,8 +2865,8 @@ var executeModuleStep = async ({
|
|
|
2731
2865
|
});
|
|
2732
2866
|
},
|
|
2733
2867
|
onFailure({ message, startedAt, durationMs }) {
|
|
2734
|
-
var
|
|
2735
|
-
(
|
|
2868
|
+
var _a3;
|
|
2869
|
+
(_a3 = callbacks.onStepFailure) == null ? void 0 : _a3.call(callbacks, {
|
|
2736
2870
|
index: i,
|
|
2737
2871
|
message,
|
|
2738
2872
|
startedAt,
|
|
@@ -2742,19 +2876,19 @@ var executeModuleStep = async ({
|
|
|
2742
2876
|
});
|
|
2743
2877
|
break;
|
|
2744
2878
|
case "AI_ACTION" /* AI_ACTION */:
|
|
2745
|
-
moduleStepResult =
|
|
2879
|
+
moduleStepResult = yield executeAIStep({
|
|
2746
2880
|
controller,
|
|
2747
2881
|
step: moduleStep,
|
|
2748
2882
|
advanced,
|
|
2749
2883
|
logger,
|
|
2750
2884
|
onSaveScreenshot: callbacks.onSaveScreenshot,
|
|
2751
2885
|
onStarted() {
|
|
2752
|
-
var
|
|
2753
|
-
(
|
|
2886
|
+
var _a3;
|
|
2887
|
+
(_a3 = callbacks.onStepStarted) == null ? void 0 : _a3.call(callbacks, { index: i });
|
|
2754
2888
|
},
|
|
2755
2889
|
onSuccess({ message, startedAt, durationMs }) {
|
|
2756
|
-
var
|
|
2757
|
-
(
|
|
2890
|
+
var _a3;
|
|
2891
|
+
(_a3 = callbacks.onStepSuccess) == null ? void 0 : _a3.call(callbacks, {
|
|
2758
2892
|
index: i,
|
|
2759
2893
|
message,
|
|
2760
2894
|
startedAt,
|
|
@@ -2762,8 +2896,8 @@ var executeModuleStep = async ({
|
|
|
2762
2896
|
});
|
|
2763
2897
|
},
|
|
2764
2898
|
onFailure({ message, startedAt, durationMs }) {
|
|
2765
|
-
var
|
|
2766
|
-
(
|
|
2899
|
+
var _a3;
|
|
2900
|
+
(_a3 = callbacks.onStepFailure) == null ? void 0 : _a3.call(callbacks, {
|
|
2767
2901
|
index: i,
|
|
2768
2902
|
message,
|
|
2769
2903
|
startedAt,
|
|
@@ -2771,12 +2905,12 @@ var executeModuleStep = async ({
|
|
|
2771
2905
|
});
|
|
2772
2906
|
},
|
|
2773
2907
|
onCommandGenerated({ commandIndex, message }) {
|
|
2774
|
-
var
|
|
2775
|
-
(
|
|
2908
|
+
var _a3;
|
|
2909
|
+
(_a3 = callbacks.onCommandGenerated) == null ? void 0 : _a3.call(callbacks, { index: i, commandIndex, message });
|
|
2776
2910
|
},
|
|
2777
2911
|
onCommandExecuted({ commandIndex, message, command }) {
|
|
2778
|
-
var
|
|
2779
|
-
(
|
|
2912
|
+
var _a3;
|
|
2913
|
+
(_a3 = callbacks.onCommandExecuted) == null ? void 0 : _a3.call(callbacks, {
|
|
2780
2914
|
index: i,
|
|
2781
2915
|
commandIndex,
|
|
2782
2916
|
message,
|
|
@@ -2797,22 +2931,21 @@ var executeModuleStep = async ({
|
|
|
2797
2931
|
result.finishedAt = /* @__PURE__ */ new Date();
|
|
2798
2932
|
for (let j = i + 1; j < step.steps.length; j++) {
|
|
2799
2933
|
const skippedStep = step.steps[j];
|
|
2800
|
-
const skippedResult = {
|
|
2801
|
-
...skippedStep,
|
|
2934
|
+
const skippedResult = __spreadProps(__spreadValues({}, skippedStep), {
|
|
2802
2935
|
status: "CANCELLED" /* CANCELLED */,
|
|
2803
2936
|
startedAt: /* @__PURE__ */ new Date(),
|
|
2804
2937
|
finishedAt: /* @__PURE__ */ new Date(),
|
|
2805
2938
|
userAgent: ChromeBrowser.USER_AGENT,
|
|
2806
2939
|
results: [],
|
|
2807
2940
|
message: "Cancelled due to previous failure."
|
|
2808
|
-
};
|
|
2941
|
+
});
|
|
2809
2942
|
result.results.push(skippedResult);
|
|
2810
2943
|
}
|
|
2811
2944
|
break;
|
|
2812
2945
|
}
|
|
2813
2946
|
}
|
|
2814
2947
|
if (result.status === "SUCCESS" /* SUCCESS */) {
|
|
2815
|
-
(
|
|
2948
|
+
(_b2 = callbacks.onSuccess) == null ? void 0 : _b2.call(callbacks, {
|
|
2816
2949
|
message: "Executed module step.",
|
|
2817
2950
|
startedAt: result.startedAt.getTime(),
|
|
2818
2951
|
durationMs: result.finishedAt.getTime() - result.startedAt.getTime()
|
|
@@ -2825,20 +2958,20 @@ var executeModuleStep = async ({
|
|
|
2825
2958
|
});
|
|
2826
2959
|
}
|
|
2827
2960
|
return result;
|
|
2828
|
-
};
|
|
2961
|
+
});
|
|
2829
2962
|
|
|
2830
2963
|
// ../../packages/execute/src/test.ts
|
|
2831
|
-
var executeTest =
|
|
2964
|
+
var executeTest = (_0) => __async(void 0, [_0], function* ({
|
|
2832
2965
|
test,
|
|
2833
2966
|
runId,
|
|
2834
2967
|
controller,
|
|
2835
2968
|
logger,
|
|
2836
2969
|
onUpdateRun,
|
|
2837
2970
|
onSaveScreenshot
|
|
2838
|
-
})
|
|
2971
|
+
}) {
|
|
2839
2972
|
const advanced = TestAdvancedSettingsSchema.parse(test.advanced);
|
|
2840
2973
|
logger.info(`Starting run ${runId} for test ${test.id}`);
|
|
2841
|
-
|
|
2974
|
+
yield onUpdateRun({
|
|
2842
2975
|
status: "RUNNING",
|
|
2843
2976
|
startedAt: /* @__PURE__ */ new Date()
|
|
2844
2977
|
});
|
|
@@ -2849,7 +2982,7 @@ var executeTest = async ({
|
|
|
2849
2982
|
let result;
|
|
2850
2983
|
switch (step.type) {
|
|
2851
2984
|
case "PRESET_ACTION" /* PRESET_ACTION */:
|
|
2852
|
-
result =
|
|
2985
|
+
result = yield executePresetStep({
|
|
2853
2986
|
controller,
|
|
2854
2987
|
step,
|
|
2855
2988
|
advanced,
|
|
@@ -2858,7 +2991,7 @@ var executeTest = async ({
|
|
|
2858
2991
|
});
|
|
2859
2992
|
break;
|
|
2860
2993
|
case "AI_ACTION" /* AI_ACTION */:
|
|
2861
|
-
result =
|
|
2994
|
+
result = yield executeAIStep({
|
|
2862
2995
|
controller,
|
|
2863
2996
|
step,
|
|
2864
2997
|
advanced,
|
|
@@ -2867,7 +3000,7 @@ var executeTest = async ({
|
|
|
2867
3000
|
});
|
|
2868
3001
|
break;
|
|
2869
3002
|
case "RESOLVED_MODULE":
|
|
2870
|
-
result =
|
|
3003
|
+
result = yield executeModuleStep({
|
|
2871
3004
|
controller,
|
|
2872
3005
|
step,
|
|
2873
3006
|
advanced,
|
|
@@ -2882,7 +3015,7 @@ var executeTest = async ({
|
|
|
2882
3015
|
return assertUnreachable(step);
|
|
2883
3016
|
}
|
|
2884
3017
|
results.push(result);
|
|
2885
|
-
|
|
3018
|
+
yield onUpdateRun({
|
|
2886
3019
|
results
|
|
2887
3020
|
});
|
|
2888
3021
|
if (result.status === "FAILED" /* FAILED */) {
|
|
@@ -2896,28 +3029,26 @@ var executeTest = async ({
|
|
|
2896
3029
|
startedAt: /* @__PURE__ */ new Date(),
|
|
2897
3030
|
userAgent: ChromeBrowser.USER_AGENT,
|
|
2898
3031
|
results: skippedStep.steps.map((s) => {
|
|
2899
|
-
return {
|
|
2900
|
-
...s,
|
|
3032
|
+
return __spreadProps(__spreadValues({}, s), {
|
|
2901
3033
|
status: "CANCELLED" /* CANCELLED */,
|
|
2902
3034
|
startedAt: /* @__PURE__ */ new Date(),
|
|
2903
3035
|
finishedAt: /* @__PURE__ */ new Date(),
|
|
2904
3036
|
userAgent: ChromeBrowser.USER_AGENT,
|
|
2905
3037
|
results: []
|
|
2906
|
-
};
|
|
3038
|
+
});
|
|
2907
3039
|
}),
|
|
2908
3040
|
finishedAt: /* @__PURE__ */ new Date(),
|
|
2909
3041
|
status: "CANCELLED" /* CANCELLED */
|
|
2910
3042
|
};
|
|
2911
3043
|
results.push(skippedResult);
|
|
2912
3044
|
} else {
|
|
2913
|
-
const skippedResult = {
|
|
2914
|
-
...skippedStep,
|
|
3045
|
+
const skippedResult = __spreadProps(__spreadValues({}, skippedStep), {
|
|
2915
3046
|
status: "CANCELLED" /* CANCELLED */,
|
|
2916
3047
|
startedAt: /* @__PURE__ */ new Date(),
|
|
2917
3048
|
finishedAt: /* @__PURE__ */ new Date(),
|
|
2918
3049
|
userAgent: ChromeBrowser.USER_AGENT,
|
|
2919
3050
|
results: []
|
|
2920
|
-
};
|
|
3051
|
+
});
|
|
2921
3052
|
results.push(skippedResult);
|
|
2922
3053
|
}
|
|
2923
3054
|
}
|
|
@@ -2926,14 +3057,14 @@ var executeTest = async ({
|
|
|
2926
3057
|
break;
|
|
2927
3058
|
}
|
|
2928
3059
|
}
|
|
2929
|
-
|
|
3060
|
+
yield onUpdateRun({
|
|
2930
3061
|
status: failed ? "FAILED" : "PASSED",
|
|
2931
3062
|
finishedAt: /* @__PURE__ */ new Date(),
|
|
2932
3063
|
results
|
|
2933
3064
|
});
|
|
2934
|
-
|
|
3065
|
+
yield controller.browser.cleanup();
|
|
2935
3066
|
return failed;
|
|
2936
|
-
};
|
|
3067
|
+
});
|
|
2937
3068
|
|
|
2938
3069
|
// src/logger.ts
|
|
2939
3070
|
var consoleLogger = {
|
|
@@ -2947,47 +3078,58 @@ var consoleLogger = {
|
|
|
2947
3078
|
};
|
|
2948
3079
|
|
|
2949
3080
|
// src/run-test.ts
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
}) {
|
|
2955
|
-
const test = await apiClient.getTest(testId);
|
|
2956
|
-
const browser = await ChromeBrowser.init(test.baseUrl, consoleLogger);
|
|
2957
|
-
const controller = new AgentController({
|
|
2958
|
-
browser,
|
|
3081
|
+
function runTest(_0) {
|
|
3082
|
+
return __async(this, arguments, function* ({
|
|
3083
|
+
testId,
|
|
3084
|
+
apiClient,
|
|
2959
3085
|
generator,
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
return key;
|
|
2978
|
-
},
|
|
2979
|
-
onUpdateRun: async (data) => {
|
|
2980
|
-
await apiClient.updateRun(run.id, data);
|
|
2981
|
-
}
|
|
3086
|
+
newBaseURL
|
|
3087
|
+
}) {
|
|
3088
|
+
const test = yield apiClient.getTest(testId);
|
|
3089
|
+
const originalURL = new URL(test.baseUrl);
|
|
3090
|
+
const newURL = new URL(newBaseURL);
|
|
3091
|
+
originalURL.hostname = newURL.hostname;
|
|
3092
|
+
originalURL.protocol = newURL.protocol;
|
|
3093
|
+
originalURL.port = newURL.port;
|
|
3094
|
+
const browser = yield ChromeBrowser.init(
|
|
3095
|
+
originalURL.toString(),
|
|
3096
|
+
consoleLogger
|
|
3097
|
+
);
|
|
3098
|
+
const controller = new AgentController({
|
|
3099
|
+
browser,
|
|
3100
|
+
generator,
|
|
3101
|
+
config: DEFAULT_CONTROLLER_CONFIG,
|
|
3102
|
+
logger: consoleLogger
|
|
2982
3103
|
});
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
await apiClient.updateRun(run.id, {
|
|
2986
|
-
status: "FAILED",
|
|
2987
|
-
finishedAt: /* @__PURE__ */ new Date()
|
|
3104
|
+
const run = yield apiClient.createRun({
|
|
3105
|
+
testId
|
|
2988
3106
|
});
|
|
2989
|
-
|
|
2990
|
-
|
|
3107
|
+
let failed = true;
|
|
3108
|
+
try {
|
|
3109
|
+
failed = yield executeTest({
|
|
3110
|
+
test,
|
|
3111
|
+
runId: run.id,
|
|
3112
|
+
controller,
|
|
3113
|
+
logger: consoleLogger,
|
|
3114
|
+
onSaveScreenshot: (buffer) => __async(this, null, function* () {
|
|
3115
|
+
const { key } = yield apiClient.uploadScreenshot({
|
|
3116
|
+
screenshot: buffer.toString("base64")
|
|
3117
|
+
});
|
|
3118
|
+
return key;
|
|
3119
|
+
}),
|
|
3120
|
+
onUpdateRun: (data) => __async(this, null, function* () {
|
|
3121
|
+
yield apiClient.updateRun(run.id, data);
|
|
3122
|
+
})
|
|
3123
|
+
});
|
|
3124
|
+
} catch (err) {
|
|
3125
|
+
consoleLogger.error(err);
|
|
3126
|
+
yield apiClient.updateRun(run.id, {
|
|
3127
|
+
status: "FAILED",
|
|
3128
|
+
finishedAt: /* @__PURE__ */ new Date()
|
|
3129
|
+
});
|
|
3130
|
+
}
|
|
3131
|
+
return failed;
|
|
3132
|
+
});
|
|
2991
3133
|
}
|
|
2992
3134
|
|
|
2993
3135
|
// src/cli.ts
|
|
@@ -3014,10 +3156,10 @@ program.command("run-tests").addOption(
|
|
|
3014
3156
|
).default(60, "one minute")
|
|
3015
3157
|
).addOption(
|
|
3016
3158
|
new Option("--api-key <key>", "API key for authenticating").env("MOMENTIC_API_KEY").makeOptionMandatory(true)
|
|
3017
|
-
).action(
|
|
3159
|
+
).action((options) => __async(void 0, null, function* () {
|
|
3018
3160
|
const { tests, start, waitOn, waitOnTimeout, apiKey } = options;
|
|
3019
|
-
|
|
3020
|
-
|
|
3161
|
+
yield execCommand(start, false);
|
|
3162
|
+
yield waitOnFn({
|
|
3021
3163
|
resources: [waitOn],
|
|
3022
3164
|
timeout: waitOnTimeout * 1e3
|
|
3023
3165
|
});
|
|
@@ -3029,15 +3171,16 @@ program.command("run-tests").addOption(
|
|
|
3029
3171
|
baseURL: "https://api.momentic.ai",
|
|
3030
3172
|
apiKey
|
|
3031
3173
|
});
|
|
3032
|
-
const promises = tests.map(
|
|
3033
|
-
const failed =
|
|
3174
|
+
const promises = tests.map((testId) => __async(void 0, null, function* () {
|
|
3175
|
+
const failed = yield runTest({
|
|
3034
3176
|
testId,
|
|
3035
3177
|
apiClient,
|
|
3036
|
-
generator: apiGenerator
|
|
3178
|
+
generator: apiGenerator,
|
|
3179
|
+
newBaseURL: waitOn
|
|
3037
3180
|
});
|
|
3038
3181
|
return { failed, testId };
|
|
3039
|
-
});
|
|
3040
|
-
const results =
|
|
3182
|
+
}));
|
|
3183
|
+
const results = yield Promise.all(promises);
|
|
3041
3184
|
const failedResults = results.filter((result) => result.failed);
|
|
3042
3185
|
if (failedResults.length > 0) {
|
|
3043
3186
|
console.log(
|
|
@@ -3051,17 +3194,19 @@ program.command("run-tests").addOption(
|
|
|
3051
3194
|
process.exit(1);
|
|
3052
3195
|
}
|
|
3053
3196
|
console.log(chalk.green(`All ${results.length} tests passed!`));
|
|
3054
|
-
});
|
|
3055
|
-
var execCommand =
|
|
3197
|
+
}));
|
|
3198
|
+
var execCommand = (fullCommand, waitToFinish = true) => __async(void 0, null, function* () {
|
|
3056
3199
|
const args = parseArgsStringToArgv2(fullCommand);
|
|
3057
|
-
const toolPath =
|
|
3200
|
+
const toolPath = yield io.which(args[0], true);
|
|
3058
3201
|
const toolArguments = args.slice(1);
|
|
3059
3202
|
const promise = exec.exec(quote(toolPath), toolArguments);
|
|
3060
3203
|
if (waitToFinish) {
|
|
3061
3204
|
return promise;
|
|
3062
3205
|
}
|
|
3063
|
-
};
|
|
3064
|
-
|
|
3065
|
-
|
|
3206
|
+
});
|
|
3207
|
+
function main() {
|
|
3208
|
+
return __async(this, null, function* () {
|
|
3209
|
+
yield program.parseAsync(process.argv);
|
|
3210
|
+
});
|
|
3066
3211
|
}
|
|
3067
3212
|
void main();
|