@midscene/web 0.7.1 → 0.7.2-beta-20241024094141.0
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/dist/browser/playground.js +8438 -0
- package/dist/browser/types/playground.d.ts +313 -0
- package/dist/es/appium.js +680 -604
- package/dist/es/debug.js +95 -73
- package/dist/es/index.js +939 -797
- package/dist/es/midscene-playground.js +678 -609
- package/dist/es/playground.js +593 -1024
- package/dist/es/playwright-report.js +29 -11
- package/dist/es/playwright.js +705 -597
- package/dist/es/puppeteer.js +636 -552
- package/dist/lib/appium.js +688 -609
- package/dist/lib/debug.js +95 -73
- package/dist/lib/index.js +950 -804
- package/dist/lib/midscene-playground.js +687 -615
- package/dist/lib/playground.js +586 -1007
- package/dist/lib/playwright-report.js +30 -9
- package/dist/lib/playwright.js +713 -602
- package/dist/lib/puppeteer.js +644 -557
- package/dist/script/htmlElement.js +11 -10
- package/dist/script/htmlElementDebug.js +11 -10
- package/dist/types/appium.d.ts +2 -3
- package/dist/types/debug.d.ts +1 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/{page-ad820b3c.d.ts → page-8117b0ad.d.ts} +8 -7
- package/dist/types/playground.d.ts +6 -21
- package/dist/types/playwright.d.ts +3 -4
- package/dist/types/puppeteer.d.ts +2 -3
- package/dist/types/{tasks-82c1054b.d.ts → tasks-cb6bf758.d.ts} +6 -6
- package/package.json +11 -5
- package/static/index.html +1 -1
package/dist/lib/puppeteer.js
CHANGED
|
@@ -46,6 +46,26 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
46
46
|
mod
|
|
47
47
|
));
|
|
48
48
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
49
|
+
var __async = (__this, __arguments, generator) => {
|
|
50
|
+
return new Promise((resolve, reject) => {
|
|
51
|
+
var fulfilled = (value) => {
|
|
52
|
+
try {
|
|
53
|
+
step(generator.next(value));
|
|
54
|
+
} catch (e) {
|
|
55
|
+
reject(e);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
var rejected = (value) => {
|
|
59
|
+
try {
|
|
60
|
+
step(generator.throw(value));
|
|
61
|
+
} catch (e) {
|
|
62
|
+
reject(e);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
66
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
67
|
+
});
|
|
68
|
+
};
|
|
49
69
|
|
|
50
70
|
// ../../node_modules/.pnpm/dayjs@1.11.11/node_modules/dayjs/dayjs.min.js
|
|
51
71
|
var require_dayjs_min = __commonJS({
|
|
@@ -351,29 +371,29 @@ __export(puppeteer_exports, {
|
|
|
351
371
|
module.exports = __toCommonJS(puppeteer_exports);
|
|
352
372
|
|
|
353
373
|
// src/common/agent.ts
|
|
354
|
-
var
|
|
374
|
+
var import_utils7 = require("@midscene/core/utils");
|
|
355
375
|
|
|
356
376
|
// src/common/tasks.ts
|
|
357
377
|
var import_node_assert2 = __toESM(require("assert"));
|
|
358
378
|
var import_core = require("@midscene/core");
|
|
359
|
-
var
|
|
360
|
-
var import_img3 = require("@midscene/shared/img");
|
|
379
|
+
var import_utils5 = require("@midscene/core/utils");
|
|
361
380
|
|
|
362
381
|
// src/common/task-cache.ts
|
|
363
382
|
var import_node_fs2 = require("fs");
|
|
364
383
|
var import_node_path2 = require("path");
|
|
365
|
-
var
|
|
384
|
+
var import_utils2 = require("@midscene/core/utils");
|
|
366
385
|
var import_fs2 = require("@midscene/shared/fs");
|
|
386
|
+
var import_utils3 = require("@midscene/shared/utils");
|
|
367
387
|
|
|
368
388
|
// src/common/utils.ts
|
|
369
389
|
var import_node_assert = __toESM(require("assert"));
|
|
370
|
-
var import_node_crypto = require("crypto");
|
|
371
390
|
var import_node_fs = require("fs");
|
|
372
391
|
var import_node_path = __toESM(require("path"));
|
|
373
392
|
var import_constants = require("@midscene/shared/constants");
|
|
374
393
|
var import_fs = require("@midscene/shared/fs");
|
|
375
394
|
var import_img = require("@midscene/shared/img");
|
|
376
395
|
var import_img2 = require("@midscene/shared/img");
|
|
396
|
+
var import_utils = require("@midscene/shared/utils");
|
|
377
397
|
var import_dayjs = __toESM(require_dayjs_min());
|
|
378
398
|
|
|
379
399
|
// src/web-element.ts
|
|
@@ -402,63 +422,68 @@ var WebElementInfo = class {
|
|
|
402
422
|
};
|
|
403
423
|
|
|
404
424
|
// src/common/utils.ts
|
|
405
|
-
|
|
406
|
-
(
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
const url = page.url();
|
|
411
|
-
const file = await page.screenshot();
|
|
412
|
-
const screenshotBase64 = (0, import_img.base64Encoded)(file);
|
|
413
|
-
const captureElementSnapshot = await page.getElementInfos();
|
|
414
|
-
const elementsInfo = await alignElements(captureElementSnapshot, page);
|
|
415
|
-
const elementsPositionInfoWithoutText = elementsInfo.filter((elementInfo) => {
|
|
416
|
-
if (elementInfo.attributes.nodeType === import_constants.NodeType.TEXT) {
|
|
417
|
-
return false;
|
|
425
|
+
function parseContextFromWebPage(page, _opt) {
|
|
426
|
+
return __async(this, null, function* () {
|
|
427
|
+
(0, import_node_assert.default)(page, "page is required");
|
|
428
|
+
if (page._forceUsePageContext) {
|
|
429
|
+
return yield page._forceUsePageContext();
|
|
418
430
|
}
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
431
|
+
const url = page.url();
|
|
432
|
+
const screenshotBase64 = yield page.screenshotBase64();
|
|
433
|
+
const captureElementSnapshot = yield page.getElementInfos();
|
|
434
|
+
const elementsInfo = yield alignElements(captureElementSnapshot, page);
|
|
435
|
+
const elementsPositionInfoWithoutText = elementsInfo.filter((elementInfo) => {
|
|
436
|
+
if (elementInfo.attributes.nodeType === import_constants.NodeType.TEXT) {
|
|
437
|
+
return false;
|
|
438
|
+
}
|
|
439
|
+
return true;
|
|
440
|
+
});
|
|
441
|
+
const size = yield (0, import_img.imageInfoOfBase64)(screenshotBase64);
|
|
442
|
+
const screenshotBase64WithElementMarker = yield (0, import_img2.compositeElementInfoImg)({
|
|
443
|
+
inputImgBase64: screenshotBase64,
|
|
444
|
+
elementsPositionInfo: elementsPositionInfoWithoutText
|
|
445
|
+
});
|
|
446
|
+
return {
|
|
447
|
+
content: elementsInfo,
|
|
448
|
+
size,
|
|
449
|
+
screenshotBase64,
|
|
450
|
+
screenshotBase64WithElementMarker: `data:image/png;base64,${screenshotBase64WithElementMarker}`,
|
|
451
|
+
url
|
|
452
|
+
};
|
|
425
453
|
});
|
|
426
|
-
return {
|
|
427
|
-
content: elementsInfo,
|
|
428
|
-
size,
|
|
429
|
-
screenshotBase64,
|
|
430
|
-
screenshotBase64WithElementMarker: `data:image/png;base64,${screenshotBase64WithElementMarker}`,
|
|
431
|
-
url
|
|
432
|
-
};
|
|
433
454
|
}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
455
|
+
function getExtraReturnLogic() {
|
|
456
|
+
return __async(this, null, function* () {
|
|
457
|
+
const pathDir = (0, import_fs.findNearestPackageJson)(__dirname);
|
|
458
|
+
(0, import_node_assert.default)(pathDir, `can't find pathDir, with ${__dirname}`);
|
|
459
|
+
const scriptPath = import_node_path.default.join(pathDir, "./dist/script/htmlElement.js");
|
|
460
|
+
const elementInfosScriptContent = (0, import_node_fs.readFileSync)(scriptPath, "utf-8");
|
|
461
|
+
return `${elementInfosScriptContent}midscene_element_inspector.webExtractTextWithPosition()`;
|
|
462
|
+
});
|
|
440
463
|
}
|
|
441
464
|
var sizeThreshold = 3;
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
465
|
+
function alignElements(elements, page) {
|
|
466
|
+
return __async(this, null, function* () {
|
|
467
|
+
const validElements = elements.filter((item) => {
|
|
468
|
+
return item.rect.height >= sizeThreshold && item.rect.width >= sizeThreshold;
|
|
469
|
+
});
|
|
470
|
+
const textsAligned = [];
|
|
471
|
+
for (const item of validElements) {
|
|
472
|
+
const { rect, id, content, attributes, locator, indexId } = item;
|
|
473
|
+
textsAligned.push(
|
|
474
|
+
new WebElementInfo({
|
|
475
|
+
rect,
|
|
476
|
+
locator,
|
|
477
|
+
id,
|
|
478
|
+
content,
|
|
479
|
+
attributes,
|
|
480
|
+
page,
|
|
481
|
+
indexId
|
|
482
|
+
})
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
return textsAligned;
|
|
445
486
|
});
|
|
446
|
-
const textsAligned = [];
|
|
447
|
-
for (const item of validElements) {
|
|
448
|
-
const { rect, id, content, attributes, locator, indexId } = item;
|
|
449
|
-
textsAligned.push(
|
|
450
|
-
new WebElementInfo({
|
|
451
|
-
rect,
|
|
452
|
-
locator,
|
|
453
|
-
id,
|
|
454
|
-
content,
|
|
455
|
-
attributes,
|
|
456
|
-
page,
|
|
457
|
-
indexId
|
|
458
|
-
})
|
|
459
|
-
);
|
|
460
|
-
}
|
|
461
|
-
return textsAligned;
|
|
462
487
|
}
|
|
463
488
|
function reportFileName(tag = "web") {
|
|
464
489
|
const dateTimeInFileName = (0, import_dayjs.default)().format("YYYY-MM-DD_HH-mm-ss-SSS");
|
|
@@ -489,7 +514,7 @@ var testFileIndex = /* @__PURE__ */ new Map();
|
|
|
489
514
|
function generateCacheId(fileName) {
|
|
490
515
|
let taskFile = fileName || getCurrentExecutionFile();
|
|
491
516
|
if (!taskFile) {
|
|
492
|
-
taskFile = (0,
|
|
517
|
+
taskFile = (0, import_utils.uuid)();
|
|
493
518
|
console.warn(
|
|
494
519
|
"Midscene - using random UUID for cache id. Cache may be invalid."
|
|
495
520
|
);
|
|
@@ -508,7 +533,7 @@ function generateCacheId(fileName) {
|
|
|
508
533
|
// src/common/task-cache.ts
|
|
509
534
|
var TaskCache = class {
|
|
510
535
|
constructor(opts) {
|
|
511
|
-
this.midscenePkgInfo = (0, import_fs2.
|
|
536
|
+
this.midscenePkgInfo = (0, import_fs2.getRunningPkgInfo)();
|
|
512
537
|
this.cacheId = generateCacheId(opts == null ? void 0 : opts.fileName);
|
|
513
538
|
this.cache = this.readCacheFromFile() || {
|
|
514
539
|
aiTasks: []
|
|
@@ -590,11 +615,17 @@ var TaskCache = class {
|
|
|
590
615
|
return this.newCache;
|
|
591
616
|
}
|
|
592
617
|
readCacheFromFile() {
|
|
593
|
-
|
|
618
|
+
if (import_utils3.ifInBrowser) {
|
|
619
|
+
return void 0;
|
|
620
|
+
}
|
|
621
|
+
const cacheFile = (0, import_node_path2.join)((0, import_utils2.getLogDirByType)("cache"), `${this.cacheId}.json`);
|
|
594
622
|
if (process.env.MIDSCENE_CACHE === "true" && (0, import_node_fs2.existsSync)(cacheFile)) {
|
|
595
623
|
try {
|
|
596
624
|
const data = (0, import_node_fs2.readFileSync)(cacheFile, "utf8");
|
|
597
625
|
const jsonData = JSON.parse(data);
|
|
626
|
+
if (!this.midscenePkgInfo) {
|
|
627
|
+
return void 0;
|
|
628
|
+
}
|
|
598
629
|
if (jsonData.pkgName !== this.midscenePkgInfo.name || jsonData.pkgVersion !== this.midscenePkgInfo.version) {
|
|
599
630
|
return void 0;
|
|
600
631
|
}
|
|
@@ -606,11 +637,14 @@ var TaskCache = class {
|
|
|
606
637
|
return void 0;
|
|
607
638
|
}
|
|
608
639
|
writeCacheToFile() {
|
|
609
|
-
const midscenePkgInfo = (0, import_fs2.
|
|
610
|
-
(
|
|
640
|
+
const midscenePkgInfo = (0, import_fs2.getRunningPkgInfo)();
|
|
641
|
+
if (!midscenePkgInfo) {
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
(0, import_utils2.writeLogFile)({
|
|
611
645
|
fileName: `${this.cacheId}`,
|
|
612
646
|
fileExt: "json",
|
|
613
|
-
fileContent: (0,
|
|
647
|
+
fileContent: (0, import_utils2.stringifyDumpData)(
|
|
614
648
|
__spreadValues({
|
|
615
649
|
pkgName: midscenePkgInfo.name,
|
|
616
650
|
pkgVersion: midscenePkgInfo.version,
|
|
@@ -627,423 +661,435 @@ var TaskCache = class {
|
|
|
627
661
|
var PageTaskExecutor = class {
|
|
628
662
|
constructor(page, opts) {
|
|
629
663
|
this.page = page;
|
|
630
|
-
this.insight = new import_core.Insight(
|
|
631
|
-
return
|
|
632
|
-
});
|
|
664
|
+
this.insight = new import_core.Insight(() => __async(this, null, function* () {
|
|
665
|
+
return yield parseContextFromWebPage(page);
|
|
666
|
+
}));
|
|
633
667
|
this.taskCache = new TaskCache({
|
|
634
668
|
fileName: opts == null ? void 0 : opts.cacheId
|
|
635
669
|
});
|
|
636
670
|
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
671
|
+
recordScreenshot(timing) {
|
|
672
|
+
return __async(this, null, function* () {
|
|
673
|
+
const base64 = yield this.page.screenshotBase64();
|
|
674
|
+
const item = {
|
|
675
|
+
type: "screenshot",
|
|
676
|
+
ts: Date.now(),
|
|
677
|
+
screenshot: base64,
|
|
678
|
+
timing
|
|
679
|
+
};
|
|
680
|
+
return item;
|
|
681
|
+
});
|
|
646
682
|
}
|
|
647
683
|
wrapExecutorWithScreenshot(taskApply) {
|
|
648
684
|
const taskWithScreenshot = __spreadProps(__spreadValues({}, taskApply), {
|
|
649
|
-
executor:
|
|
685
|
+
executor: (param, context, ...args) => __async(this, null, function* () {
|
|
650
686
|
const recorder = [];
|
|
651
687
|
const { task } = context;
|
|
652
688
|
task.recorder = recorder;
|
|
653
|
-
const shot =
|
|
689
|
+
const shot = yield this.recordScreenshot(`before ${task.type}`);
|
|
654
690
|
recorder.push(shot);
|
|
655
|
-
const result =
|
|
691
|
+
const result = yield taskApply.executor(param, context, ...args);
|
|
656
692
|
if (taskApply.type === "Action") {
|
|
657
|
-
|
|
658
|
-
const shot2 =
|
|
693
|
+
yield (0, import_utils5.sleep)(1e3);
|
|
694
|
+
const shot2 = yield this.recordScreenshot("after Action");
|
|
659
695
|
recorder.push(shot2);
|
|
660
696
|
}
|
|
661
697
|
return result;
|
|
662
|
-
}
|
|
698
|
+
})
|
|
663
699
|
});
|
|
664
700
|
return taskWithScreenshot;
|
|
665
701
|
}
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
this.insight.onceDumpUpdatedFn = dumpCollector;
|
|
680
|
-
const pageContext = await this.insight.contextRetrieverFn();
|
|
681
|
-
const locateCache = cacheGroup == null ? void 0 : cacheGroup.readCache(
|
|
682
|
-
pageContext,
|
|
683
|
-
"locate",
|
|
684
|
-
param.prompt
|
|
685
|
-
);
|
|
686
|
-
let locateResult;
|
|
687
|
-
const callAI = this.insight.aiVendorFn;
|
|
688
|
-
const element = await this.insight.locate(param.prompt, {
|
|
689
|
-
quickAnswer: plan2.quickAnswer,
|
|
690
|
-
callAI: async (...message) => {
|
|
691
|
-
if (locateCache) {
|
|
692
|
-
locateResult = locateCache;
|
|
693
|
-
return Promise.resolve(locateCache);
|
|
694
|
-
}
|
|
695
|
-
locateResult = await callAI(...message);
|
|
696
|
-
(0, import_node_assert2.default)(locateResult);
|
|
697
|
-
return locateResult;
|
|
698
|
-
}
|
|
699
|
-
});
|
|
700
|
-
if (locateResult) {
|
|
701
|
-
cacheGroup == null ? void 0 : cacheGroup.saveCache({
|
|
702
|
-
type: "locate",
|
|
703
|
-
pageContext: {
|
|
704
|
-
url: pageContext.url,
|
|
705
|
-
size: pageContext.size
|
|
706
|
-
},
|
|
707
|
-
prompt: param.prompt,
|
|
708
|
-
response: locateResult
|
|
709
|
-
});
|
|
710
|
-
}
|
|
711
|
-
if (!element) {
|
|
712
|
-
task.log = {
|
|
713
|
-
dump: insightDump
|
|
702
|
+
convertPlanToExecutable(plans, cacheGroup) {
|
|
703
|
+
return __async(this, null, function* () {
|
|
704
|
+
const tasks = plans.map((plan2) => {
|
|
705
|
+
if (plan2.type === "Locate") {
|
|
706
|
+
const taskFind = {
|
|
707
|
+
type: "Insight",
|
|
708
|
+
subType: "Locate",
|
|
709
|
+
param: plan2.param,
|
|
710
|
+
executor: (param, taskContext) => __async(this, null, function* () {
|
|
711
|
+
const { task } = taskContext;
|
|
712
|
+
let insightDump;
|
|
713
|
+
const dumpCollector = (dump) => {
|
|
714
|
+
insightDump = dump;
|
|
714
715
|
};
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
716
|
+
this.insight.onceDumpUpdatedFn = dumpCollector;
|
|
717
|
+
const pageContext = yield this.insight.contextRetrieverFn();
|
|
718
|
+
const locateCache = cacheGroup == null ? void 0 : cacheGroup.readCache(
|
|
719
|
+
pageContext,
|
|
720
|
+
"locate",
|
|
721
|
+
param.prompt
|
|
722
|
+
);
|
|
723
|
+
let locateResult;
|
|
724
|
+
const callAI = this.insight.aiVendorFn;
|
|
725
|
+
const element = yield this.insight.locate(param.prompt, {
|
|
726
|
+
quickAnswer: plan2.quickAnswer,
|
|
727
|
+
callAI: (...message) => __async(this, null, function* () {
|
|
728
|
+
if (locateCache) {
|
|
729
|
+
locateResult = locateCache;
|
|
730
|
+
return Promise.resolve(locateCache);
|
|
731
|
+
}
|
|
732
|
+
locateResult = yield callAI(...message);
|
|
733
|
+
(0, import_node_assert2.default)(locateResult);
|
|
734
|
+
return locateResult;
|
|
735
|
+
})
|
|
736
|
+
});
|
|
737
|
+
if (locateResult) {
|
|
738
|
+
cacheGroup == null ? void 0 : cacheGroup.saveCache({
|
|
739
|
+
type: "locate",
|
|
740
|
+
pageContext: {
|
|
741
|
+
url: pageContext.url,
|
|
742
|
+
size: pageContext.size
|
|
743
|
+
},
|
|
744
|
+
prompt: param.prompt,
|
|
745
|
+
response: locateResult
|
|
746
|
+
});
|
|
726
747
|
}
|
|
727
|
-
|
|
728
|
-
}
|
|
729
|
-
};
|
|
730
|
-
return taskFind;
|
|
731
|
-
}
|
|
732
|
-
if (plan2.type === "Assert" || plan2.type === "AssertWithoutThrow") {
|
|
733
|
-
const assertPlan = plan2;
|
|
734
|
-
const taskAssert = {
|
|
735
|
-
type: "Insight",
|
|
736
|
-
subType: "Assert",
|
|
737
|
-
param: assertPlan.param,
|
|
738
|
-
executor: async (param, taskContext) => {
|
|
739
|
-
const { task } = taskContext;
|
|
740
|
-
let insightDump;
|
|
741
|
-
const dumpCollector = (dump) => {
|
|
742
|
-
insightDump = dump;
|
|
743
|
-
};
|
|
744
|
-
this.insight.onceDumpUpdatedFn = dumpCollector;
|
|
745
|
-
const assertion = await this.insight.assert(
|
|
746
|
-
assertPlan.param.assertion
|
|
747
|
-
);
|
|
748
|
-
if (!assertion.pass) {
|
|
749
|
-
if (plan2.type === "Assert") {
|
|
750
|
-
task.output = assertion;
|
|
748
|
+
if (!element) {
|
|
751
749
|
task.log = {
|
|
752
750
|
dump: insightDump
|
|
753
751
|
};
|
|
754
|
-
throw new Error(
|
|
755
|
-
assertion.thought || "Assertion failed without reason"
|
|
756
|
-
);
|
|
752
|
+
throw new Error(`Element not found: ${param.prompt}`);
|
|
757
753
|
}
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
754
|
+
return {
|
|
755
|
+
output: {
|
|
756
|
+
element
|
|
757
|
+
},
|
|
758
|
+
log: {
|
|
759
|
+
dump: insightDump
|
|
760
|
+
},
|
|
761
|
+
cache: {
|
|
762
|
+
hit: Boolean(locateCache)
|
|
763
|
+
}
|
|
764
|
+
};
|
|
765
|
+
})
|
|
766
|
+
};
|
|
767
|
+
return taskFind;
|
|
768
|
+
}
|
|
769
|
+
if (plan2.type === "Assert" || plan2.type === "AssertWithoutThrow") {
|
|
770
|
+
const assertPlan = plan2;
|
|
771
|
+
const taskAssert = {
|
|
772
|
+
type: "Insight",
|
|
773
|
+
subType: "Assert",
|
|
774
|
+
param: assertPlan.param,
|
|
775
|
+
executor: (param, taskContext) => __async(this, null, function* () {
|
|
776
|
+
const { task } = taskContext;
|
|
777
|
+
let insightDump;
|
|
778
|
+
const dumpCollector = (dump) => {
|
|
779
|
+
insightDump = dump;
|
|
780
|
+
};
|
|
781
|
+
this.insight.onceDumpUpdatedFn = dumpCollector;
|
|
782
|
+
const assertion = yield this.insight.assert(
|
|
783
|
+
assertPlan.param.assertion
|
|
784
|
+
);
|
|
785
|
+
if (!assertion.pass) {
|
|
786
|
+
if (plan2.type === "Assert") {
|
|
787
|
+
task.output = assertion;
|
|
788
|
+
task.log = {
|
|
789
|
+
dump: insightDump
|
|
790
|
+
};
|
|
791
|
+
throw new Error(
|
|
792
|
+
assertion.thought || "Assertion failed without reason"
|
|
793
|
+
);
|
|
794
|
+
}
|
|
795
|
+
task.error = assertion.thought;
|
|
764
796
|
}
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
797
|
+
return {
|
|
798
|
+
output: assertion,
|
|
799
|
+
log: {
|
|
800
|
+
dump: insightDump
|
|
801
|
+
}
|
|
802
|
+
};
|
|
803
|
+
})
|
|
804
|
+
};
|
|
805
|
+
return taskAssert;
|
|
806
|
+
}
|
|
807
|
+
if (plan2.type === "Input") {
|
|
808
|
+
const taskActionInput = {
|
|
809
|
+
type: "Action",
|
|
810
|
+
subType: "Input",
|
|
811
|
+
param: plan2.param,
|
|
812
|
+
executor: (_0, _1) => __async(this, [_0, _1], function* (taskParam, { element }) {
|
|
813
|
+
if (element) {
|
|
814
|
+
yield this.page.clearInput(element);
|
|
815
|
+
if (taskParam.value === "") {
|
|
816
|
+
return;
|
|
817
|
+
}
|
|
818
|
+
yield this.page.keyboard.type(taskParam.value);
|
|
780
819
|
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
)
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
return
|
|
820
|
+
})
|
|
821
|
+
};
|
|
822
|
+
return taskActionInput;
|
|
823
|
+
}
|
|
824
|
+
if (plan2.type === "KeyboardPress") {
|
|
825
|
+
const taskActionKeyboardPress = {
|
|
826
|
+
type: "Action",
|
|
827
|
+
subType: "KeyboardPress",
|
|
828
|
+
param: plan2.param,
|
|
829
|
+
executor: (taskParam) => __async(this, null, function* () {
|
|
830
|
+
(0, import_node_assert2.default)(taskParam.value, "No key to press");
|
|
831
|
+
yield this.page.keyboard.press(taskParam.value);
|
|
832
|
+
})
|
|
833
|
+
};
|
|
834
|
+
return taskActionKeyboardPress;
|
|
835
|
+
}
|
|
836
|
+
if (plan2.type === "Tap") {
|
|
837
|
+
const taskActionTap = {
|
|
838
|
+
type: "Action",
|
|
839
|
+
subType: "Tap",
|
|
840
|
+
executor: (_0, _1) => __async(this, [_0, _1], function* (param, { element }) {
|
|
841
|
+
(0, import_node_assert2.default)(element, "Element not found, cannot tap");
|
|
842
|
+
yield this.page.mouse.click(
|
|
843
|
+
element.center[0],
|
|
844
|
+
element.center[1]
|
|
845
|
+
);
|
|
846
|
+
})
|
|
847
|
+
};
|
|
848
|
+
return taskActionTap;
|
|
849
|
+
}
|
|
850
|
+
if (plan2.type === "Hover") {
|
|
851
|
+
const taskActionHover = {
|
|
852
|
+
type: "Action",
|
|
853
|
+
subType: "Hover",
|
|
854
|
+
executor: (_0, _1) => __async(this, [_0, _1], function* (param, { element }) {
|
|
855
|
+
(0, import_node_assert2.default)(element, "Element not found, cannot hover");
|
|
856
|
+
yield this.page.mouse.move(
|
|
857
|
+
element.center[0],
|
|
858
|
+
element.center[1]
|
|
859
|
+
);
|
|
860
|
+
})
|
|
861
|
+
};
|
|
862
|
+
return taskActionHover;
|
|
863
|
+
}
|
|
864
|
+
if (plan2.type === "Scroll") {
|
|
865
|
+
const taskActionScroll = {
|
|
866
|
+
type: "Action",
|
|
867
|
+
subType: "Scroll",
|
|
868
|
+
param: plan2.param,
|
|
869
|
+
executor: (taskParam) => __async(this, null, function* () {
|
|
870
|
+
const scrollToEventName = taskParam.scrollType;
|
|
871
|
+
switch (scrollToEventName) {
|
|
872
|
+
case "scrollUntilTop":
|
|
873
|
+
yield this.page.scrollUntilTop();
|
|
874
|
+
break;
|
|
875
|
+
case "scrollUntilBottom":
|
|
876
|
+
yield this.page.scrollUntilBottom();
|
|
877
|
+
break;
|
|
878
|
+
case "scrollUpOneScreen":
|
|
879
|
+
yield this.page.scrollUpOneScreen();
|
|
880
|
+
break;
|
|
881
|
+
case "scrollDownOneScreen":
|
|
882
|
+
yield this.page.scrollDownOneScreen();
|
|
883
|
+
break;
|
|
884
|
+
default:
|
|
885
|
+
console.error(
|
|
886
|
+
"Unknown scroll event type:",
|
|
887
|
+
scrollToEventName
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
})
|
|
891
|
+
};
|
|
892
|
+
return taskActionScroll;
|
|
893
|
+
}
|
|
894
|
+
if (plan2.type === "Sleep") {
|
|
895
|
+
const taskActionSleep = {
|
|
896
|
+
type: "Action",
|
|
897
|
+
subType: "Sleep",
|
|
898
|
+
param: plan2.param,
|
|
899
|
+
executor: (taskParam) => __async(this, null, function* () {
|
|
900
|
+
yield (0, import_utils5.sleep)(taskParam.timeMs || 3e3);
|
|
901
|
+
})
|
|
902
|
+
};
|
|
903
|
+
return taskActionSleep;
|
|
904
|
+
}
|
|
905
|
+
if (plan2.type === "Error") {
|
|
906
|
+
const taskActionError = {
|
|
907
|
+
type: "Action",
|
|
908
|
+
subType: "Error",
|
|
909
|
+
param: plan2.param,
|
|
910
|
+
executor: (taskParam) => __async(this, null, function* () {
|
|
911
|
+
(0, import_node_assert2.default)(
|
|
912
|
+
taskParam.thought,
|
|
913
|
+
"An error occurred, but no thought provided"
|
|
914
|
+
);
|
|
915
|
+
throw new Error(taskParam.thought);
|
|
916
|
+
})
|
|
917
|
+
};
|
|
918
|
+
return taskActionError;
|
|
919
|
+
}
|
|
920
|
+
throw new Error(`Unknown or Unsupported task type: ${plan2.type}`);
|
|
921
|
+
}).map((task) => {
|
|
922
|
+
return this.wrapExecutorWithScreenshot(task);
|
|
923
|
+
});
|
|
924
|
+
return tasks;
|
|
886
925
|
});
|
|
887
|
-
return tasks;
|
|
888
926
|
}
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
927
|
+
action(userPrompt) {
|
|
928
|
+
return __async(this, null, function* () {
|
|
929
|
+
const taskExecutor = new import_core.Executor(userPrompt);
|
|
930
|
+
const cacheGroup = this.taskCache.getCacheGroupByPrompt(userPrompt);
|
|
931
|
+
let plans = [];
|
|
932
|
+
const planningTask = {
|
|
933
|
+
type: "Planning",
|
|
934
|
+
param: {
|
|
935
|
+
userPrompt
|
|
936
|
+
},
|
|
937
|
+
executor: (param) => __async(this, null, function* () {
|
|
938
|
+
const pageContext = yield this.insight.contextRetrieverFn();
|
|
939
|
+
let planResult;
|
|
940
|
+
const planCache = cacheGroup.readCache(pageContext, "plan", userPrompt);
|
|
941
|
+
if (planCache) {
|
|
942
|
+
planResult = planCache;
|
|
943
|
+
} else {
|
|
944
|
+
planResult = yield (0, import_core.plan)(param.userPrompt, {
|
|
945
|
+
context: pageContext
|
|
946
|
+
});
|
|
947
|
+
}
|
|
948
|
+
(0, import_node_assert2.default)(planResult.plans.length > 0, "No plans found");
|
|
949
|
+
plans = planResult.plans;
|
|
950
|
+
cacheGroup.saveCache({
|
|
951
|
+
type: "plan",
|
|
952
|
+
pageContext: {
|
|
953
|
+
url: pageContext.url,
|
|
954
|
+
size: pageContext.size
|
|
955
|
+
},
|
|
956
|
+
prompt: userPrompt,
|
|
957
|
+
response: planResult
|
|
907
958
|
});
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
});
|
|
959
|
+
return {
|
|
960
|
+
output: planResult,
|
|
961
|
+
cache: {
|
|
962
|
+
hit: Boolean(planCache)
|
|
963
|
+
}
|
|
964
|
+
};
|
|
965
|
+
})
|
|
966
|
+
};
|
|
967
|
+
yield taskExecutor.append(this.wrapExecutorWithScreenshot(planningTask));
|
|
968
|
+
let output = yield taskExecutor.flush();
|
|
969
|
+
if (taskExecutor.isInErrorState()) {
|
|
920
970
|
return {
|
|
921
|
-
output
|
|
922
|
-
|
|
923
|
-
hit: Boolean(planCache)
|
|
924
|
-
}
|
|
971
|
+
output,
|
|
972
|
+
executor: taskExecutor
|
|
925
973
|
};
|
|
926
974
|
}
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
if (taskExecutor.isInErrorState()) {
|
|
975
|
+
const executables = yield this.convertPlanToExecutable(plans, cacheGroup);
|
|
976
|
+
yield taskExecutor.append(executables);
|
|
977
|
+
output = yield taskExecutor.flush();
|
|
931
978
|
return {
|
|
932
979
|
output,
|
|
933
980
|
executor: taskExecutor
|
|
934
981
|
};
|
|
935
|
-
}
|
|
936
|
-
const executables = await this.convertPlanToExecutable(plans, cacheGroup);
|
|
937
|
-
await taskExecutor.append(executables);
|
|
938
|
-
output = await taskExecutor.flush();
|
|
939
|
-
return {
|
|
940
|
-
output,
|
|
941
|
-
executor: taskExecutor
|
|
942
|
-
};
|
|
943
|
-
}
|
|
944
|
-
async query(demand) {
|
|
945
|
-
const description = typeof demand === "string" ? demand : JSON.stringify(demand);
|
|
946
|
-
const taskExecutor = new import_core.Executor(description);
|
|
947
|
-
const queryTask = {
|
|
948
|
-
type: "Insight",
|
|
949
|
-
subType: "Query",
|
|
950
|
-
param: {
|
|
951
|
-
dataDemand: demand
|
|
952
|
-
},
|
|
953
|
-
executor: async (param) => {
|
|
954
|
-
let insightDump;
|
|
955
|
-
const dumpCollector = (dump) => {
|
|
956
|
-
insightDump = dump;
|
|
957
|
-
};
|
|
958
|
-
this.insight.onceDumpUpdatedFn = dumpCollector;
|
|
959
|
-
const data = await this.insight.extract(param.dataDemand);
|
|
960
|
-
return {
|
|
961
|
-
output: data,
|
|
962
|
-
log: { dump: insightDump }
|
|
963
|
-
};
|
|
964
|
-
}
|
|
965
|
-
};
|
|
966
|
-
await taskExecutor.append(this.wrapExecutorWithScreenshot(queryTask));
|
|
967
|
-
const output = await taskExecutor.flush();
|
|
968
|
-
return {
|
|
969
|
-
output,
|
|
970
|
-
executor: taskExecutor
|
|
971
|
-
};
|
|
982
|
+
});
|
|
972
983
|
}
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
984
|
+
query(demand) {
|
|
985
|
+
return __async(this, null, function* () {
|
|
986
|
+
const description = typeof demand === "string" ? demand : JSON.stringify(demand);
|
|
987
|
+
const taskExecutor = new import_core.Executor(description);
|
|
988
|
+
const queryTask = {
|
|
989
|
+
type: "Insight",
|
|
990
|
+
subType: "Query",
|
|
991
|
+
param: {
|
|
992
|
+
dataDemand: demand
|
|
993
|
+
},
|
|
994
|
+
executor: (param) => __async(this, null, function* () {
|
|
995
|
+
let insightDump;
|
|
996
|
+
const dumpCollector = (dump) => {
|
|
997
|
+
insightDump = dump;
|
|
998
|
+
};
|
|
999
|
+
this.insight.onceDumpUpdatedFn = dumpCollector;
|
|
1000
|
+
const data = yield this.insight.extract(param.dataDemand);
|
|
1001
|
+
return {
|
|
1002
|
+
output: data,
|
|
1003
|
+
log: { dump: insightDump }
|
|
1004
|
+
};
|
|
1005
|
+
})
|
|
1006
|
+
};
|
|
1007
|
+
yield taskExecutor.append(this.wrapExecutorWithScreenshot(queryTask));
|
|
1008
|
+
const output = yield taskExecutor.flush();
|
|
1009
|
+
return {
|
|
1010
|
+
output,
|
|
1011
|
+
executor: taskExecutor
|
|
1012
|
+
};
|
|
1013
|
+
});
|
|
989
1014
|
}
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
(0, import_node_assert2.default)(checkIntervalMs, "No checkIntervalMs for waitFor");
|
|
997
|
-
const overallStartTime = Date.now();
|
|
998
|
-
let startTime = Date.now();
|
|
999
|
-
let errorThought = "";
|
|
1000
|
-
while (Date.now() - overallStartTime < timeoutMs) {
|
|
1001
|
-
startTime = Date.now();
|
|
1002
|
-
const assertPlan = {
|
|
1003
|
-
type: "AssertWithoutThrow",
|
|
1015
|
+
assert(assertion) {
|
|
1016
|
+
return __async(this, null, function* () {
|
|
1017
|
+
const description = `assert: ${assertion}`;
|
|
1018
|
+
const taskExecutor = new import_core.Executor(description);
|
|
1019
|
+
const assertionPlan = {
|
|
1020
|
+
type: "Assert",
|
|
1004
1021
|
param: {
|
|
1005
1022
|
assertion
|
|
1006
1023
|
}
|
|
1007
1024
|
};
|
|
1008
|
-
const assertTask =
|
|
1009
|
-
|
|
1010
|
-
const output =
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1025
|
+
const assertTask = yield this.convertPlanToExecutable([assertionPlan]);
|
|
1026
|
+
yield taskExecutor.append(this.wrapExecutorWithScreenshot(assertTask[0]));
|
|
1027
|
+
const output = yield taskExecutor.flush();
|
|
1028
|
+
return {
|
|
1029
|
+
output,
|
|
1030
|
+
executor: taskExecutor
|
|
1031
|
+
};
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
waitFor(assertion, opt) {
|
|
1035
|
+
return __async(this, null, function* () {
|
|
1036
|
+
const description = `waitFor: ${assertion}`;
|
|
1037
|
+
const taskExecutor = new import_core.Executor(description);
|
|
1038
|
+
const { timeoutMs, checkIntervalMs } = opt;
|
|
1039
|
+
(0, import_node_assert2.default)(assertion, "No assertion for waitFor");
|
|
1040
|
+
(0, import_node_assert2.default)(timeoutMs, "No timeoutMs for waitFor");
|
|
1041
|
+
(0, import_node_assert2.default)(checkIntervalMs, "No checkIntervalMs for waitFor");
|
|
1042
|
+
const overallStartTime = Date.now();
|
|
1043
|
+
let startTime = Date.now();
|
|
1044
|
+
let errorThought = "";
|
|
1045
|
+
while (Date.now() - overallStartTime < timeoutMs) {
|
|
1046
|
+
startTime = Date.now();
|
|
1047
|
+
const assertPlan = {
|
|
1048
|
+
type: "AssertWithoutThrow",
|
|
1023
1049
|
param: {
|
|
1024
|
-
|
|
1050
|
+
assertion
|
|
1025
1051
|
}
|
|
1026
1052
|
};
|
|
1027
|
-
const
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
)
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1053
|
+
const assertTask = yield this.convertPlanToExecutable([assertPlan]);
|
|
1054
|
+
yield taskExecutor.append(this.wrapExecutorWithScreenshot(assertTask[0]));
|
|
1055
|
+
const output = yield taskExecutor.flush();
|
|
1056
|
+
if (output == null ? void 0 : output.pass) {
|
|
1057
|
+
return {
|
|
1058
|
+
output: void 0,
|
|
1059
|
+
executor: taskExecutor
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1062
|
+
errorThought = (output == null ? void 0 : output.thought) || "unknown error";
|
|
1063
|
+
const now = Date.now();
|
|
1064
|
+
if (now - startTime < checkIntervalMs) {
|
|
1065
|
+
const timeRemaining = checkIntervalMs - (now - startTime);
|
|
1066
|
+
const sleepPlan = {
|
|
1067
|
+
type: "Sleep",
|
|
1068
|
+
param: {
|
|
1069
|
+
timeMs: timeRemaining
|
|
1070
|
+
}
|
|
1071
|
+
};
|
|
1072
|
+
const sleepTask = yield this.convertPlanToExecutable([sleepPlan]);
|
|
1073
|
+
yield taskExecutor.append(
|
|
1074
|
+
this.wrapExecutorWithScreenshot(sleepTask[0])
|
|
1075
|
+
);
|
|
1076
|
+
yield taskExecutor.flush();
|
|
1077
|
+
}
|
|
1038
1078
|
}
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1079
|
+
const errorPlan = {
|
|
1080
|
+
type: "Error",
|
|
1081
|
+
param: {
|
|
1082
|
+
thought: `waitFor timeout: ${errorThought}`
|
|
1083
|
+
}
|
|
1084
|
+
};
|
|
1085
|
+
const errorTask = yield this.convertPlanToExecutable([errorPlan]);
|
|
1086
|
+
yield taskExecutor.append(errorTask[0]);
|
|
1087
|
+
yield taskExecutor.flush();
|
|
1088
|
+
return {
|
|
1089
|
+
output: void 0,
|
|
1090
|
+
executor: taskExecutor
|
|
1091
|
+
};
|
|
1092
|
+
});
|
|
1047
1093
|
}
|
|
1048
1094
|
};
|
|
1049
1095
|
|
|
@@ -1077,169 +1123,206 @@ var PageAgent = class {
|
|
|
1077
1123
|
dumpDataString() {
|
|
1078
1124
|
this.dump.groupName = this.opts.groupName;
|
|
1079
1125
|
this.dump.groupDescription = this.opts.groupDescription;
|
|
1080
|
-
return (0,
|
|
1126
|
+
return (0, import_utils7.stringifyDumpData)(this.dump);
|
|
1081
1127
|
}
|
|
1082
1128
|
writeOutActionDumps() {
|
|
1083
1129
|
const { generateReport, autoPrintReportMsg } = this.opts;
|
|
1084
|
-
this.reportFile = (0,
|
|
1130
|
+
this.reportFile = (0, import_utils7.writeLogFile)({
|
|
1085
1131
|
fileName: this.reportFileName,
|
|
1086
|
-
fileExt:
|
|
1132
|
+
fileExt: import_utils7.groupedActionDumpFileExt,
|
|
1087
1133
|
fileContent: this.dumpDataString(),
|
|
1088
1134
|
type: "dump",
|
|
1089
1135
|
generateReport
|
|
1090
1136
|
});
|
|
1091
|
-
if (generateReport && autoPrintReportMsg) {
|
|
1137
|
+
if (generateReport && autoPrintReportMsg && this.reportFile) {
|
|
1092
1138
|
printReportMsg(this.reportFile);
|
|
1093
1139
|
}
|
|
1094
1140
|
}
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1141
|
+
aiAction(taskPrompt) {
|
|
1142
|
+
return __async(this, null, function* () {
|
|
1143
|
+
const { executor } = yield this.taskExecutor.action(taskPrompt);
|
|
1144
|
+
this.appendExecutionDump(executor.dump());
|
|
1145
|
+
this.writeOutActionDumps();
|
|
1146
|
+
if (executor.isInErrorState()) {
|
|
1147
|
+
const errorTask = executor.latestErrorTask();
|
|
1148
|
+
throw new Error(`${errorTask == null ? void 0 : errorTask.error}
|
|
1102
1149
|
${errorTask == null ? void 0 : errorTask.errorStack}`);
|
|
1103
|
-
|
|
1150
|
+
}
|
|
1151
|
+
});
|
|
1104
1152
|
}
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1153
|
+
aiQuery(demand) {
|
|
1154
|
+
return __async(this, null, function* () {
|
|
1155
|
+
const { output, executor } = yield this.taskExecutor.query(demand);
|
|
1156
|
+
this.appendExecutionDump(executor.dump());
|
|
1157
|
+
this.writeOutActionDumps();
|
|
1158
|
+
if (executor.isInErrorState()) {
|
|
1159
|
+
const errorTask = executor.latestErrorTask();
|
|
1160
|
+
throw new Error(`${errorTask == null ? void 0 : errorTask.error}
|
|
1112
1161
|
${errorTask == null ? void 0 : errorTask.errorStack}`);
|
|
1113
|
-
|
|
1114
|
-
return output;
|
|
1115
|
-
}
|
|
1116
|
-
async aiAssert(assertion, msg, opt) {
|
|
1117
|
-
const { output, executor } = await this.taskExecutor.assert(assertion);
|
|
1118
|
-
this.appendExecutionDump(executor.dump());
|
|
1119
|
-
this.writeOutActionDumps();
|
|
1120
|
-
if (opt == null ? void 0 : opt.keepRawResponse) {
|
|
1162
|
+
}
|
|
1121
1163
|
return output;
|
|
1122
|
-
}
|
|
1123
|
-
if (!(output == null ? void 0 : output.pass)) {
|
|
1124
|
-
const errMsg = msg || `Assertion failed: ${assertion}`;
|
|
1125
|
-
const reasonMsg = `Reason: ${(output == null ? void 0 : output.thought) || "(no_reason)"}`;
|
|
1126
|
-
throw new Error(`${errMsg}
|
|
1127
|
-
${reasonMsg}`);
|
|
1128
|
-
}
|
|
1164
|
+
});
|
|
1129
1165
|
}
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1166
|
+
aiAssert(assertion, msg, opt) {
|
|
1167
|
+
return __async(this, null, function* () {
|
|
1168
|
+
var _a;
|
|
1169
|
+
const { output, executor } = yield this.taskExecutor.assert(assertion);
|
|
1170
|
+
this.appendExecutionDump(executor.dump());
|
|
1171
|
+
this.writeOutActionDumps();
|
|
1172
|
+
if (opt == null ? void 0 : opt.keepRawResponse) {
|
|
1173
|
+
return output;
|
|
1174
|
+
}
|
|
1175
|
+
if (!(output == null ? void 0 : output.pass)) {
|
|
1176
|
+
const errMsg = msg || `Assertion failed: ${assertion}`;
|
|
1177
|
+
const reasonMsg = `Reason: ${(output == null ? void 0 : output.thought) || ((_a = executor.latestErrorTask()) == null ? void 0 : _a.error) || "(no_reason)"}`;
|
|
1178
|
+
throw new Error(`${errMsg}
|
|
1179
|
+
${reasonMsg}`);
|
|
1180
|
+
}
|
|
1135
1181
|
});
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
const
|
|
1140
|
-
|
|
1182
|
+
}
|
|
1183
|
+
aiWaitFor(assertion, opt) {
|
|
1184
|
+
return __async(this, null, function* () {
|
|
1185
|
+
const { executor } = yield this.taskExecutor.waitFor(assertion, {
|
|
1186
|
+
timeoutMs: (opt == null ? void 0 : opt.timeoutMs) || 15 * 1e3,
|
|
1187
|
+
checkIntervalMs: (opt == null ? void 0 : opt.checkIntervalMs) || 3 * 1e3,
|
|
1188
|
+
assertion
|
|
1189
|
+
});
|
|
1190
|
+
this.appendExecutionDump(executor.dump());
|
|
1191
|
+
this.writeOutActionDumps();
|
|
1192
|
+
if (executor.isInErrorState()) {
|
|
1193
|
+
const errorTask = executor.latestErrorTask();
|
|
1194
|
+
throw new Error(`${errorTask == null ? void 0 : errorTask.error}
|
|
1141
1195
|
${errorTask == null ? void 0 : errorTask.errorStack}`);
|
|
1142
|
-
|
|
1196
|
+
}
|
|
1197
|
+
});
|
|
1143
1198
|
}
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1199
|
+
ai(taskPrompt, type = "action") {
|
|
1200
|
+
return __async(this, null, function* () {
|
|
1201
|
+
if (type === "action") {
|
|
1202
|
+
return this.aiAction(taskPrompt);
|
|
1203
|
+
}
|
|
1204
|
+
if (type === "query") {
|
|
1205
|
+
return this.aiQuery(taskPrompt);
|
|
1206
|
+
}
|
|
1207
|
+
if (type === "assert") {
|
|
1208
|
+
return this.aiAssert(taskPrompt);
|
|
1209
|
+
}
|
|
1210
|
+
throw new Error(
|
|
1211
|
+
`Unknown type: ${type}, only support 'action', 'query', 'assert'`
|
|
1212
|
+
);
|
|
1213
|
+
});
|
|
1157
1214
|
}
|
|
1158
1215
|
};
|
|
1159
1216
|
|
|
1160
1217
|
// src/puppeteer/base-page.ts
|
|
1161
1218
|
var import_node_fs3 = require("fs");
|
|
1162
|
-
var
|
|
1163
|
-
var
|
|
1219
|
+
var import_utils9 = require("@midscene/core/utils");
|
|
1220
|
+
var import_img3 = require("@midscene/shared/img");
|
|
1164
1221
|
var Page = class {
|
|
1165
1222
|
evaluate(pageFunction, arg) {
|
|
1166
1223
|
if (this.pageType === "puppeteer") {
|
|
1167
|
-
return this.
|
|
1224
|
+
return this.underlyingPage.evaluate(pageFunction, arg);
|
|
1168
1225
|
}
|
|
1169
|
-
return this.
|
|
1226
|
+
return this.underlyingPage.evaluate(pageFunction, arg);
|
|
1170
1227
|
}
|
|
1171
|
-
constructor(
|
|
1172
|
-
this.
|
|
1228
|
+
constructor(underlyingPage, pageType) {
|
|
1229
|
+
this.underlyingPage = underlyingPage;
|
|
1173
1230
|
this.pageType = pageType;
|
|
1174
1231
|
}
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
async screenshot() {
|
|
1181
|
-
const viewportSize = await this.evaluate(() => {
|
|
1182
|
-
return {
|
|
1183
|
-
width: document.documentElement.clientWidth,
|
|
1184
|
-
height: document.documentElement.clientHeight,
|
|
1185
|
-
deviceScaleFactor: window.devicePixelRatio
|
|
1186
|
-
};
|
|
1187
|
-
});
|
|
1188
|
-
const path2 = (0, import_utils7.getTmpFile)("png");
|
|
1189
|
-
await this.page.screenshot({
|
|
1190
|
-
path: path2,
|
|
1191
|
-
type: "png"
|
|
1232
|
+
getElementInfos() {
|
|
1233
|
+
return __async(this, null, function* () {
|
|
1234
|
+
const scripts = yield getExtraReturnLogic();
|
|
1235
|
+
const captureElementSnapshot = yield this.evaluate(scripts);
|
|
1236
|
+
return captureElementSnapshot;
|
|
1192
1237
|
});
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1238
|
+
}
|
|
1239
|
+
screenshotBase64() {
|
|
1240
|
+
return __async(this, null, function* () {
|
|
1241
|
+
const viewportSize = yield this.evaluate(() => {
|
|
1242
|
+
return {
|
|
1243
|
+
width: document.documentElement.clientWidth,
|
|
1244
|
+
height: document.documentElement.clientHeight,
|
|
1245
|
+
deviceScaleFactor: window.devicePixelRatio
|
|
1246
|
+
};
|
|
1198
1247
|
});
|
|
1199
|
-
(0,
|
|
1200
|
-
|
|
1201
|
-
|
|
1248
|
+
const path2 = (0, import_utils9.getTmpFile)("png");
|
|
1249
|
+
yield this.underlyingPage.screenshot({
|
|
1250
|
+
path: path2,
|
|
1251
|
+
type: "png"
|
|
1252
|
+
});
|
|
1253
|
+
let buf;
|
|
1254
|
+
if (viewportSize.deviceScaleFactor > 1) {
|
|
1255
|
+
buf = yield (0, import_img3.resizeImg)((0, import_node_fs3.readFileSync)(path2), {
|
|
1256
|
+
width: viewportSize.width,
|
|
1257
|
+
height: viewportSize.height
|
|
1258
|
+
});
|
|
1259
|
+
(0, import_node_fs3.writeFileSync)(path2, buf);
|
|
1260
|
+
}
|
|
1261
|
+
return (0, import_img3.base64Encoded)(path2, true);
|
|
1262
|
+
});
|
|
1202
1263
|
}
|
|
1203
1264
|
url() {
|
|
1204
|
-
return this.
|
|
1265
|
+
return this.underlyingPage.url();
|
|
1205
1266
|
}
|
|
1206
1267
|
get mouse() {
|
|
1207
1268
|
return {
|
|
1208
|
-
click:
|
|
1209
|
-
|
|
1269
|
+
click: (x, y, options) => __async(this, null, function* () {
|
|
1270
|
+
return this.underlyingPage.mouse.click(x, y, {
|
|
1271
|
+
button: (options == null ? void 0 : options.button) || "left"
|
|
1272
|
+
});
|
|
1273
|
+
}),
|
|
1274
|
+
wheel: (deltaX, deltaY) => __async(this, null, function* () {
|
|
1210
1275
|
if (this.pageType === "puppeteer") {
|
|
1211
|
-
|
|
1276
|
+
yield this.underlyingPage.mouse.wheel({
|
|
1277
|
+
deltaX,
|
|
1278
|
+
deltaY
|
|
1279
|
+
});
|
|
1212
1280
|
} else if (this.pageType === "playwright") {
|
|
1213
|
-
|
|
1281
|
+
yield this.underlyingPage.mouse.wheel(
|
|
1282
|
+
deltaX,
|
|
1283
|
+
deltaY
|
|
1284
|
+
);
|
|
1214
1285
|
}
|
|
1215
|
-
},
|
|
1216
|
-
move:
|
|
1286
|
+
}),
|
|
1287
|
+
move: (x, y) => __async(this, null, function* () {
|
|
1288
|
+
return this.underlyingPage.mouse.move(x, y);
|
|
1289
|
+
})
|
|
1217
1290
|
};
|
|
1218
1291
|
}
|
|
1219
1292
|
get keyboard() {
|
|
1220
1293
|
return {
|
|
1221
|
-
type:
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1294
|
+
type: (text) => __async(this, null, function* () {
|
|
1295
|
+
return this.underlyingPage.keyboard.type(text);
|
|
1296
|
+
}),
|
|
1297
|
+
press: (key) => __async(this, null, function* () {
|
|
1298
|
+
return this.underlyingPage.keyboard.press(key);
|
|
1299
|
+
}),
|
|
1300
|
+
down: (key) => __async(this, null, function* () {
|
|
1301
|
+
return this.underlyingPage.keyboard.down(key);
|
|
1302
|
+
}),
|
|
1303
|
+
up: (key) => __async(this, null, function* () {
|
|
1304
|
+
return this.underlyingPage.keyboard.up(key);
|
|
1305
|
+
})
|
|
1225
1306
|
};
|
|
1226
1307
|
}
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1308
|
+
clearInput(element) {
|
|
1309
|
+
return __async(this, null, function* () {
|
|
1310
|
+
if (!element) {
|
|
1311
|
+
return;
|
|
1312
|
+
}
|
|
1313
|
+
yield this.mouse.click(element.center[0], element.center[1]);
|
|
1314
|
+
const isMac = process.platform === "darwin";
|
|
1315
|
+
if (isMac) {
|
|
1316
|
+
yield this.underlyingPage.keyboard.down("Meta");
|
|
1317
|
+
yield this.underlyingPage.keyboard.press("a");
|
|
1318
|
+
yield this.underlyingPage.keyboard.up("Meta");
|
|
1319
|
+
} else {
|
|
1320
|
+
yield this.underlyingPage.keyboard.down("Control");
|
|
1321
|
+
yield this.underlyingPage.keyboard.press("a");
|
|
1322
|
+
yield this.underlyingPage.keyboard.up("Control");
|
|
1323
|
+
}
|
|
1324
|
+
yield this.keyboard.press("Backspace");
|
|
1325
|
+
});
|
|
1243
1326
|
}
|
|
1244
1327
|
scrollUntilTop() {
|
|
1245
1328
|
return this.mouse.wheel(0, -9999999);
|
|
@@ -1247,15 +1330,19 @@ var Page = class {
|
|
|
1247
1330
|
scrollUntilBottom() {
|
|
1248
1331
|
return this.mouse.wheel(0, 9999999);
|
|
1249
1332
|
}
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1333
|
+
scrollUpOneScreen() {
|
|
1334
|
+
return __async(this, null, function* () {
|
|
1335
|
+
const innerHeight = yield this.evaluate(() => window.innerHeight);
|
|
1336
|
+
const distance = innerHeight * 0.7;
|
|
1337
|
+
yield this.mouse.wheel(0, -distance);
|
|
1338
|
+
});
|
|
1254
1339
|
}
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1340
|
+
scrollDownOneScreen() {
|
|
1341
|
+
return __async(this, null, function* () {
|
|
1342
|
+
const innerHeight = yield this.evaluate(() => window.innerHeight);
|
|
1343
|
+
const distance = innerHeight * 0.7;
|
|
1344
|
+
yield this.mouse.wheel(0, distance);
|
|
1345
|
+
});
|
|
1259
1346
|
}
|
|
1260
1347
|
};
|
|
1261
1348
|
|