@midscene/web 0.11.1 → 0.11.2
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/es/appium.js +84 -39
- package/dist/es/bridge-mode-browser.js +58 -19
- package/dist/es/bridge-mode.js +61 -43
- package/dist/es/chrome-extension.js +104 -51
- package/dist/es/index.js +291 -218
- package/dist/es/midscene-playground.js +56 -38
- package/dist/es/playground.js +56 -38
- package/dist/es/playwright.js +251 -203
- package/dist/es/puppeteer.js +85 -60
- package/dist/es/ui-utils.js +43 -0
- package/dist/lib/appium.js +84 -39
- package/dist/lib/bridge-mode-browser.js +58 -19
- package/dist/lib/bridge-mode.js +61 -43
- package/dist/lib/chrome-extension.js +104 -51
- package/dist/lib/index.js +291 -218
- package/dist/lib/midscene-playground.js +56 -38
- package/dist/lib/playground.js +56 -38
- package/dist/lib/playwright.js +251 -203
- package/dist/lib/puppeteer.js +85 -60
- package/dist/lib/ui-utils.js +43 -0
- package/dist/types/{tasks-d5a01262.d.ts → agent-ac363fa3.d.ts} +41 -41
- package/dist/types/appium.d.ts +2 -2
- package/dist/types/bridge-mode-browser.d.ts +2 -2
- package/dist/types/bridge-mode.d.ts +3 -3
- package/dist/types/{browser-7d5614fb.d.ts → browser-eae1a5c1.d.ts} +4 -4
- package/dist/types/chrome-extension.d.ts +3 -3
- package/dist/types/index.d.ts +8 -8
- package/dist/types/{page-77af8d5f.d.ts → page-cf0f892e.d.ts} +32 -6
- package/dist/types/playground.d.ts +3 -3
- package/dist/types/playwright.d.ts +12 -6
- package/dist/types/puppeteer.d.ts +2 -2
- package/dist/types/ui-utils.d.ts +6 -1
- package/dist/types/{utils-1a3bc661.d.ts → utils-9a29bfa0.d.ts} +1 -1
- package/dist/types/utils.d.ts +1 -1
- package/dist/types/yaml.d.ts +3 -3
- package/package.json +6 -6
package/dist/es/index.js
CHANGED
|
@@ -330,7 +330,7 @@ var src_exports = {};
|
|
|
330
330
|
__export(src_exports, {
|
|
331
331
|
AppiumAgent: () => PageAgent,
|
|
332
332
|
AppiumPage: () => Page2,
|
|
333
|
-
PlaywrightAgent: () =>
|
|
333
|
+
PlaywrightAgent: () => PlaywrightAgent,
|
|
334
334
|
PlaywrightAiFixture: () => PlaywrightAiFixture,
|
|
335
335
|
PuppeteerAgent: () => PuppeteerAgent,
|
|
336
336
|
ScriptPlayer: () => ScriptPlayer,
|
|
@@ -340,9 +340,6 @@ __export(src_exports, {
|
|
|
340
340
|
});
|
|
341
341
|
module.exports = __toCommonJS(src_exports);
|
|
342
342
|
|
|
343
|
-
// src/playwright/ai-fixture.ts
|
|
344
|
-
var import_node_crypto = require("crypto");
|
|
345
|
-
|
|
346
343
|
// src/common/agent.ts
|
|
347
344
|
var import_core2 = require("@midscene/core");
|
|
348
345
|
var import_constants2 = require("@midscene/shared/constants");
|
|
@@ -3407,7 +3404,9 @@ var TaskCache = class {
|
|
|
3407
3404
|
if (!this.midscenePkgInfo) {
|
|
3408
3405
|
return void 0;
|
|
3409
3406
|
}
|
|
3410
|
-
|
|
3407
|
+
const jsonDataPkgVersion = jsonData.pkgVersion.split(".");
|
|
3408
|
+
const midscenePkgInfoPkgVersion = this.midscenePkgInfo.version.split(".");
|
|
3409
|
+
if (jsonDataPkgVersion[0] !== midscenePkgInfoPkgVersion[0] || jsonDataPkgVersion[1] !== midscenePkgInfoPkgVersion[1]) {
|
|
3411
3410
|
return void 0;
|
|
3412
3411
|
}
|
|
3413
3412
|
return jsonData;
|
|
@@ -3441,6 +3440,56 @@ var TaskCache = class {
|
|
|
3441
3440
|
}
|
|
3442
3441
|
};
|
|
3443
3442
|
|
|
3443
|
+
// src/common/ui-utils.ts
|
|
3444
|
+
function typeStr(task) {
|
|
3445
|
+
return task.subType ? `${task.type} / ${task.subType || ""}` : task.type;
|
|
3446
|
+
}
|
|
3447
|
+
function getKeyCommands(value) {
|
|
3448
|
+
const keys = Array.isArray(value) ? value : [value];
|
|
3449
|
+
return keys.reduce((acc, k) => {
|
|
3450
|
+
const includeMeta = keys.includes("Meta") || keys.includes("Control");
|
|
3451
|
+
if (includeMeta && (k === "a" || k === "A")) {
|
|
3452
|
+
return acc.concat([{ key: k, command: "SelectAll" }]);
|
|
3453
|
+
}
|
|
3454
|
+
if (includeMeta && (k === "c" || k === "C")) {
|
|
3455
|
+
return acc.concat([{ key: k, command: "Copy" }]);
|
|
3456
|
+
}
|
|
3457
|
+
if (includeMeta && (k === "v" || k === "V")) {
|
|
3458
|
+
return acc.concat([{ key: k, command: "Paste" }]);
|
|
3459
|
+
}
|
|
3460
|
+
return acc.concat([{ key: k }]);
|
|
3461
|
+
}, []);
|
|
3462
|
+
}
|
|
3463
|
+
function paramStr(task) {
|
|
3464
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
3465
|
+
let value;
|
|
3466
|
+
if (task.type === "Planning") {
|
|
3467
|
+
value = (_a = task == null ? void 0 : task.param) == null ? void 0 : _a.userPrompt;
|
|
3468
|
+
}
|
|
3469
|
+
if (task.type === "Insight") {
|
|
3470
|
+
value = ((_b = task == null ? void 0 : task.param) == null ? void 0 : _b.prompt) || ((_c = task == null ? void 0 : task.param) == null ? void 0 : _c.id) || ((_d = task == null ? void 0 : task.param) == null ? void 0 : _d.dataDemand) || ((_e = task == null ? void 0 : task.param) == null ? void 0 : _e.assertion);
|
|
3471
|
+
}
|
|
3472
|
+
if (task.type === "Action") {
|
|
3473
|
+
const sleepMs = (_f = task == null ? void 0 : task.param) == null ? void 0 : _f.timeMs;
|
|
3474
|
+
const scrollType = (_g = task == null ? void 0 : task.param) == null ? void 0 : _g.scrollType;
|
|
3475
|
+
if (sleepMs) {
|
|
3476
|
+
value = `${sleepMs}ms`;
|
|
3477
|
+
} else if (scrollType) {
|
|
3478
|
+
const scrollDirection = (_h = task == null ? void 0 : task.param) == null ? void 0 : _h.direction;
|
|
3479
|
+
const scrollDistance = (_i = task == null ? void 0 : task.param) == null ? void 0 : _i.distance;
|
|
3480
|
+
value = `${scrollDirection || "down"}, ${scrollType || "once"}, ${scrollDistance || "distance-not-set"}`;
|
|
3481
|
+
} else {
|
|
3482
|
+
value = ((_j = task == null ? void 0 : task.param) == null ? void 0 : _j.value) || ((_k = task == null ? void 0 : task.param) == null ? void 0 : _k.scrollType);
|
|
3483
|
+
}
|
|
3484
|
+
if (!value) {
|
|
3485
|
+
value = task.thought;
|
|
3486
|
+
}
|
|
3487
|
+
}
|
|
3488
|
+
if (typeof value === "undefined")
|
|
3489
|
+
return "";
|
|
3490
|
+
return typeof value === "string" ? value : JSON.stringify(value, void 0, 2);
|
|
3491
|
+
}
|
|
3492
|
+
|
|
3444
3493
|
// src/common/tasks.ts
|
|
3445
3494
|
var PageTaskExecutor = class {
|
|
3446
3495
|
constructor(page, insight, opts) {
|
|
@@ -3654,8 +3703,8 @@ var PageTaskExecutor = class {
|
|
|
3654
3703
|
thought: plan2.thought,
|
|
3655
3704
|
locate: plan2.locate,
|
|
3656
3705
|
executor: async (taskParam) => {
|
|
3657
|
-
|
|
3658
|
-
await this.page.keyboard.press(
|
|
3706
|
+
const keys = getKeyCommands(taskParam.value);
|
|
3707
|
+
await this.page.keyboard.press(keys);
|
|
3659
3708
|
}
|
|
3660
3709
|
};
|
|
3661
3710
|
tasks.push(taskActionKeyboardPress);
|
|
@@ -4063,7 +4112,7 @@ var PageTaskExecutor = class {
|
|
|
4063
4112
|
const cacheGroup = this.taskCache.getCacheGroupByPrompt(userPrompt);
|
|
4064
4113
|
const isCompleted = false;
|
|
4065
4114
|
let currentActionNumber = 0;
|
|
4066
|
-
const maxActionNumber =
|
|
4115
|
+
const maxActionNumber = 40;
|
|
4067
4116
|
while (!isCompleted && currentActionNumber < maxActionNumber) {
|
|
4068
4117
|
currentActionNumber++;
|
|
4069
4118
|
const planningTask = this.planningTaskToGoal(
|
|
@@ -4283,40 +4332,6 @@ var WebElementInfo = class {
|
|
|
4283
4332
|
}
|
|
4284
4333
|
};
|
|
4285
4334
|
|
|
4286
|
-
// src/common/ui-utils.ts
|
|
4287
|
-
function typeStr(task) {
|
|
4288
|
-
return task.subType ? `${task.type} / ${task.subType || ""}` : task.type;
|
|
4289
|
-
}
|
|
4290
|
-
function paramStr(task) {
|
|
4291
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
4292
|
-
let value;
|
|
4293
|
-
if (task.type === "Planning") {
|
|
4294
|
-
value = (_a = task == null ? void 0 : task.param) == null ? void 0 : _a.userPrompt;
|
|
4295
|
-
}
|
|
4296
|
-
if (task.type === "Insight") {
|
|
4297
|
-
value = ((_b = task == null ? void 0 : task.param) == null ? void 0 : _b.prompt) || ((_c = task == null ? void 0 : task.param) == null ? void 0 : _c.id) || ((_d = task == null ? void 0 : task.param) == null ? void 0 : _d.dataDemand) || ((_e = task == null ? void 0 : task.param) == null ? void 0 : _e.assertion);
|
|
4298
|
-
}
|
|
4299
|
-
if (task.type === "Action") {
|
|
4300
|
-
const sleepMs = (_f = task == null ? void 0 : task.param) == null ? void 0 : _f.timeMs;
|
|
4301
|
-
const scrollType = (_g = task == null ? void 0 : task.param) == null ? void 0 : _g.scrollType;
|
|
4302
|
-
if (sleepMs) {
|
|
4303
|
-
value = `${sleepMs}ms`;
|
|
4304
|
-
} else if (scrollType) {
|
|
4305
|
-
const scrollDirection = (_h = task == null ? void 0 : task.param) == null ? void 0 : _h.direction;
|
|
4306
|
-
const scrollDistance = (_i = task == null ? void 0 : task.param) == null ? void 0 : _i.distance;
|
|
4307
|
-
value = `${scrollDirection || "down"}, ${scrollType || "once"}, ${scrollDistance || "distance-not-set"}`;
|
|
4308
|
-
} else {
|
|
4309
|
-
value = ((_j = task == null ? void 0 : task.param) == null ? void 0 : _j.value) || ((_k = task == null ? void 0 : task.param) == null ? void 0 : _k.scrollType);
|
|
4310
|
-
}
|
|
4311
|
-
if (!value) {
|
|
4312
|
-
value = task.thought;
|
|
4313
|
-
}
|
|
4314
|
-
}
|
|
4315
|
-
if (typeof value === "undefined")
|
|
4316
|
-
return "";
|
|
4317
|
-
return typeof value === "string" ? value : JSON.stringify(value, void 0, 2);
|
|
4318
|
-
}
|
|
4319
|
-
|
|
4320
4335
|
// src/common/utils.ts
|
|
4321
4336
|
var import_node_assert4 = __toESM(require("assert"));
|
|
4322
4337
|
var import_node_fs3 = require("fs");
|
|
@@ -4609,160 +4624,6 @@ ${errors}`);
|
|
|
4609
4624
|
}
|
|
4610
4625
|
};
|
|
4611
4626
|
|
|
4612
|
-
// src/playwright/ai-fixture.ts
|
|
4613
|
-
var import_test = require("@playwright/test");
|
|
4614
|
-
var groupAndCaseForTest = (testInfo) => {
|
|
4615
|
-
let taskFile;
|
|
4616
|
-
let taskTitle;
|
|
4617
|
-
const titlePath = [...testInfo.titlePath];
|
|
4618
|
-
if (titlePath.length > 1) {
|
|
4619
|
-
taskTitle = titlePath.pop() || "unnamed";
|
|
4620
|
-
taskFile = `${titlePath.join(" > ")}`;
|
|
4621
|
-
} else if (titlePath.length === 1) {
|
|
4622
|
-
taskTitle = titlePath[0];
|
|
4623
|
-
taskFile = `${taskTitle}`;
|
|
4624
|
-
} else {
|
|
4625
|
-
taskTitle = "unnamed";
|
|
4626
|
-
taskFile = "unnamed";
|
|
4627
|
-
}
|
|
4628
|
-
return { taskFile, taskTitle };
|
|
4629
|
-
};
|
|
4630
|
-
var midsceneAgentKeyId = "_midsceneAgentId";
|
|
4631
|
-
var midsceneDumpAnnotationId = "MIDSCENE_DUMP_ANNOTATION";
|
|
4632
|
-
var PlaywrightAiFixture = () => {
|
|
4633
|
-
const pageAgentMap = {};
|
|
4634
|
-
const agentForPage = (page, testInfo) => {
|
|
4635
|
-
let idForPage = page[midsceneAgentKeyId];
|
|
4636
|
-
if (!idForPage) {
|
|
4637
|
-
idForPage = (0, import_node_crypto.randomUUID)();
|
|
4638
|
-
page[midsceneAgentKeyId] = idForPage;
|
|
4639
|
-
const { testId } = testInfo;
|
|
4640
|
-
const { taskFile, taskTitle } = groupAndCaseForTest(testInfo);
|
|
4641
|
-
pageAgentMap[idForPage] = new PageAgent(new WebPage(page), {
|
|
4642
|
-
testId: `playwright-${testId}-${idForPage}`,
|
|
4643
|
-
cacheId: `${taskFile}(${taskTitle})`,
|
|
4644
|
-
groupName: taskTitle,
|
|
4645
|
-
groupDescription: taskFile,
|
|
4646
|
-
generateReport: false
|
|
4647
|
-
// we will generate it in the reporter
|
|
4648
|
-
});
|
|
4649
|
-
}
|
|
4650
|
-
return pageAgentMap[idForPage];
|
|
4651
|
-
};
|
|
4652
|
-
const updateDumpAnnotation = (test2, dump2) => {
|
|
4653
|
-
const currentAnnotation = test2.annotations.find((item) => {
|
|
4654
|
-
return item.type === midsceneDumpAnnotationId;
|
|
4655
|
-
});
|
|
4656
|
-
if (currentAnnotation) {
|
|
4657
|
-
currentAnnotation.description = dump2;
|
|
4658
|
-
} else {
|
|
4659
|
-
test2.annotations.push({
|
|
4660
|
-
type: midsceneDumpAnnotationId,
|
|
4661
|
-
description: dump2
|
|
4662
|
-
});
|
|
4663
|
-
}
|
|
4664
|
-
};
|
|
4665
|
-
return {
|
|
4666
|
-
ai: async ({ page }, use, testInfo) => {
|
|
4667
|
-
const agent = agentForPage(page, testInfo);
|
|
4668
|
-
await use(
|
|
4669
|
-
async (taskPrompt, opts) => {
|
|
4670
|
-
return new Promise((resolve, reject) => {
|
|
4671
|
-
import_test.test.step(`ai - ${taskPrompt}`, async () => {
|
|
4672
|
-
await waitForNetworkIdle(page);
|
|
4673
|
-
const actionType = (opts == null ? void 0 : opts.type) || "action";
|
|
4674
|
-
try {
|
|
4675
|
-
const result = await agent.ai(taskPrompt, actionType);
|
|
4676
|
-
resolve(result);
|
|
4677
|
-
} catch (error) {
|
|
4678
|
-
reject(error);
|
|
4679
|
-
}
|
|
4680
|
-
});
|
|
4681
|
-
});
|
|
4682
|
-
}
|
|
4683
|
-
);
|
|
4684
|
-
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4685
|
-
},
|
|
4686
|
-
aiAction: async ({ page }, use, testInfo) => {
|
|
4687
|
-
const agent = agentForPage(page, testInfo);
|
|
4688
|
-
await use(async (taskPrompt) => {
|
|
4689
|
-
return new Promise((resolve, reject) => {
|
|
4690
|
-
import_test.test.step(`aiAction - ${taskPrompt}`, async () => {
|
|
4691
|
-
await waitForNetworkIdle(page);
|
|
4692
|
-
try {
|
|
4693
|
-
const result = await agent.aiAction(taskPrompt);
|
|
4694
|
-
resolve(result);
|
|
4695
|
-
} catch (error) {
|
|
4696
|
-
reject(error);
|
|
4697
|
-
}
|
|
4698
|
-
});
|
|
4699
|
-
});
|
|
4700
|
-
});
|
|
4701
|
-
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4702
|
-
},
|
|
4703
|
-
aiQuery: async ({ page }, use, testInfo) => {
|
|
4704
|
-
const agent = agentForPage(page, testInfo);
|
|
4705
|
-
await use(async (demand) => {
|
|
4706
|
-
return new Promise((resolve, reject) => {
|
|
4707
|
-
import_test.test.step(`aiQuery - ${JSON.stringify(demand)}`, async () => {
|
|
4708
|
-
await waitForNetworkIdle(page);
|
|
4709
|
-
try {
|
|
4710
|
-
const result = await agent.aiQuery(demand);
|
|
4711
|
-
resolve(result);
|
|
4712
|
-
} catch (error) {
|
|
4713
|
-
reject(error);
|
|
4714
|
-
}
|
|
4715
|
-
});
|
|
4716
|
-
});
|
|
4717
|
-
});
|
|
4718
|
-
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4719
|
-
},
|
|
4720
|
-
aiAssert: async ({ page }, use, testInfo) => {
|
|
4721
|
-
const agent = agentForPage(page, testInfo);
|
|
4722
|
-
await use(async (assertion, errorMsg) => {
|
|
4723
|
-
return new Promise((resolve, reject) => {
|
|
4724
|
-
import_test.test.step(`aiAssert - ${assertion}`, async () => {
|
|
4725
|
-
await waitForNetworkIdle(page);
|
|
4726
|
-
try {
|
|
4727
|
-
await agent.aiAssert(assertion, errorMsg);
|
|
4728
|
-
resolve(null);
|
|
4729
|
-
} catch (error) {
|
|
4730
|
-
reject(error);
|
|
4731
|
-
}
|
|
4732
|
-
});
|
|
4733
|
-
});
|
|
4734
|
-
});
|
|
4735
|
-
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4736
|
-
},
|
|
4737
|
-
aiWaitFor: async ({ page }, use, testInfo) => {
|
|
4738
|
-
const agent = agentForPage(page, testInfo);
|
|
4739
|
-
await use(async (assertion, opt) => {
|
|
4740
|
-
return new Promise((resolve, reject) => {
|
|
4741
|
-
import_test.test.step(`aiWaitFor - ${assertion}`, async () => {
|
|
4742
|
-
await waitForNetworkIdle(page);
|
|
4743
|
-
try {
|
|
4744
|
-
await agent.aiWaitFor(assertion, opt);
|
|
4745
|
-
resolve(null);
|
|
4746
|
-
} catch (error) {
|
|
4747
|
-
reject(error);
|
|
4748
|
-
}
|
|
4749
|
-
});
|
|
4750
|
-
});
|
|
4751
|
-
});
|
|
4752
|
-
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4753
|
-
}
|
|
4754
|
-
};
|
|
4755
|
-
};
|
|
4756
|
-
async function waitForNetworkIdle(page, timeout = 2e4) {
|
|
4757
|
-
try {
|
|
4758
|
-
await page.waitForLoadState("networkidle", { timeout });
|
|
4759
|
-
} catch (error) {
|
|
4760
|
-
console.warn(
|
|
4761
|
-
`Network idle timeout exceeded: ${error instanceof Error ? error.message : String(error)}`
|
|
4762
|
-
);
|
|
4763
|
-
}
|
|
4764
|
-
}
|
|
4765
|
-
|
|
4766
4627
|
// src/puppeteer/base-page.ts
|
|
4767
4628
|
var import_utils9 = require("@midscene/core/utils");
|
|
4768
4629
|
var import_extractor2 = require("@midscene/shared/extractor");
|
|
@@ -4778,12 +4639,19 @@ var Page = class {
|
|
|
4778
4639
|
this.underlyingPage = underlyingPage;
|
|
4779
4640
|
this.pageType = pageType;
|
|
4780
4641
|
}
|
|
4642
|
+
async waitForNavigation() {
|
|
4643
|
+
if (this.pageType === "puppeteer" || this.pageType === "playwright") {
|
|
4644
|
+
await this.underlyingPage.waitForSelector("html");
|
|
4645
|
+
}
|
|
4646
|
+
}
|
|
4781
4647
|
// @deprecated
|
|
4782
4648
|
async getElementsInfo() {
|
|
4649
|
+
await this.waitForNavigation();
|
|
4783
4650
|
const tree = await this.getElementsNodeTree();
|
|
4784
4651
|
return (0, import_extractor2.treeToList)(tree);
|
|
4785
4652
|
}
|
|
4786
4653
|
async getElementsNodeTree() {
|
|
4654
|
+
await this.waitForNavigation();
|
|
4787
4655
|
const scripts = await getExtraReturnLogic(true);
|
|
4788
4656
|
const captureElementSnapshot = await this.evaluate(scripts);
|
|
4789
4657
|
return captureElementSnapshot;
|
|
@@ -4804,6 +4672,7 @@ var Page = class {
|
|
|
4804
4672
|
async screenshotBase64() {
|
|
4805
4673
|
const imgType = "jpeg";
|
|
4806
4674
|
const path2 = (0, import_utils9.getTmpFile)(imgType);
|
|
4675
|
+
await this.waitForNavigation();
|
|
4807
4676
|
await this.underlyingPage.screenshot({
|
|
4808
4677
|
path: path2,
|
|
4809
4678
|
type: imgType,
|
|
@@ -4861,13 +4730,14 @@ var Page = class {
|
|
|
4861
4730
|
get keyboard() {
|
|
4862
4731
|
return {
|
|
4863
4732
|
type: async (text) => this.underlyingPage.keyboard.type(text, { delay: 80 }),
|
|
4864
|
-
press: async (
|
|
4865
|
-
const keys = Array.isArray(
|
|
4866
|
-
for (const
|
|
4867
|
-
|
|
4733
|
+
press: async (action) => {
|
|
4734
|
+
const keys = Array.isArray(action) ? action : [action];
|
|
4735
|
+
for (const k of keys) {
|
|
4736
|
+
const commands = k.command ? [k.command] : [];
|
|
4737
|
+
await this.underlyingPage.keyboard.down(k.key, { commands });
|
|
4868
4738
|
}
|
|
4869
|
-
for (const
|
|
4870
|
-
await this.underlyingPage.keyboard.up(
|
|
4739
|
+
for (const k of [...keys].reverse()) {
|
|
4740
|
+
await this.underlyingPage.keyboard.up(k.key);
|
|
4871
4741
|
}
|
|
4872
4742
|
},
|
|
4873
4743
|
down: async (key) => {
|
|
@@ -4902,7 +4772,7 @@ var Page = class {
|
|
|
4902
4772
|
await this.underlyingPage.keyboard.up("Control");
|
|
4903
4773
|
}
|
|
4904
4774
|
await (0, import_utils9.sleep)(100);
|
|
4905
|
-
await this.keyboard.press("Backspace");
|
|
4775
|
+
await this.keyboard.press([{ key: "Backspace" }]);
|
|
4906
4776
|
}
|
|
4907
4777
|
async moveToPoint(point) {
|
|
4908
4778
|
if (point) {
|
|
@@ -4963,8 +4833,186 @@ var WebPage = class extends Page {
|
|
|
4963
4833
|
}
|
|
4964
4834
|
};
|
|
4965
4835
|
|
|
4836
|
+
// src/playwright/ai-fixture.ts
|
|
4837
|
+
var import_node_crypto = require("crypto");
|
|
4838
|
+
var import_test = require("@playwright/test");
|
|
4839
|
+
var groupAndCaseForTest = (testInfo) => {
|
|
4840
|
+
let taskFile;
|
|
4841
|
+
let taskTitle;
|
|
4842
|
+
const titlePath = [...testInfo.titlePath];
|
|
4843
|
+
if (titlePath.length > 1) {
|
|
4844
|
+
taskTitle = titlePath.pop() || "unnamed";
|
|
4845
|
+
taskFile = `${titlePath.join(" > ")}`;
|
|
4846
|
+
} else if (titlePath.length === 1) {
|
|
4847
|
+
taskTitle = titlePath[0];
|
|
4848
|
+
taskFile = `${taskTitle}`;
|
|
4849
|
+
} else {
|
|
4850
|
+
taskTitle = "unnamed";
|
|
4851
|
+
taskFile = "unnamed";
|
|
4852
|
+
}
|
|
4853
|
+
return { taskFile, taskTitle };
|
|
4854
|
+
};
|
|
4855
|
+
var midsceneAgentKeyId = "_midsceneAgentId";
|
|
4856
|
+
var midsceneDumpAnnotationId = "MIDSCENE_DUMP_ANNOTATION";
|
|
4857
|
+
var PlaywrightAiFixture = (options) => {
|
|
4858
|
+
const { forceSameTabNavigation = true } = options != null ? options : {};
|
|
4859
|
+
const pageAgentMap = {};
|
|
4860
|
+
const agentForPage = (page, testInfo) => {
|
|
4861
|
+
let idForPage = page[midsceneAgentKeyId];
|
|
4862
|
+
if (!idForPage) {
|
|
4863
|
+
idForPage = (0, import_node_crypto.randomUUID)();
|
|
4864
|
+
page[midsceneAgentKeyId] = idForPage;
|
|
4865
|
+
const { testId } = testInfo;
|
|
4866
|
+
const { taskFile, taskTitle } = groupAndCaseForTest(testInfo);
|
|
4867
|
+
pageAgentMap[idForPage] = new PlaywrightAgent(page, {
|
|
4868
|
+
testId: `playwright-${testId}-${idForPage}`,
|
|
4869
|
+
forceSameTabNavigation,
|
|
4870
|
+
cacheId: `${taskFile}(${taskTitle})`,
|
|
4871
|
+
groupName: taskTitle,
|
|
4872
|
+
groupDescription: taskFile,
|
|
4873
|
+
generateReport: false
|
|
4874
|
+
// we will generate it in the reporter
|
|
4875
|
+
});
|
|
4876
|
+
}
|
|
4877
|
+
return pageAgentMap[idForPage];
|
|
4878
|
+
};
|
|
4879
|
+
const updateDumpAnnotation = (test2, dump2) => {
|
|
4880
|
+
const currentAnnotation = test2.annotations.find((item) => {
|
|
4881
|
+
return item.type === midsceneDumpAnnotationId;
|
|
4882
|
+
});
|
|
4883
|
+
if (currentAnnotation) {
|
|
4884
|
+
currentAnnotation.description = dump2;
|
|
4885
|
+
} else {
|
|
4886
|
+
test2.annotations.push({
|
|
4887
|
+
type: midsceneDumpAnnotationId,
|
|
4888
|
+
description: dump2
|
|
4889
|
+
});
|
|
4890
|
+
}
|
|
4891
|
+
};
|
|
4892
|
+
return {
|
|
4893
|
+
ai: async ({ page }, use, testInfo) => {
|
|
4894
|
+
const agent = agentForPage(page, testInfo);
|
|
4895
|
+
await use(
|
|
4896
|
+
async (taskPrompt, opts) => {
|
|
4897
|
+
return new Promise((resolve, reject) => {
|
|
4898
|
+
const { type: type2 = "action" } = opts || {};
|
|
4899
|
+
import_test.test.step(`ai - ${taskPrompt}`, async () => {
|
|
4900
|
+
await waitForNetworkIdle(page);
|
|
4901
|
+
try {
|
|
4902
|
+
const result = await agent.ai(taskPrompt, type2);
|
|
4903
|
+
resolve(result);
|
|
4904
|
+
} catch (error) {
|
|
4905
|
+
reject(error);
|
|
4906
|
+
}
|
|
4907
|
+
});
|
|
4908
|
+
});
|
|
4909
|
+
}
|
|
4910
|
+
);
|
|
4911
|
+
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4912
|
+
},
|
|
4913
|
+
aiAction: async ({ page }, use, testInfo) => {
|
|
4914
|
+
const agent = agentForPage(page, testInfo);
|
|
4915
|
+
await use(async (taskPrompt) => {
|
|
4916
|
+
return new Promise((resolve, reject) => {
|
|
4917
|
+
import_test.test.step(`aiAction - ${taskPrompt}`, async () => {
|
|
4918
|
+
await waitForNetworkIdle(page);
|
|
4919
|
+
try {
|
|
4920
|
+
const result = await agent.aiAction(taskPrompt);
|
|
4921
|
+
resolve(result);
|
|
4922
|
+
} catch (error) {
|
|
4923
|
+
reject(error);
|
|
4924
|
+
}
|
|
4925
|
+
});
|
|
4926
|
+
});
|
|
4927
|
+
});
|
|
4928
|
+
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4929
|
+
},
|
|
4930
|
+
aiQuery: async ({ page }, use, testInfo) => {
|
|
4931
|
+
const agent = agentForPage(page, testInfo);
|
|
4932
|
+
await use(async (demand) => {
|
|
4933
|
+
return new Promise((resolve, reject) => {
|
|
4934
|
+
import_test.test.step(`aiQuery - ${JSON.stringify(demand)}`, async () => {
|
|
4935
|
+
await waitForNetworkIdle(page);
|
|
4936
|
+
try {
|
|
4937
|
+
const result = await agent.aiQuery(demand);
|
|
4938
|
+
resolve(result);
|
|
4939
|
+
} catch (error) {
|
|
4940
|
+
reject(error);
|
|
4941
|
+
}
|
|
4942
|
+
});
|
|
4943
|
+
});
|
|
4944
|
+
});
|
|
4945
|
+
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4946
|
+
},
|
|
4947
|
+
aiAssert: async ({ page }, use, testInfo) => {
|
|
4948
|
+
const agent = agentForPage(page, testInfo);
|
|
4949
|
+
await use(async (assertion, errorMsg) => {
|
|
4950
|
+
return new Promise((resolve, reject) => {
|
|
4951
|
+
import_test.test.step(`aiAssert - ${assertion}`, async () => {
|
|
4952
|
+
await waitForNetworkIdle(page);
|
|
4953
|
+
try {
|
|
4954
|
+
await agent.aiAssert(assertion, errorMsg);
|
|
4955
|
+
resolve(null);
|
|
4956
|
+
} catch (error) {
|
|
4957
|
+
reject(error);
|
|
4958
|
+
}
|
|
4959
|
+
});
|
|
4960
|
+
});
|
|
4961
|
+
});
|
|
4962
|
+
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4963
|
+
},
|
|
4964
|
+
aiWaitFor: async ({ page }, use, testInfo) => {
|
|
4965
|
+
const agent = agentForPage(page, testInfo);
|
|
4966
|
+
await use(async (assertion, opt) => {
|
|
4967
|
+
return new Promise((resolve, reject) => {
|
|
4968
|
+
import_test.test.step(`aiWaitFor - ${assertion}`, async () => {
|
|
4969
|
+
await waitForNetworkIdle(page);
|
|
4970
|
+
try {
|
|
4971
|
+
await agent.aiWaitFor(assertion, opt);
|
|
4972
|
+
resolve(null);
|
|
4973
|
+
} catch (error) {
|
|
4974
|
+
reject(error);
|
|
4975
|
+
}
|
|
4976
|
+
});
|
|
4977
|
+
});
|
|
4978
|
+
});
|
|
4979
|
+
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4980
|
+
}
|
|
4981
|
+
};
|
|
4982
|
+
};
|
|
4983
|
+
async function waitForNetworkIdle(page, timeout = 2e4) {
|
|
4984
|
+
try {
|
|
4985
|
+
await page.waitForLoadState("networkidle", { timeout });
|
|
4986
|
+
} catch (error) {
|
|
4987
|
+
console.warn(
|
|
4988
|
+
`Network idle timeout exceeded: ${error instanceof Error ? error.message : String(error)}`
|
|
4989
|
+
);
|
|
4990
|
+
}
|
|
4991
|
+
}
|
|
4992
|
+
|
|
4966
4993
|
// src/playwright/index.ts
|
|
4967
4994
|
var import_env4 = require("@midscene/core/env");
|
|
4995
|
+
var PlaywrightAgent = class extends PageAgent {
|
|
4996
|
+
constructor(page, opts) {
|
|
4997
|
+
const webPage = new WebPage(page);
|
|
4998
|
+
super(webPage, opts);
|
|
4999
|
+
const { forceSameTabNavigation = true } = opts != null ? opts : {};
|
|
5000
|
+
if (forceSameTabNavigation) {
|
|
5001
|
+
page.on("popup", async (popup) => {
|
|
5002
|
+
if (!popup) {
|
|
5003
|
+
console.warn(
|
|
5004
|
+
"got a popup event, but the popup is not ready yet, skip"
|
|
5005
|
+
);
|
|
5006
|
+
return;
|
|
5007
|
+
}
|
|
5008
|
+
const url = await popup.url();
|
|
5009
|
+
console.log(`Popup opened: ${url}`);
|
|
5010
|
+
await popup.close();
|
|
5011
|
+
await page.goto(url);
|
|
5012
|
+
});
|
|
5013
|
+
}
|
|
5014
|
+
}
|
|
5015
|
+
};
|
|
4968
5016
|
|
|
4969
5017
|
// src/puppeteer/page.ts
|
|
4970
5018
|
var WebPage2 = class extends Page {
|
|
@@ -4994,21 +5042,19 @@ var PuppeteerAgent = class extends PageAgent {
|
|
|
4994
5042
|
constructor(page, opts) {
|
|
4995
5043
|
const webPage = new WebPage2(page);
|
|
4996
5044
|
super(webPage, opts);
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
if (
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
);
|
|
5006
|
-
return;
|
|
5007
|
-
}
|
|
5008
|
-
const midscenePage = new WebPage2(targetPage);
|
|
5009
|
-
this.page = midscenePage;
|
|
5010
|
-
this.taskExecutor.page = midscenePage;
|
|
5045
|
+
const { forceSameTabNavigation = true } = opts != null ? opts : {};
|
|
5046
|
+
if (forceSameTabNavigation) {
|
|
5047
|
+
page.on("popup", async (popup) => {
|
|
5048
|
+
if (!popup) {
|
|
5049
|
+
console.warn(
|
|
5050
|
+
"got a popup event, but the popup is not ready yet, skip"
|
|
5051
|
+
);
|
|
5052
|
+
return;
|
|
5011
5053
|
}
|
|
5054
|
+
const url = await popup.url();
|
|
5055
|
+
console.log(`Popup opened: ${url}`);
|
|
5056
|
+
await popup.close();
|
|
5057
|
+
await page.goto(url);
|
|
5012
5058
|
});
|
|
5013
5059
|
}
|
|
5014
5060
|
}
|
|
@@ -5067,7 +5113,7 @@ var Page2 = class {
|
|
|
5067
5113
|
get keyboard() {
|
|
5068
5114
|
return {
|
|
5069
5115
|
type: (text) => this.keyboardType(text),
|
|
5070
|
-
press: (
|
|
5116
|
+
press: (action) => this.keyboardPressAction(action)
|
|
5071
5117
|
};
|
|
5072
5118
|
}
|
|
5073
5119
|
async clearInput(element) {
|
|
@@ -5181,6 +5227,33 @@ var Page2 = class {
|
|
|
5181
5227
|
}
|
|
5182
5228
|
]);
|
|
5183
5229
|
}
|
|
5230
|
+
async keyboardPressAction(action) {
|
|
5231
|
+
if (Array.isArray(action)) {
|
|
5232
|
+
for (const act of action) {
|
|
5233
|
+
await this.browser.performActions([
|
|
5234
|
+
{
|
|
5235
|
+
type: "key",
|
|
5236
|
+
id: "keyboard",
|
|
5237
|
+
actions: [
|
|
5238
|
+
{ type: "keyDown", value: act.key },
|
|
5239
|
+
{ type: "keyUp", value: act.key }
|
|
5240
|
+
]
|
|
5241
|
+
}
|
|
5242
|
+
]);
|
|
5243
|
+
}
|
|
5244
|
+
} else {
|
|
5245
|
+
await this.browser.performActions([
|
|
5246
|
+
{
|
|
5247
|
+
type: "key",
|
|
5248
|
+
id: "keyboard",
|
|
5249
|
+
actions: [
|
|
5250
|
+
{ type: "keyDown", value: action.key },
|
|
5251
|
+
{ type: "keyUp", value: action.key }
|
|
5252
|
+
]
|
|
5253
|
+
}
|
|
5254
|
+
]);
|
|
5255
|
+
}
|
|
5256
|
+
}
|
|
5184
5257
|
async mouseClick(x, y, button = "left") {
|
|
5185
5258
|
await this.mouseMove(x, y);
|
|
5186
5259
|
await this.browser.performActions([
|