@midscene/web 0.11.1 → 0.11.3
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 +85 -39
- package/dist/es/bridge-mode-browser.js +58 -19
- package/dist/es/bridge-mode.js +62 -43
- package/dist/es/chrome-extension.js +105 -51
- package/dist/es/index.js +292 -218
- package/dist/es/midscene-playground.js +57 -38
- package/dist/es/playground.js +57 -38
- package/dist/es/playwright-report.js +4 -0
- package/dist/es/playwright.js +252 -203
- package/dist/es/puppeteer.js +86 -60
- package/dist/es/ui-utils.js +43 -0
- package/dist/lib/appium.js +85 -39
- package/dist/lib/bridge-mode-browser.js +58 -19
- package/dist/lib/bridge-mode.js +62 -43
- package/dist/lib/chrome-extension.js +105 -51
- package/dist/lib/index.js +292 -218
- package/dist/lib/midscene-playground.js +57 -38
- package/dist/lib/playground.js +57 -38
- package/dist/lib/playwright-report.js +4 -0
- package/dist/lib/playwright.js +252 -203
- package/dist/lib/puppeteer.js +86 -60
- package/dist/lib/ui-utils.js +43 -0
- package/dist/types/{tasks-d5a01262.d.ts → agent-ae110e80.d.ts} +43 -43
- package/dist/types/appium.d.ts +3 -3
- package/dist/types/bridge-mode-browser.d.ts +3 -3
- package/dist/types/bridge-mode.d.ts +4 -4
- package/dist/types/{browser-7d5614fb.d.ts → browser-9d620553.d.ts} +4 -4
- package/dist/types/chrome-extension.d.ts +4 -4
- package/dist/types/index.d.ts +8 -8
- package/dist/types/{page-77af8d5f.d.ts → page-97720803.d.ts} +34 -8
- package/dist/types/playground.d.ts +4 -4
- package/dist/types/playwright.d.ts +13 -7
- package/dist/types/puppeteer.d.ts +3 -3
- package/dist/types/ui-utils.d.ts +6 -1
- package/dist/types/{utils-1a3bc661.d.ts → utils-93b3f5f3.d.ts} +1 -1
- package/dist/types/utils.d.ts +2 -2
- package/dist/types/yaml.d.ts +4 -4
- 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) {
|
|
@@ -3575,6 +3624,7 @@ var PageTaskExecutor = class {
|
|
|
3575
3624
|
output: {
|
|
3576
3625
|
element
|
|
3577
3626
|
},
|
|
3627
|
+
pageContext,
|
|
3578
3628
|
log: {
|
|
3579
3629
|
dump: insightDump
|
|
3580
3630
|
},
|
|
@@ -3654,8 +3704,8 @@ var PageTaskExecutor = class {
|
|
|
3654
3704
|
thought: plan2.thought,
|
|
3655
3705
|
locate: plan2.locate,
|
|
3656
3706
|
executor: async (taskParam) => {
|
|
3657
|
-
|
|
3658
|
-
await this.page.keyboard.press(
|
|
3707
|
+
const keys = getKeyCommands(taskParam.value);
|
|
3708
|
+
await this.page.keyboard.press(keys);
|
|
3659
3709
|
}
|
|
3660
3710
|
};
|
|
3661
3711
|
tasks.push(taskActionKeyboardPress);
|
|
@@ -4063,7 +4113,7 @@ var PageTaskExecutor = class {
|
|
|
4063
4113
|
const cacheGroup = this.taskCache.getCacheGroupByPrompt(userPrompt);
|
|
4064
4114
|
const isCompleted = false;
|
|
4065
4115
|
let currentActionNumber = 0;
|
|
4066
|
-
const maxActionNumber =
|
|
4116
|
+
const maxActionNumber = 40;
|
|
4067
4117
|
while (!isCompleted && currentActionNumber < maxActionNumber) {
|
|
4068
4118
|
currentActionNumber++;
|
|
4069
4119
|
const planningTask = this.planningTaskToGoal(
|
|
@@ -4283,40 +4333,6 @@ var WebElementInfo = class {
|
|
|
4283
4333
|
}
|
|
4284
4334
|
};
|
|
4285
4335
|
|
|
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
4336
|
// src/common/utils.ts
|
|
4321
4337
|
var import_node_assert4 = __toESM(require("assert"));
|
|
4322
4338
|
var import_node_fs3 = require("fs");
|
|
@@ -4609,160 +4625,6 @@ ${errors}`);
|
|
|
4609
4625
|
}
|
|
4610
4626
|
};
|
|
4611
4627
|
|
|
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
4628
|
// src/puppeteer/base-page.ts
|
|
4767
4629
|
var import_utils9 = require("@midscene/core/utils");
|
|
4768
4630
|
var import_extractor2 = require("@midscene/shared/extractor");
|
|
@@ -4778,12 +4640,19 @@ var Page = class {
|
|
|
4778
4640
|
this.underlyingPage = underlyingPage;
|
|
4779
4641
|
this.pageType = pageType;
|
|
4780
4642
|
}
|
|
4643
|
+
async waitForNavigation() {
|
|
4644
|
+
if (this.pageType === "puppeteer" || this.pageType === "playwright") {
|
|
4645
|
+
await this.underlyingPage.waitForSelector("html");
|
|
4646
|
+
}
|
|
4647
|
+
}
|
|
4781
4648
|
// @deprecated
|
|
4782
4649
|
async getElementsInfo() {
|
|
4650
|
+
await this.waitForNavigation();
|
|
4783
4651
|
const tree = await this.getElementsNodeTree();
|
|
4784
4652
|
return (0, import_extractor2.treeToList)(tree);
|
|
4785
4653
|
}
|
|
4786
4654
|
async getElementsNodeTree() {
|
|
4655
|
+
await this.waitForNavigation();
|
|
4787
4656
|
const scripts = await getExtraReturnLogic(true);
|
|
4788
4657
|
const captureElementSnapshot = await this.evaluate(scripts);
|
|
4789
4658
|
return captureElementSnapshot;
|
|
@@ -4804,6 +4673,7 @@ var Page = class {
|
|
|
4804
4673
|
async screenshotBase64() {
|
|
4805
4674
|
const imgType = "jpeg";
|
|
4806
4675
|
const path2 = (0, import_utils9.getTmpFile)(imgType);
|
|
4676
|
+
await this.waitForNavigation();
|
|
4807
4677
|
await this.underlyingPage.screenshot({
|
|
4808
4678
|
path: path2,
|
|
4809
4679
|
type: imgType,
|
|
@@ -4861,13 +4731,14 @@ var Page = class {
|
|
|
4861
4731
|
get keyboard() {
|
|
4862
4732
|
return {
|
|
4863
4733
|
type: async (text) => this.underlyingPage.keyboard.type(text, { delay: 80 }),
|
|
4864
|
-
press: async (
|
|
4865
|
-
const keys = Array.isArray(
|
|
4866
|
-
for (const
|
|
4867
|
-
|
|
4734
|
+
press: async (action) => {
|
|
4735
|
+
const keys = Array.isArray(action) ? action : [action];
|
|
4736
|
+
for (const k of keys) {
|
|
4737
|
+
const commands = k.command ? [k.command] : [];
|
|
4738
|
+
await this.underlyingPage.keyboard.down(k.key, { commands });
|
|
4868
4739
|
}
|
|
4869
|
-
for (const
|
|
4870
|
-
await this.underlyingPage.keyboard.up(
|
|
4740
|
+
for (const k of [...keys].reverse()) {
|
|
4741
|
+
await this.underlyingPage.keyboard.up(k.key);
|
|
4871
4742
|
}
|
|
4872
4743
|
},
|
|
4873
4744
|
down: async (key) => {
|
|
@@ -4902,7 +4773,7 @@ var Page = class {
|
|
|
4902
4773
|
await this.underlyingPage.keyboard.up("Control");
|
|
4903
4774
|
}
|
|
4904
4775
|
await (0, import_utils9.sleep)(100);
|
|
4905
|
-
await this.keyboard.press("Backspace");
|
|
4776
|
+
await this.keyboard.press([{ key: "Backspace" }]);
|
|
4906
4777
|
}
|
|
4907
4778
|
async moveToPoint(point) {
|
|
4908
4779
|
if (point) {
|
|
@@ -4963,8 +4834,186 @@ var WebPage = class extends Page {
|
|
|
4963
4834
|
}
|
|
4964
4835
|
};
|
|
4965
4836
|
|
|
4837
|
+
// src/playwright/ai-fixture.ts
|
|
4838
|
+
var import_node_crypto = require("crypto");
|
|
4839
|
+
var import_test = require("@playwright/test");
|
|
4840
|
+
var groupAndCaseForTest = (testInfo) => {
|
|
4841
|
+
let taskFile;
|
|
4842
|
+
let taskTitle;
|
|
4843
|
+
const titlePath = [...testInfo.titlePath];
|
|
4844
|
+
if (titlePath.length > 1) {
|
|
4845
|
+
taskTitle = titlePath.pop() || "unnamed";
|
|
4846
|
+
taskFile = `${titlePath.join(" > ")}`;
|
|
4847
|
+
} else if (titlePath.length === 1) {
|
|
4848
|
+
taskTitle = titlePath[0];
|
|
4849
|
+
taskFile = `${taskTitle}`;
|
|
4850
|
+
} else {
|
|
4851
|
+
taskTitle = "unnamed";
|
|
4852
|
+
taskFile = "unnamed";
|
|
4853
|
+
}
|
|
4854
|
+
return { taskFile, taskTitle };
|
|
4855
|
+
};
|
|
4856
|
+
var midsceneAgentKeyId = "_midsceneAgentId";
|
|
4857
|
+
var midsceneDumpAnnotationId = "MIDSCENE_DUMP_ANNOTATION";
|
|
4858
|
+
var PlaywrightAiFixture = (options) => {
|
|
4859
|
+
const { forceSameTabNavigation = true } = options != null ? options : {};
|
|
4860
|
+
const pageAgentMap = {};
|
|
4861
|
+
const agentForPage = (page, testInfo) => {
|
|
4862
|
+
let idForPage = page[midsceneAgentKeyId];
|
|
4863
|
+
if (!idForPage) {
|
|
4864
|
+
idForPage = (0, import_node_crypto.randomUUID)();
|
|
4865
|
+
page[midsceneAgentKeyId] = idForPage;
|
|
4866
|
+
const { testId } = testInfo;
|
|
4867
|
+
const { taskFile, taskTitle } = groupAndCaseForTest(testInfo);
|
|
4868
|
+
pageAgentMap[idForPage] = new PlaywrightAgent(page, {
|
|
4869
|
+
testId: `playwright-${testId}-${idForPage}`,
|
|
4870
|
+
forceSameTabNavigation,
|
|
4871
|
+
cacheId: `${taskFile}(${taskTitle})`,
|
|
4872
|
+
groupName: taskTitle,
|
|
4873
|
+
groupDescription: taskFile,
|
|
4874
|
+
generateReport: false
|
|
4875
|
+
// we will generate it in the reporter
|
|
4876
|
+
});
|
|
4877
|
+
}
|
|
4878
|
+
return pageAgentMap[idForPage];
|
|
4879
|
+
};
|
|
4880
|
+
const updateDumpAnnotation = (test2, dump2) => {
|
|
4881
|
+
const currentAnnotation = test2.annotations.find((item) => {
|
|
4882
|
+
return item.type === midsceneDumpAnnotationId;
|
|
4883
|
+
});
|
|
4884
|
+
if (currentAnnotation) {
|
|
4885
|
+
currentAnnotation.description = dump2;
|
|
4886
|
+
} else {
|
|
4887
|
+
test2.annotations.push({
|
|
4888
|
+
type: midsceneDumpAnnotationId,
|
|
4889
|
+
description: dump2
|
|
4890
|
+
});
|
|
4891
|
+
}
|
|
4892
|
+
};
|
|
4893
|
+
return {
|
|
4894
|
+
ai: async ({ page }, use, testInfo) => {
|
|
4895
|
+
const agent = agentForPage(page, testInfo);
|
|
4896
|
+
await use(
|
|
4897
|
+
async (taskPrompt, opts) => {
|
|
4898
|
+
return new Promise((resolve, reject) => {
|
|
4899
|
+
const { type: type2 = "action" } = opts || {};
|
|
4900
|
+
import_test.test.step(`ai - ${taskPrompt}`, async () => {
|
|
4901
|
+
await waitForNetworkIdle(page);
|
|
4902
|
+
try {
|
|
4903
|
+
const result = await agent.ai(taskPrompt, type2);
|
|
4904
|
+
resolve(result);
|
|
4905
|
+
} catch (error) {
|
|
4906
|
+
reject(error);
|
|
4907
|
+
}
|
|
4908
|
+
});
|
|
4909
|
+
});
|
|
4910
|
+
}
|
|
4911
|
+
);
|
|
4912
|
+
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4913
|
+
},
|
|
4914
|
+
aiAction: async ({ page }, use, testInfo) => {
|
|
4915
|
+
const agent = agentForPage(page, testInfo);
|
|
4916
|
+
await use(async (taskPrompt) => {
|
|
4917
|
+
return new Promise((resolve, reject) => {
|
|
4918
|
+
import_test.test.step(`aiAction - ${taskPrompt}`, async () => {
|
|
4919
|
+
await waitForNetworkIdle(page);
|
|
4920
|
+
try {
|
|
4921
|
+
const result = await agent.aiAction(taskPrompt);
|
|
4922
|
+
resolve(result);
|
|
4923
|
+
} catch (error) {
|
|
4924
|
+
reject(error);
|
|
4925
|
+
}
|
|
4926
|
+
});
|
|
4927
|
+
});
|
|
4928
|
+
});
|
|
4929
|
+
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4930
|
+
},
|
|
4931
|
+
aiQuery: async ({ page }, use, testInfo) => {
|
|
4932
|
+
const agent = agentForPage(page, testInfo);
|
|
4933
|
+
await use(async (demand) => {
|
|
4934
|
+
return new Promise((resolve, reject) => {
|
|
4935
|
+
import_test.test.step(`aiQuery - ${JSON.stringify(demand)}`, async () => {
|
|
4936
|
+
await waitForNetworkIdle(page);
|
|
4937
|
+
try {
|
|
4938
|
+
const result = await agent.aiQuery(demand);
|
|
4939
|
+
resolve(result);
|
|
4940
|
+
} catch (error) {
|
|
4941
|
+
reject(error);
|
|
4942
|
+
}
|
|
4943
|
+
});
|
|
4944
|
+
});
|
|
4945
|
+
});
|
|
4946
|
+
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4947
|
+
},
|
|
4948
|
+
aiAssert: async ({ page }, use, testInfo) => {
|
|
4949
|
+
const agent = agentForPage(page, testInfo);
|
|
4950
|
+
await use(async (assertion, errorMsg) => {
|
|
4951
|
+
return new Promise((resolve, reject) => {
|
|
4952
|
+
import_test.test.step(`aiAssert - ${assertion}`, async () => {
|
|
4953
|
+
await waitForNetworkIdle(page);
|
|
4954
|
+
try {
|
|
4955
|
+
await agent.aiAssert(assertion, errorMsg);
|
|
4956
|
+
resolve(null);
|
|
4957
|
+
} catch (error) {
|
|
4958
|
+
reject(error);
|
|
4959
|
+
}
|
|
4960
|
+
});
|
|
4961
|
+
});
|
|
4962
|
+
});
|
|
4963
|
+
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4964
|
+
},
|
|
4965
|
+
aiWaitFor: async ({ page }, use, testInfo) => {
|
|
4966
|
+
const agent = agentForPage(page, testInfo);
|
|
4967
|
+
await use(async (assertion, opt) => {
|
|
4968
|
+
return new Promise((resolve, reject) => {
|
|
4969
|
+
import_test.test.step(`aiWaitFor - ${assertion}`, async () => {
|
|
4970
|
+
await waitForNetworkIdle(page);
|
|
4971
|
+
try {
|
|
4972
|
+
await agent.aiWaitFor(assertion, opt);
|
|
4973
|
+
resolve(null);
|
|
4974
|
+
} catch (error) {
|
|
4975
|
+
reject(error);
|
|
4976
|
+
}
|
|
4977
|
+
});
|
|
4978
|
+
});
|
|
4979
|
+
});
|
|
4980
|
+
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4981
|
+
}
|
|
4982
|
+
};
|
|
4983
|
+
};
|
|
4984
|
+
async function waitForNetworkIdle(page, timeout = 2e4) {
|
|
4985
|
+
try {
|
|
4986
|
+
await page.waitForLoadState("networkidle", { timeout });
|
|
4987
|
+
} catch (error) {
|
|
4988
|
+
console.warn(
|
|
4989
|
+
`Network idle timeout exceeded: ${error instanceof Error ? error.message : String(error)}`
|
|
4990
|
+
);
|
|
4991
|
+
}
|
|
4992
|
+
}
|
|
4993
|
+
|
|
4966
4994
|
// src/playwright/index.ts
|
|
4967
4995
|
var import_env4 = require("@midscene/core/env");
|
|
4996
|
+
var PlaywrightAgent = class extends PageAgent {
|
|
4997
|
+
constructor(page, opts) {
|
|
4998
|
+
const webPage = new WebPage(page);
|
|
4999
|
+
super(webPage, opts);
|
|
5000
|
+
const { forceSameTabNavigation = true } = opts != null ? opts : {};
|
|
5001
|
+
if (forceSameTabNavigation) {
|
|
5002
|
+
page.on("popup", async (popup) => {
|
|
5003
|
+
if (!popup) {
|
|
5004
|
+
console.warn(
|
|
5005
|
+
"got a popup event, but the popup is not ready yet, skip"
|
|
5006
|
+
);
|
|
5007
|
+
return;
|
|
5008
|
+
}
|
|
5009
|
+
const url = await popup.url();
|
|
5010
|
+
console.log(`Popup opened: ${url}`);
|
|
5011
|
+
await popup.close();
|
|
5012
|
+
await page.goto(url);
|
|
5013
|
+
});
|
|
5014
|
+
}
|
|
5015
|
+
}
|
|
5016
|
+
};
|
|
4968
5017
|
|
|
4969
5018
|
// src/puppeteer/page.ts
|
|
4970
5019
|
var WebPage2 = class extends Page {
|
|
@@ -4994,21 +5043,19 @@ var PuppeteerAgent = class extends PageAgent {
|
|
|
4994
5043
|
constructor(page, opts) {
|
|
4995
5044
|
const webPage = new WebPage2(page);
|
|
4996
5045
|
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;
|
|
5046
|
+
const { forceSameTabNavigation = true } = opts != null ? opts : {};
|
|
5047
|
+
if (forceSameTabNavigation) {
|
|
5048
|
+
page.on("popup", async (popup) => {
|
|
5049
|
+
if (!popup) {
|
|
5050
|
+
console.warn(
|
|
5051
|
+
"got a popup event, but the popup is not ready yet, skip"
|
|
5052
|
+
);
|
|
5053
|
+
return;
|
|
5011
5054
|
}
|
|
5055
|
+
const url = await popup.url();
|
|
5056
|
+
console.log(`Popup opened: ${url}`);
|
|
5057
|
+
await popup.close();
|
|
5058
|
+
await page.goto(url);
|
|
5012
5059
|
});
|
|
5013
5060
|
}
|
|
5014
5061
|
}
|
|
@@ -5067,7 +5114,7 @@ var Page2 = class {
|
|
|
5067
5114
|
get keyboard() {
|
|
5068
5115
|
return {
|
|
5069
5116
|
type: (text) => this.keyboardType(text),
|
|
5070
|
-
press: (
|
|
5117
|
+
press: (action) => this.keyboardPressAction(action)
|
|
5071
5118
|
};
|
|
5072
5119
|
}
|
|
5073
5120
|
async clearInput(element) {
|
|
@@ -5181,6 +5228,33 @@ var Page2 = class {
|
|
|
5181
5228
|
}
|
|
5182
5229
|
]);
|
|
5183
5230
|
}
|
|
5231
|
+
async keyboardPressAction(action) {
|
|
5232
|
+
if (Array.isArray(action)) {
|
|
5233
|
+
for (const act of action) {
|
|
5234
|
+
await this.browser.performActions([
|
|
5235
|
+
{
|
|
5236
|
+
type: "key",
|
|
5237
|
+
id: "keyboard",
|
|
5238
|
+
actions: [
|
|
5239
|
+
{ type: "keyDown", value: act.key },
|
|
5240
|
+
{ type: "keyUp", value: act.key }
|
|
5241
|
+
]
|
|
5242
|
+
}
|
|
5243
|
+
]);
|
|
5244
|
+
}
|
|
5245
|
+
} else {
|
|
5246
|
+
await this.browser.performActions([
|
|
5247
|
+
{
|
|
5248
|
+
type: "key",
|
|
5249
|
+
id: "keyboard",
|
|
5250
|
+
actions: [
|
|
5251
|
+
{ type: "keyDown", value: action.key },
|
|
5252
|
+
{ type: "keyUp", value: action.key }
|
|
5253
|
+
]
|
|
5254
|
+
}
|
|
5255
|
+
]);
|
|
5256
|
+
}
|
|
5257
|
+
}
|
|
5184
5258
|
async mouseClick(x, y, button = "left") {
|
|
5185
5259
|
await this.mouseMove(x, y);
|
|
5186
5260
|
await this.browser.performActions([
|