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