@midscene/web 0.3.0 → 0.3.1-beta-20240821105917.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/LICENSE +1 -1
- package/dist/es/index.js +118 -19
- package/dist/lib/index.js +118 -19
- package/dist/script/htmlElement.js +83 -53
- package/dist/script/htmlElementDebug.js +880 -0
- package/dist/script/types/htmlElement.d.ts +5 -3
- package/dist/script/types/htmlElementDebug.d.ts +2 -0
- package/dist/types/index.d.ts +10 -2
- package/package.json +6 -5
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2024-present Bytedance, Inc. and its affiliates.
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/dist/es/index.js
CHANGED
|
@@ -483,17 +483,24 @@ async function alignElements(screenshotBuffer, elements, page) {
|
|
|
483
483
|
return item.rect.height >= sizeThreshold && item.rect.width >= sizeThreshold;
|
|
484
484
|
});
|
|
485
485
|
for (const item of validElements) {
|
|
486
|
-
const { rect } = item;
|
|
486
|
+
const { rect, id, content, attributes, locator } = item;
|
|
487
487
|
const aligned = await alignCoordByTrim(screenshotBuffer, rect);
|
|
488
|
+
if (aligned.width < 0)
|
|
489
|
+
continue;
|
|
488
490
|
item.rect = aligned;
|
|
489
491
|
item.center = [
|
|
490
492
|
Math.round(aligned.left + aligned.width / 2),
|
|
491
493
|
Math.round(aligned.top + aligned.height / 2)
|
|
492
494
|
];
|
|
493
495
|
textsAligned.push(
|
|
494
|
-
new WebElementInfo(
|
|
496
|
+
new WebElementInfo({
|
|
497
|
+
rect,
|
|
498
|
+
locator,
|
|
499
|
+
id,
|
|
500
|
+
content,
|
|
501
|
+
attributes,
|
|
495
502
|
page
|
|
496
|
-
})
|
|
503
|
+
})
|
|
497
504
|
);
|
|
498
505
|
}
|
|
499
506
|
return textsAligned;
|
|
@@ -617,7 +624,7 @@ var PageTaskExecutor = class {
|
|
|
617
624
|
};
|
|
618
625
|
return taskFind;
|
|
619
626
|
}
|
|
620
|
-
if (plan2.type === "Assert") {
|
|
627
|
+
if (plan2.type === "Assert" || plan2.type === "AssertWithoutThrow") {
|
|
621
628
|
const assertPlan = plan2;
|
|
622
629
|
const taskAssert = {
|
|
623
630
|
type: "Insight",
|
|
@@ -634,13 +641,16 @@ var PageTaskExecutor = class {
|
|
|
634
641
|
assertPlan.param.assertion
|
|
635
642
|
);
|
|
636
643
|
if (!assertion.pass) {
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
+
if (plan2.type === "Assert") {
|
|
645
|
+
task.output = assertion;
|
|
646
|
+
task.log = {
|
|
647
|
+
dump: insightDump
|
|
648
|
+
};
|
|
649
|
+
throw new Error(
|
|
650
|
+
assertion.thought || "Assertion failed without reason"
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
task.error = assertion.thought;
|
|
644
654
|
}
|
|
645
655
|
return {
|
|
646
656
|
output: assertion,
|
|
@@ -756,7 +766,19 @@ var PageTaskExecutor = class {
|
|
|
756
766
|
return taskActionSleep;
|
|
757
767
|
}
|
|
758
768
|
if (plan2.type === "Error") {
|
|
759
|
-
|
|
769
|
+
const taskActionError = {
|
|
770
|
+
type: "Action",
|
|
771
|
+
subType: "Error",
|
|
772
|
+
param: plan2.param,
|
|
773
|
+
executor: async (taskParam) => {
|
|
774
|
+
assert2(
|
|
775
|
+
taskParam.thought,
|
|
776
|
+
"An error occurred, but no thought provided"
|
|
777
|
+
);
|
|
778
|
+
throw new Error(taskParam.thought);
|
|
779
|
+
}
|
|
780
|
+
};
|
|
781
|
+
return taskActionError;
|
|
760
782
|
}
|
|
761
783
|
throw new Error(`Unknown or Unsupported task type: ${plan2.type}`);
|
|
762
784
|
}).map((task) => {
|
|
@@ -766,7 +788,6 @@ var PageTaskExecutor = class {
|
|
|
766
788
|
}
|
|
767
789
|
async action(userPrompt) {
|
|
768
790
|
const taskExecutor = new Executor(userPrompt);
|
|
769
|
-
taskExecutor.description = userPrompt;
|
|
770
791
|
let plans = [];
|
|
771
792
|
const planningTask = {
|
|
772
793
|
type: "Planning",
|
|
@@ -826,7 +847,6 @@ var PageTaskExecutor = class {
|
|
|
826
847
|
async query(demand) {
|
|
827
848
|
const description = typeof demand === "string" ? demand : JSON.stringify(demand);
|
|
828
849
|
const taskExecutor = new Executor(description);
|
|
829
|
-
taskExecutor.description = description;
|
|
830
850
|
const queryTask = {
|
|
831
851
|
type: "Insight",
|
|
832
852
|
subType: "Query",
|
|
@@ -854,9 +874,8 @@ var PageTaskExecutor = class {
|
|
|
854
874
|
};
|
|
855
875
|
}
|
|
856
876
|
async assert(assertion) {
|
|
857
|
-
const description = assertion
|
|
877
|
+
const description = `assert: ${assertion}`;
|
|
858
878
|
const taskExecutor = new Executor(description);
|
|
859
|
-
taskExecutor.description = description;
|
|
860
879
|
const assertionPlan = {
|
|
861
880
|
type: "Assert",
|
|
862
881
|
param: {
|
|
@@ -871,6 +890,64 @@ var PageTaskExecutor = class {
|
|
|
871
890
|
executor: taskExecutor
|
|
872
891
|
};
|
|
873
892
|
}
|
|
893
|
+
async waitFor(assertion, opt) {
|
|
894
|
+
const description = `waitFor: ${assertion}`;
|
|
895
|
+
const taskExecutor = new Executor(description);
|
|
896
|
+
const { timeoutMs, checkIntervalMs } = opt;
|
|
897
|
+
assert2(assertion, "No assertion for waitFor");
|
|
898
|
+
assert2(timeoutMs, "No timeoutMs for waitFor");
|
|
899
|
+
assert2(checkIntervalMs, "No checkIntervalMs for waitFor");
|
|
900
|
+
const overallStartTime = Date.now();
|
|
901
|
+
let startTime = Date.now();
|
|
902
|
+
let errorThought = "";
|
|
903
|
+
while (Date.now() - overallStartTime < timeoutMs) {
|
|
904
|
+
startTime = Date.now();
|
|
905
|
+
const assertPlan = {
|
|
906
|
+
type: "AssertWithoutThrow",
|
|
907
|
+
param: {
|
|
908
|
+
assertion
|
|
909
|
+
}
|
|
910
|
+
};
|
|
911
|
+
const assertTask = await this.convertPlanToExecutable([assertPlan]);
|
|
912
|
+
await taskExecutor.append(this.wrapExecutorWithScreenshot(assertTask[0]));
|
|
913
|
+
const output = await taskExecutor.flush();
|
|
914
|
+
if (output.pass) {
|
|
915
|
+
return {
|
|
916
|
+
output: void 0,
|
|
917
|
+
executor: taskExecutor
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
errorThought = output.thought;
|
|
921
|
+
const now = Date.now();
|
|
922
|
+
if (now - startTime < checkIntervalMs) {
|
|
923
|
+
const timeRemaining = checkIntervalMs - (now - startTime);
|
|
924
|
+
const sleepPlan = {
|
|
925
|
+
type: "Sleep",
|
|
926
|
+
param: {
|
|
927
|
+
timeMs: timeRemaining
|
|
928
|
+
}
|
|
929
|
+
};
|
|
930
|
+
const sleepTask = await this.convertPlanToExecutable([sleepPlan]);
|
|
931
|
+
await taskExecutor.append(
|
|
932
|
+
this.wrapExecutorWithScreenshot(sleepTask[0])
|
|
933
|
+
);
|
|
934
|
+
await taskExecutor.flush();
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
const errorPlan = {
|
|
938
|
+
type: "Error",
|
|
939
|
+
param: {
|
|
940
|
+
thought: `waitFor timeout: ${errorThought}`
|
|
941
|
+
}
|
|
942
|
+
};
|
|
943
|
+
const errorTask = await this.convertPlanToExecutable([errorPlan]);
|
|
944
|
+
await taskExecutor.append(errorTask[0]);
|
|
945
|
+
await taskExecutor.flush();
|
|
946
|
+
return {
|
|
947
|
+
output: void 0,
|
|
948
|
+
executor: taskExecutor
|
|
949
|
+
};
|
|
950
|
+
}
|
|
874
951
|
};
|
|
875
952
|
|
|
876
953
|
// src/common/agent.ts
|
|
@@ -880,6 +957,7 @@ var PageAgent = class {
|
|
|
880
957
|
this.opts = Object.assign(
|
|
881
958
|
{
|
|
882
959
|
generateReport: true,
|
|
960
|
+
autoPrintReportMsg: true,
|
|
883
961
|
groupName: "Midscene Report",
|
|
884
962
|
groupDescription: ""
|
|
885
963
|
},
|
|
@@ -905,7 +983,7 @@ var PageAgent = class {
|
|
|
905
983
|
return stringifyDumpData(this.dump);
|
|
906
984
|
}
|
|
907
985
|
writeOutActionDumps() {
|
|
908
|
-
const generateReport = this.opts
|
|
986
|
+
const { generateReport, autoPrintReportMsg } = this.opts;
|
|
909
987
|
this.reportFile = writeLogFile({
|
|
910
988
|
fileName: this.reportFileName,
|
|
911
989
|
fileExt: groupedActionDumpFileExt,
|
|
@@ -913,7 +991,7 @@ var PageAgent = class {
|
|
|
913
991
|
type: "dump",
|
|
914
992
|
generateReport
|
|
915
993
|
});
|
|
916
|
-
if (generateReport) {
|
|
994
|
+
if (generateReport && autoPrintReportMsg) {
|
|
917
995
|
printReportMsg(this.reportFile);
|
|
918
996
|
}
|
|
919
997
|
}
|
|
@@ -944,11 +1022,25 @@ ${errorTask == null ? void 0 : errorTask.errorStack}`);
|
|
|
944
1022
|
this.writeOutActionDumps();
|
|
945
1023
|
if (!(output == null ? void 0 : output.pass)) {
|
|
946
1024
|
const errMsg = msg || `Assertion failed: ${assertion}`;
|
|
947
|
-
const reasonMsg = `Reason: ${output == null ? void 0 : output.thought
|
|
1025
|
+
const reasonMsg = `Reason: ${(output == null ? void 0 : output.thought) || "(no_reason)"}`;
|
|
948
1026
|
throw new Error(`${errMsg}
|
|
949
1027
|
${reasonMsg}`);
|
|
950
1028
|
}
|
|
951
1029
|
}
|
|
1030
|
+
async aiWaitFor(assertion, opt) {
|
|
1031
|
+
const { executor } = await this.taskExecutor.waitFor(assertion, {
|
|
1032
|
+
timeoutMs: (opt == null ? void 0 : opt.timeoutMs) || 15 * 1e3,
|
|
1033
|
+
checkIntervalMs: (opt == null ? void 0 : opt.checkIntervalMs) || 3 * 1e3,
|
|
1034
|
+
assertion
|
|
1035
|
+
});
|
|
1036
|
+
this.appendExecutionDump(executor.dump());
|
|
1037
|
+
this.writeOutActionDumps();
|
|
1038
|
+
if (executor.isInErrorState()) {
|
|
1039
|
+
const errorTask = executor.latestErrorTask();
|
|
1040
|
+
throw new Error(`${errorTask == null ? void 0 : errorTask.error}
|
|
1041
|
+
${errorTask == null ? void 0 : errorTask.errorStack}`);
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
952
1044
|
async ai(taskPrompt, type = "action") {
|
|
953
1045
|
if (type === "action") {
|
|
954
1046
|
return this.aiAction(taskPrompt);
|
|
@@ -1124,6 +1216,13 @@ var PlaywrightAiFixture = () => {
|
|
|
1124
1216
|
await agent.aiAssert(assertion, errorMsg);
|
|
1125
1217
|
});
|
|
1126
1218
|
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
1219
|
+
},
|
|
1220
|
+
aiWaitFor: async ({ page }, use, testInfo) => {
|
|
1221
|
+
const agent = agentForPage(page, testInfo);
|
|
1222
|
+
await use(async (assertion, opt) => {
|
|
1223
|
+
await agent.aiWaitFor(assertion, opt);
|
|
1224
|
+
});
|
|
1225
|
+
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
1127
1226
|
}
|
|
1128
1227
|
};
|
|
1129
1228
|
};
|
package/dist/lib/index.js
CHANGED
|
@@ -486,17 +486,24 @@ async function alignElements(screenshotBuffer, elements, page) {
|
|
|
486
486
|
return item.rect.height >= sizeThreshold && item.rect.width >= sizeThreshold;
|
|
487
487
|
});
|
|
488
488
|
for (const item of validElements) {
|
|
489
|
-
const { rect } = item;
|
|
489
|
+
const { rect, id, content, attributes, locator } = item;
|
|
490
490
|
const aligned = await (0, import_image.alignCoordByTrim)(screenshotBuffer, rect);
|
|
491
|
+
if (aligned.width < 0)
|
|
492
|
+
continue;
|
|
491
493
|
item.rect = aligned;
|
|
492
494
|
item.center = [
|
|
493
495
|
Math.round(aligned.left + aligned.width / 2),
|
|
494
496
|
Math.round(aligned.top + aligned.height / 2)
|
|
495
497
|
];
|
|
496
498
|
textsAligned.push(
|
|
497
|
-
new WebElementInfo(
|
|
499
|
+
new WebElementInfo({
|
|
500
|
+
rect,
|
|
501
|
+
locator,
|
|
502
|
+
id,
|
|
503
|
+
content,
|
|
504
|
+
attributes,
|
|
498
505
|
page
|
|
499
|
-
})
|
|
506
|
+
})
|
|
500
507
|
);
|
|
501
508
|
}
|
|
502
509
|
return textsAligned;
|
|
@@ -620,7 +627,7 @@ var PageTaskExecutor = class {
|
|
|
620
627
|
};
|
|
621
628
|
return taskFind;
|
|
622
629
|
}
|
|
623
|
-
if (plan2.type === "Assert") {
|
|
630
|
+
if (plan2.type === "Assert" || plan2.type === "AssertWithoutThrow") {
|
|
624
631
|
const assertPlan = plan2;
|
|
625
632
|
const taskAssert = {
|
|
626
633
|
type: "Insight",
|
|
@@ -637,13 +644,16 @@ var PageTaskExecutor = class {
|
|
|
637
644
|
assertPlan.param.assertion
|
|
638
645
|
);
|
|
639
646
|
if (!assertion.pass) {
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
+
if (plan2.type === "Assert") {
|
|
648
|
+
task.output = assertion;
|
|
649
|
+
task.log = {
|
|
650
|
+
dump: insightDump
|
|
651
|
+
};
|
|
652
|
+
throw new Error(
|
|
653
|
+
assertion.thought || "Assertion failed without reason"
|
|
654
|
+
);
|
|
655
|
+
}
|
|
656
|
+
task.error = assertion.thought;
|
|
647
657
|
}
|
|
648
658
|
return {
|
|
649
659
|
output: assertion,
|
|
@@ -759,7 +769,19 @@ var PageTaskExecutor = class {
|
|
|
759
769
|
return taskActionSleep;
|
|
760
770
|
}
|
|
761
771
|
if (plan2.type === "Error") {
|
|
762
|
-
|
|
772
|
+
const taskActionError = {
|
|
773
|
+
type: "Action",
|
|
774
|
+
subType: "Error",
|
|
775
|
+
param: plan2.param,
|
|
776
|
+
executor: async (taskParam) => {
|
|
777
|
+
(0, import_node_assert2.default)(
|
|
778
|
+
taskParam.thought,
|
|
779
|
+
"An error occurred, but no thought provided"
|
|
780
|
+
);
|
|
781
|
+
throw new Error(taskParam.thought);
|
|
782
|
+
}
|
|
783
|
+
};
|
|
784
|
+
return taskActionError;
|
|
763
785
|
}
|
|
764
786
|
throw new Error(`Unknown or Unsupported task type: ${plan2.type}`);
|
|
765
787
|
}).map((task) => {
|
|
@@ -769,7 +791,6 @@ var PageTaskExecutor = class {
|
|
|
769
791
|
}
|
|
770
792
|
async action(userPrompt) {
|
|
771
793
|
const taskExecutor = new import_core.Executor(userPrompt);
|
|
772
|
-
taskExecutor.description = userPrompt;
|
|
773
794
|
let plans = [];
|
|
774
795
|
const planningTask = {
|
|
775
796
|
type: "Planning",
|
|
@@ -829,7 +850,6 @@ var PageTaskExecutor = class {
|
|
|
829
850
|
async query(demand) {
|
|
830
851
|
const description = typeof demand === "string" ? demand : JSON.stringify(demand);
|
|
831
852
|
const taskExecutor = new import_core.Executor(description);
|
|
832
|
-
taskExecutor.description = description;
|
|
833
853
|
const queryTask = {
|
|
834
854
|
type: "Insight",
|
|
835
855
|
subType: "Query",
|
|
@@ -857,9 +877,8 @@ var PageTaskExecutor = class {
|
|
|
857
877
|
};
|
|
858
878
|
}
|
|
859
879
|
async assert(assertion) {
|
|
860
|
-
const description = assertion
|
|
880
|
+
const description = `assert: ${assertion}`;
|
|
861
881
|
const taskExecutor = new import_core.Executor(description);
|
|
862
|
-
taskExecutor.description = description;
|
|
863
882
|
const assertionPlan = {
|
|
864
883
|
type: "Assert",
|
|
865
884
|
param: {
|
|
@@ -874,6 +893,64 @@ var PageTaskExecutor = class {
|
|
|
874
893
|
executor: taskExecutor
|
|
875
894
|
};
|
|
876
895
|
}
|
|
896
|
+
async waitFor(assertion, opt) {
|
|
897
|
+
const description = `waitFor: ${assertion}`;
|
|
898
|
+
const taskExecutor = new import_core.Executor(description);
|
|
899
|
+
const { timeoutMs, checkIntervalMs } = opt;
|
|
900
|
+
(0, import_node_assert2.default)(assertion, "No assertion for waitFor");
|
|
901
|
+
(0, import_node_assert2.default)(timeoutMs, "No timeoutMs for waitFor");
|
|
902
|
+
(0, import_node_assert2.default)(checkIntervalMs, "No checkIntervalMs for waitFor");
|
|
903
|
+
const overallStartTime = Date.now();
|
|
904
|
+
let startTime = Date.now();
|
|
905
|
+
let errorThought = "";
|
|
906
|
+
while (Date.now() - overallStartTime < timeoutMs) {
|
|
907
|
+
startTime = Date.now();
|
|
908
|
+
const assertPlan = {
|
|
909
|
+
type: "AssertWithoutThrow",
|
|
910
|
+
param: {
|
|
911
|
+
assertion
|
|
912
|
+
}
|
|
913
|
+
};
|
|
914
|
+
const assertTask = await this.convertPlanToExecutable([assertPlan]);
|
|
915
|
+
await taskExecutor.append(this.wrapExecutorWithScreenshot(assertTask[0]));
|
|
916
|
+
const output = await taskExecutor.flush();
|
|
917
|
+
if (output.pass) {
|
|
918
|
+
return {
|
|
919
|
+
output: void 0,
|
|
920
|
+
executor: taskExecutor
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
errorThought = output.thought;
|
|
924
|
+
const now = Date.now();
|
|
925
|
+
if (now - startTime < checkIntervalMs) {
|
|
926
|
+
const timeRemaining = checkIntervalMs - (now - startTime);
|
|
927
|
+
const sleepPlan = {
|
|
928
|
+
type: "Sleep",
|
|
929
|
+
param: {
|
|
930
|
+
timeMs: timeRemaining
|
|
931
|
+
}
|
|
932
|
+
};
|
|
933
|
+
const sleepTask = await this.convertPlanToExecutable([sleepPlan]);
|
|
934
|
+
await taskExecutor.append(
|
|
935
|
+
this.wrapExecutorWithScreenshot(sleepTask[0])
|
|
936
|
+
);
|
|
937
|
+
await taskExecutor.flush();
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
const errorPlan = {
|
|
941
|
+
type: "Error",
|
|
942
|
+
param: {
|
|
943
|
+
thought: `waitFor timeout: ${errorThought}`
|
|
944
|
+
}
|
|
945
|
+
};
|
|
946
|
+
const errorTask = await this.convertPlanToExecutable([errorPlan]);
|
|
947
|
+
await taskExecutor.append(errorTask[0]);
|
|
948
|
+
await taskExecutor.flush();
|
|
949
|
+
return {
|
|
950
|
+
output: void 0,
|
|
951
|
+
executor: taskExecutor
|
|
952
|
+
};
|
|
953
|
+
}
|
|
877
954
|
};
|
|
878
955
|
|
|
879
956
|
// src/common/agent.ts
|
|
@@ -883,6 +960,7 @@ var PageAgent = class {
|
|
|
883
960
|
this.opts = Object.assign(
|
|
884
961
|
{
|
|
885
962
|
generateReport: true,
|
|
963
|
+
autoPrintReportMsg: true,
|
|
886
964
|
groupName: "Midscene Report",
|
|
887
965
|
groupDescription: ""
|
|
888
966
|
},
|
|
@@ -908,7 +986,7 @@ var PageAgent = class {
|
|
|
908
986
|
return (0, import_utils4.stringifyDumpData)(this.dump);
|
|
909
987
|
}
|
|
910
988
|
writeOutActionDumps() {
|
|
911
|
-
const generateReport = this.opts
|
|
989
|
+
const { generateReport, autoPrintReportMsg } = this.opts;
|
|
912
990
|
this.reportFile = (0, import_utils4.writeLogFile)({
|
|
913
991
|
fileName: this.reportFileName,
|
|
914
992
|
fileExt: import_utils4.groupedActionDumpFileExt,
|
|
@@ -916,7 +994,7 @@ var PageAgent = class {
|
|
|
916
994
|
type: "dump",
|
|
917
995
|
generateReport
|
|
918
996
|
});
|
|
919
|
-
if (generateReport) {
|
|
997
|
+
if (generateReport && autoPrintReportMsg) {
|
|
920
998
|
printReportMsg(this.reportFile);
|
|
921
999
|
}
|
|
922
1000
|
}
|
|
@@ -947,11 +1025,25 @@ ${errorTask == null ? void 0 : errorTask.errorStack}`);
|
|
|
947
1025
|
this.writeOutActionDumps();
|
|
948
1026
|
if (!(output == null ? void 0 : output.pass)) {
|
|
949
1027
|
const errMsg = msg || `Assertion failed: ${assertion}`;
|
|
950
|
-
const reasonMsg = `Reason: ${output == null ? void 0 : output.thought
|
|
1028
|
+
const reasonMsg = `Reason: ${(output == null ? void 0 : output.thought) || "(no_reason)"}`;
|
|
951
1029
|
throw new Error(`${errMsg}
|
|
952
1030
|
${reasonMsg}`);
|
|
953
1031
|
}
|
|
954
1032
|
}
|
|
1033
|
+
async aiWaitFor(assertion, opt) {
|
|
1034
|
+
const { executor } = await this.taskExecutor.waitFor(assertion, {
|
|
1035
|
+
timeoutMs: (opt == null ? void 0 : opt.timeoutMs) || 15 * 1e3,
|
|
1036
|
+
checkIntervalMs: (opt == null ? void 0 : opt.checkIntervalMs) || 3 * 1e3,
|
|
1037
|
+
assertion
|
|
1038
|
+
});
|
|
1039
|
+
this.appendExecutionDump(executor.dump());
|
|
1040
|
+
this.writeOutActionDumps();
|
|
1041
|
+
if (executor.isInErrorState()) {
|
|
1042
|
+
const errorTask = executor.latestErrorTask();
|
|
1043
|
+
throw new Error(`${errorTask == null ? void 0 : errorTask.error}
|
|
1044
|
+
${errorTask == null ? void 0 : errorTask.errorStack}`);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
955
1047
|
async ai(taskPrompt, type = "action") {
|
|
956
1048
|
if (type === "action") {
|
|
957
1049
|
return this.aiAction(taskPrompt);
|
|
@@ -1123,6 +1215,13 @@ var PlaywrightAiFixture = () => {
|
|
|
1123
1215
|
await agent.aiAssert(assertion, errorMsg);
|
|
1124
1216
|
});
|
|
1125
1217
|
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
1218
|
+
},
|
|
1219
|
+
aiWaitFor: async ({ page }, use, testInfo) => {
|
|
1220
|
+
const agent = agentForPage(page, testInfo);
|
|
1221
|
+
await use(async (assertion, opt) => {
|
|
1222
|
+
await agent.aiWaitFor(assertion, opt);
|
|
1223
|
+
});
|
|
1224
|
+
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
1126
1225
|
}
|
|
1127
1226
|
};
|
|
1128
1227
|
};
|