@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/lib/playwright.js
CHANGED
|
@@ -328,16 +328,13 @@ var require_dayjs_min = __commonJS({
|
|
|
328
328
|
// src/playwright/index.ts
|
|
329
329
|
var playwright_exports = {};
|
|
330
330
|
__export(playwright_exports, {
|
|
331
|
-
PlaywrightAgent: () =>
|
|
331
|
+
PlaywrightAgent: () => PlaywrightAgent,
|
|
332
332
|
PlaywrightAiFixture: () => PlaywrightAiFixture,
|
|
333
333
|
PlaywrightWebPage: () => WebPage,
|
|
334
334
|
overrideAIConfig: () => import_env4.overrideAIConfig
|
|
335
335
|
});
|
|
336
336
|
module.exports = __toCommonJS(playwright_exports);
|
|
337
337
|
|
|
338
|
-
// src/playwright/ai-fixture.ts
|
|
339
|
-
var import_node_crypto = require("crypto");
|
|
340
|
-
|
|
341
338
|
// src/common/agent.ts
|
|
342
339
|
var import_core2 = require("@midscene/core");
|
|
343
340
|
var import_constants2 = require("@midscene/shared/constants");
|
|
@@ -3367,7 +3364,9 @@ var TaskCache = class {
|
|
|
3367
3364
|
if (!this.midscenePkgInfo) {
|
|
3368
3365
|
return void 0;
|
|
3369
3366
|
}
|
|
3370
|
-
|
|
3367
|
+
const jsonDataPkgVersion = jsonData.pkgVersion.split(".");
|
|
3368
|
+
const midscenePkgInfoPkgVersion = this.midscenePkgInfo.version.split(".");
|
|
3369
|
+
if (jsonDataPkgVersion[0] !== midscenePkgInfoPkgVersion[0] || jsonDataPkgVersion[1] !== midscenePkgInfoPkgVersion[1]) {
|
|
3371
3370
|
return void 0;
|
|
3372
3371
|
}
|
|
3373
3372
|
return jsonData;
|
|
@@ -3401,6 +3400,56 @@ var TaskCache = class {
|
|
|
3401
3400
|
}
|
|
3402
3401
|
};
|
|
3403
3402
|
|
|
3403
|
+
// src/common/ui-utils.ts
|
|
3404
|
+
function typeStr(task) {
|
|
3405
|
+
return task.subType ? `${task.type} / ${task.subType || ""}` : task.type;
|
|
3406
|
+
}
|
|
3407
|
+
function getKeyCommands(value) {
|
|
3408
|
+
const keys = Array.isArray(value) ? value : [value];
|
|
3409
|
+
return keys.reduce((acc, k) => {
|
|
3410
|
+
const includeMeta = keys.includes("Meta") || keys.includes("Control");
|
|
3411
|
+
if (includeMeta && (k === "a" || k === "A")) {
|
|
3412
|
+
return acc.concat([{ key: k, command: "SelectAll" }]);
|
|
3413
|
+
}
|
|
3414
|
+
if (includeMeta && (k === "c" || k === "C")) {
|
|
3415
|
+
return acc.concat([{ key: k, command: "Copy" }]);
|
|
3416
|
+
}
|
|
3417
|
+
if (includeMeta && (k === "v" || k === "V")) {
|
|
3418
|
+
return acc.concat([{ key: k, command: "Paste" }]);
|
|
3419
|
+
}
|
|
3420
|
+
return acc.concat([{ key: k }]);
|
|
3421
|
+
}, []);
|
|
3422
|
+
}
|
|
3423
|
+
function paramStr(task) {
|
|
3424
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
3425
|
+
let value;
|
|
3426
|
+
if (task.type === "Planning") {
|
|
3427
|
+
value = (_a = task == null ? void 0 : task.param) == null ? void 0 : _a.userPrompt;
|
|
3428
|
+
}
|
|
3429
|
+
if (task.type === "Insight") {
|
|
3430
|
+
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);
|
|
3431
|
+
}
|
|
3432
|
+
if (task.type === "Action") {
|
|
3433
|
+
const sleepMs = (_f = task == null ? void 0 : task.param) == null ? void 0 : _f.timeMs;
|
|
3434
|
+
const scrollType = (_g = task == null ? void 0 : task.param) == null ? void 0 : _g.scrollType;
|
|
3435
|
+
if (sleepMs) {
|
|
3436
|
+
value = `${sleepMs}ms`;
|
|
3437
|
+
} else if (scrollType) {
|
|
3438
|
+
const scrollDirection = (_h = task == null ? void 0 : task.param) == null ? void 0 : _h.direction;
|
|
3439
|
+
const scrollDistance = (_i = task == null ? void 0 : task.param) == null ? void 0 : _i.distance;
|
|
3440
|
+
value = `${scrollDirection || "down"}, ${scrollType || "once"}, ${scrollDistance || "distance-not-set"}`;
|
|
3441
|
+
} else {
|
|
3442
|
+
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);
|
|
3443
|
+
}
|
|
3444
|
+
if (!value) {
|
|
3445
|
+
value = task.thought;
|
|
3446
|
+
}
|
|
3447
|
+
}
|
|
3448
|
+
if (typeof value === "undefined")
|
|
3449
|
+
return "";
|
|
3450
|
+
return typeof value === "string" ? value : JSON.stringify(value, void 0, 2);
|
|
3451
|
+
}
|
|
3452
|
+
|
|
3404
3453
|
// src/common/tasks.ts
|
|
3405
3454
|
var PageTaskExecutor = class {
|
|
3406
3455
|
constructor(page, insight, opts) {
|
|
@@ -3614,8 +3663,8 @@ var PageTaskExecutor = class {
|
|
|
3614
3663
|
thought: plan2.thought,
|
|
3615
3664
|
locate: plan2.locate,
|
|
3616
3665
|
executor: async (taskParam) => {
|
|
3617
|
-
|
|
3618
|
-
await this.page.keyboard.press(
|
|
3666
|
+
const keys = getKeyCommands(taskParam.value);
|
|
3667
|
+
await this.page.keyboard.press(keys);
|
|
3619
3668
|
}
|
|
3620
3669
|
};
|
|
3621
3670
|
tasks.push(taskActionKeyboardPress);
|
|
@@ -4023,7 +4072,7 @@ var PageTaskExecutor = class {
|
|
|
4023
4072
|
const cacheGroup = this.taskCache.getCacheGroupByPrompt(userPrompt);
|
|
4024
4073
|
const isCompleted = false;
|
|
4025
4074
|
let currentActionNumber = 0;
|
|
4026
|
-
const maxActionNumber =
|
|
4075
|
+
const maxActionNumber = 40;
|
|
4027
4076
|
while (!isCompleted && currentActionNumber < maxActionNumber) {
|
|
4028
4077
|
currentActionNumber++;
|
|
4029
4078
|
const planningTask = this.planningTaskToGoal(
|
|
@@ -4243,40 +4292,6 @@ var WebElementInfo = class {
|
|
|
4243
4292
|
}
|
|
4244
4293
|
};
|
|
4245
4294
|
|
|
4246
|
-
// src/common/ui-utils.ts
|
|
4247
|
-
function typeStr(task) {
|
|
4248
|
-
return task.subType ? `${task.type} / ${task.subType || ""}` : task.type;
|
|
4249
|
-
}
|
|
4250
|
-
function paramStr(task) {
|
|
4251
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
4252
|
-
let value;
|
|
4253
|
-
if (task.type === "Planning") {
|
|
4254
|
-
value = (_a = task == null ? void 0 : task.param) == null ? void 0 : _a.userPrompt;
|
|
4255
|
-
}
|
|
4256
|
-
if (task.type === "Insight") {
|
|
4257
|
-
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);
|
|
4258
|
-
}
|
|
4259
|
-
if (task.type === "Action") {
|
|
4260
|
-
const sleepMs = (_f = task == null ? void 0 : task.param) == null ? void 0 : _f.timeMs;
|
|
4261
|
-
const scrollType = (_g = task == null ? void 0 : task.param) == null ? void 0 : _g.scrollType;
|
|
4262
|
-
if (sleepMs) {
|
|
4263
|
-
value = `${sleepMs}ms`;
|
|
4264
|
-
} else if (scrollType) {
|
|
4265
|
-
const scrollDirection = (_h = task == null ? void 0 : task.param) == null ? void 0 : _h.direction;
|
|
4266
|
-
const scrollDistance = (_i = task == null ? void 0 : task.param) == null ? void 0 : _i.distance;
|
|
4267
|
-
value = `${scrollDirection || "down"}, ${scrollType || "once"}, ${scrollDistance || "distance-not-set"}`;
|
|
4268
|
-
} else {
|
|
4269
|
-
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);
|
|
4270
|
-
}
|
|
4271
|
-
if (!value) {
|
|
4272
|
-
value = task.thought;
|
|
4273
|
-
}
|
|
4274
|
-
}
|
|
4275
|
-
if (typeof value === "undefined")
|
|
4276
|
-
return "";
|
|
4277
|
-
return typeof value === "string" ? value : JSON.stringify(value, void 0, 2);
|
|
4278
|
-
}
|
|
4279
|
-
|
|
4280
4295
|
// src/common/utils.ts
|
|
4281
4296
|
var import_node_assert4 = __toESM(require("assert"));
|
|
4282
4297
|
var import_node_fs3 = require("fs");
|
|
@@ -4569,160 +4584,6 @@ ${errors}`);
|
|
|
4569
4584
|
}
|
|
4570
4585
|
};
|
|
4571
4586
|
|
|
4572
|
-
// src/playwright/ai-fixture.ts
|
|
4573
|
-
var import_test = require("@playwright/test");
|
|
4574
|
-
var groupAndCaseForTest = (testInfo) => {
|
|
4575
|
-
let taskFile;
|
|
4576
|
-
let taskTitle;
|
|
4577
|
-
const titlePath = [...testInfo.titlePath];
|
|
4578
|
-
if (titlePath.length > 1) {
|
|
4579
|
-
taskTitle = titlePath.pop() || "unnamed";
|
|
4580
|
-
taskFile = `${titlePath.join(" > ")}`;
|
|
4581
|
-
} else if (titlePath.length === 1) {
|
|
4582
|
-
taskTitle = titlePath[0];
|
|
4583
|
-
taskFile = `${taskTitle}`;
|
|
4584
|
-
} else {
|
|
4585
|
-
taskTitle = "unnamed";
|
|
4586
|
-
taskFile = "unnamed";
|
|
4587
|
-
}
|
|
4588
|
-
return { taskFile, taskTitle };
|
|
4589
|
-
};
|
|
4590
|
-
var midsceneAgentKeyId = "_midsceneAgentId";
|
|
4591
|
-
var midsceneDumpAnnotationId = "MIDSCENE_DUMP_ANNOTATION";
|
|
4592
|
-
var PlaywrightAiFixture = () => {
|
|
4593
|
-
const pageAgentMap = {};
|
|
4594
|
-
const agentForPage = (page, testInfo) => {
|
|
4595
|
-
let idForPage = page[midsceneAgentKeyId];
|
|
4596
|
-
if (!idForPage) {
|
|
4597
|
-
idForPage = (0, import_node_crypto.randomUUID)();
|
|
4598
|
-
page[midsceneAgentKeyId] = idForPage;
|
|
4599
|
-
const { testId } = testInfo;
|
|
4600
|
-
const { taskFile, taskTitle } = groupAndCaseForTest(testInfo);
|
|
4601
|
-
pageAgentMap[idForPage] = new PageAgent(new WebPage(page), {
|
|
4602
|
-
testId: `playwright-${testId}-${idForPage}`,
|
|
4603
|
-
cacheId: `${taskFile}(${taskTitle})`,
|
|
4604
|
-
groupName: taskTitle,
|
|
4605
|
-
groupDescription: taskFile,
|
|
4606
|
-
generateReport: false
|
|
4607
|
-
// we will generate it in the reporter
|
|
4608
|
-
});
|
|
4609
|
-
}
|
|
4610
|
-
return pageAgentMap[idForPage];
|
|
4611
|
-
};
|
|
4612
|
-
const updateDumpAnnotation = (test2, dump2) => {
|
|
4613
|
-
const currentAnnotation = test2.annotations.find((item) => {
|
|
4614
|
-
return item.type === midsceneDumpAnnotationId;
|
|
4615
|
-
});
|
|
4616
|
-
if (currentAnnotation) {
|
|
4617
|
-
currentAnnotation.description = dump2;
|
|
4618
|
-
} else {
|
|
4619
|
-
test2.annotations.push({
|
|
4620
|
-
type: midsceneDumpAnnotationId,
|
|
4621
|
-
description: dump2
|
|
4622
|
-
});
|
|
4623
|
-
}
|
|
4624
|
-
};
|
|
4625
|
-
return {
|
|
4626
|
-
ai: async ({ page }, use, testInfo) => {
|
|
4627
|
-
const agent = agentForPage(page, testInfo);
|
|
4628
|
-
await use(
|
|
4629
|
-
async (taskPrompt, opts) => {
|
|
4630
|
-
return new Promise((resolve, reject) => {
|
|
4631
|
-
import_test.test.step(`ai - ${taskPrompt}`, async () => {
|
|
4632
|
-
await waitForNetworkIdle(page);
|
|
4633
|
-
const actionType = (opts == null ? void 0 : opts.type) || "action";
|
|
4634
|
-
try {
|
|
4635
|
-
const result = await agent.ai(taskPrompt, actionType);
|
|
4636
|
-
resolve(result);
|
|
4637
|
-
} catch (error) {
|
|
4638
|
-
reject(error);
|
|
4639
|
-
}
|
|
4640
|
-
});
|
|
4641
|
-
});
|
|
4642
|
-
}
|
|
4643
|
-
);
|
|
4644
|
-
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4645
|
-
},
|
|
4646
|
-
aiAction: async ({ page }, use, testInfo) => {
|
|
4647
|
-
const agent = agentForPage(page, testInfo);
|
|
4648
|
-
await use(async (taskPrompt) => {
|
|
4649
|
-
return new Promise((resolve, reject) => {
|
|
4650
|
-
import_test.test.step(`aiAction - ${taskPrompt}`, async () => {
|
|
4651
|
-
await waitForNetworkIdle(page);
|
|
4652
|
-
try {
|
|
4653
|
-
const result = await agent.aiAction(taskPrompt);
|
|
4654
|
-
resolve(result);
|
|
4655
|
-
} catch (error) {
|
|
4656
|
-
reject(error);
|
|
4657
|
-
}
|
|
4658
|
-
});
|
|
4659
|
-
});
|
|
4660
|
-
});
|
|
4661
|
-
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4662
|
-
},
|
|
4663
|
-
aiQuery: async ({ page }, use, testInfo) => {
|
|
4664
|
-
const agent = agentForPage(page, testInfo);
|
|
4665
|
-
await use(async (demand) => {
|
|
4666
|
-
return new Promise((resolve, reject) => {
|
|
4667
|
-
import_test.test.step(`aiQuery - ${JSON.stringify(demand)}`, async () => {
|
|
4668
|
-
await waitForNetworkIdle(page);
|
|
4669
|
-
try {
|
|
4670
|
-
const result = await agent.aiQuery(demand);
|
|
4671
|
-
resolve(result);
|
|
4672
|
-
} catch (error) {
|
|
4673
|
-
reject(error);
|
|
4674
|
-
}
|
|
4675
|
-
});
|
|
4676
|
-
});
|
|
4677
|
-
});
|
|
4678
|
-
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4679
|
-
},
|
|
4680
|
-
aiAssert: async ({ page }, use, testInfo) => {
|
|
4681
|
-
const agent = agentForPage(page, testInfo);
|
|
4682
|
-
await use(async (assertion, errorMsg) => {
|
|
4683
|
-
return new Promise((resolve, reject) => {
|
|
4684
|
-
import_test.test.step(`aiAssert - ${assertion}`, async () => {
|
|
4685
|
-
await waitForNetworkIdle(page);
|
|
4686
|
-
try {
|
|
4687
|
-
await agent.aiAssert(assertion, errorMsg);
|
|
4688
|
-
resolve(null);
|
|
4689
|
-
} catch (error) {
|
|
4690
|
-
reject(error);
|
|
4691
|
-
}
|
|
4692
|
-
});
|
|
4693
|
-
});
|
|
4694
|
-
});
|
|
4695
|
-
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4696
|
-
},
|
|
4697
|
-
aiWaitFor: async ({ page }, use, testInfo) => {
|
|
4698
|
-
const agent = agentForPage(page, testInfo);
|
|
4699
|
-
await use(async (assertion, opt) => {
|
|
4700
|
-
return new Promise((resolve, reject) => {
|
|
4701
|
-
import_test.test.step(`aiWaitFor - ${assertion}`, async () => {
|
|
4702
|
-
await waitForNetworkIdle(page);
|
|
4703
|
-
try {
|
|
4704
|
-
await agent.aiWaitFor(assertion, opt);
|
|
4705
|
-
resolve(null);
|
|
4706
|
-
} catch (error) {
|
|
4707
|
-
reject(error);
|
|
4708
|
-
}
|
|
4709
|
-
});
|
|
4710
|
-
});
|
|
4711
|
-
});
|
|
4712
|
-
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4713
|
-
}
|
|
4714
|
-
};
|
|
4715
|
-
};
|
|
4716
|
-
async function waitForNetworkIdle(page, timeout = 2e4) {
|
|
4717
|
-
try {
|
|
4718
|
-
await page.waitForLoadState("networkidle", { timeout });
|
|
4719
|
-
} catch (error) {
|
|
4720
|
-
console.warn(
|
|
4721
|
-
`Network idle timeout exceeded: ${error instanceof Error ? error.message : String(error)}`
|
|
4722
|
-
);
|
|
4723
|
-
}
|
|
4724
|
-
}
|
|
4725
|
-
|
|
4726
4587
|
// src/puppeteer/base-page.ts
|
|
4727
4588
|
var import_utils9 = require("@midscene/core/utils");
|
|
4728
4589
|
var import_extractor2 = require("@midscene/shared/extractor");
|
|
@@ -4738,12 +4599,19 @@ var Page = class {
|
|
|
4738
4599
|
this.underlyingPage = underlyingPage;
|
|
4739
4600
|
this.pageType = pageType;
|
|
4740
4601
|
}
|
|
4602
|
+
async waitForNavigation() {
|
|
4603
|
+
if (this.pageType === "puppeteer" || this.pageType === "playwright") {
|
|
4604
|
+
await this.underlyingPage.waitForSelector("html");
|
|
4605
|
+
}
|
|
4606
|
+
}
|
|
4741
4607
|
// @deprecated
|
|
4742
4608
|
async getElementsInfo() {
|
|
4609
|
+
await this.waitForNavigation();
|
|
4743
4610
|
const tree = await this.getElementsNodeTree();
|
|
4744
4611
|
return (0, import_extractor2.treeToList)(tree);
|
|
4745
4612
|
}
|
|
4746
4613
|
async getElementsNodeTree() {
|
|
4614
|
+
await this.waitForNavigation();
|
|
4747
4615
|
const scripts = await getExtraReturnLogic(true);
|
|
4748
4616
|
const captureElementSnapshot = await this.evaluate(scripts);
|
|
4749
4617
|
return captureElementSnapshot;
|
|
@@ -4764,6 +4632,7 @@ var Page = class {
|
|
|
4764
4632
|
async screenshotBase64() {
|
|
4765
4633
|
const imgType = "jpeg";
|
|
4766
4634
|
const path2 = (0, import_utils9.getTmpFile)(imgType);
|
|
4635
|
+
await this.waitForNavigation();
|
|
4767
4636
|
await this.underlyingPage.screenshot({
|
|
4768
4637
|
path: path2,
|
|
4769
4638
|
type: imgType,
|
|
@@ -4821,13 +4690,14 @@ var Page = class {
|
|
|
4821
4690
|
get keyboard() {
|
|
4822
4691
|
return {
|
|
4823
4692
|
type: async (text) => this.underlyingPage.keyboard.type(text, { delay: 80 }),
|
|
4824
|
-
press: async (
|
|
4825
|
-
const keys = Array.isArray(
|
|
4826
|
-
for (const
|
|
4827
|
-
|
|
4693
|
+
press: async (action) => {
|
|
4694
|
+
const keys = Array.isArray(action) ? action : [action];
|
|
4695
|
+
for (const k of keys) {
|
|
4696
|
+
const commands = k.command ? [k.command] : [];
|
|
4697
|
+
await this.underlyingPage.keyboard.down(k.key, { commands });
|
|
4828
4698
|
}
|
|
4829
|
-
for (const
|
|
4830
|
-
await this.underlyingPage.keyboard.up(
|
|
4699
|
+
for (const k of [...keys].reverse()) {
|
|
4700
|
+
await this.underlyingPage.keyboard.up(k.key);
|
|
4831
4701
|
}
|
|
4832
4702
|
},
|
|
4833
4703
|
down: async (key) => {
|
|
@@ -4862,7 +4732,7 @@ var Page = class {
|
|
|
4862
4732
|
await this.underlyingPage.keyboard.up("Control");
|
|
4863
4733
|
}
|
|
4864
4734
|
await (0, import_utils9.sleep)(100);
|
|
4865
|
-
await this.keyboard.press("Backspace");
|
|
4735
|
+
await this.keyboard.press([{ key: "Backspace" }]);
|
|
4866
4736
|
}
|
|
4867
4737
|
async moveToPoint(point) {
|
|
4868
4738
|
if (point) {
|
|
@@ -4923,8 +4793,186 @@ var WebPage = class extends Page {
|
|
|
4923
4793
|
}
|
|
4924
4794
|
};
|
|
4925
4795
|
|
|
4796
|
+
// src/playwright/ai-fixture.ts
|
|
4797
|
+
var import_node_crypto = require("crypto");
|
|
4798
|
+
var import_test = require("@playwright/test");
|
|
4799
|
+
var groupAndCaseForTest = (testInfo) => {
|
|
4800
|
+
let taskFile;
|
|
4801
|
+
let taskTitle;
|
|
4802
|
+
const titlePath = [...testInfo.titlePath];
|
|
4803
|
+
if (titlePath.length > 1) {
|
|
4804
|
+
taskTitle = titlePath.pop() || "unnamed";
|
|
4805
|
+
taskFile = `${titlePath.join(" > ")}`;
|
|
4806
|
+
} else if (titlePath.length === 1) {
|
|
4807
|
+
taskTitle = titlePath[0];
|
|
4808
|
+
taskFile = `${taskTitle}`;
|
|
4809
|
+
} else {
|
|
4810
|
+
taskTitle = "unnamed";
|
|
4811
|
+
taskFile = "unnamed";
|
|
4812
|
+
}
|
|
4813
|
+
return { taskFile, taskTitle };
|
|
4814
|
+
};
|
|
4815
|
+
var midsceneAgentKeyId = "_midsceneAgentId";
|
|
4816
|
+
var midsceneDumpAnnotationId = "MIDSCENE_DUMP_ANNOTATION";
|
|
4817
|
+
var PlaywrightAiFixture = (options) => {
|
|
4818
|
+
const { forceSameTabNavigation = true } = options != null ? options : {};
|
|
4819
|
+
const pageAgentMap = {};
|
|
4820
|
+
const agentForPage = (page, testInfo) => {
|
|
4821
|
+
let idForPage = page[midsceneAgentKeyId];
|
|
4822
|
+
if (!idForPage) {
|
|
4823
|
+
idForPage = (0, import_node_crypto.randomUUID)();
|
|
4824
|
+
page[midsceneAgentKeyId] = idForPage;
|
|
4825
|
+
const { testId } = testInfo;
|
|
4826
|
+
const { taskFile, taskTitle } = groupAndCaseForTest(testInfo);
|
|
4827
|
+
pageAgentMap[idForPage] = new PlaywrightAgent(page, {
|
|
4828
|
+
testId: `playwright-${testId}-${idForPage}`,
|
|
4829
|
+
forceSameTabNavigation,
|
|
4830
|
+
cacheId: `${taskFile}(${taskTitle})`,
|
|
4831
|
+
groupName: taskTitle,
|
|
4832
|
+
groupDescription: taskFile,
|
|
4833
|
+
generateReport: false
|
|
4834
|
+
// we will generate it in the reporter
|
|
4835
|
+
});
|
|
4836
|
+
}
|
|
4837
|
+
return pageAgentMap[idForPage];
|
|
4838
|
+
};
|
|
4839
|
+
const updateDumpAnnotation = (test2, dump2) => {
|
|
4840
|
+
const currentAnnotation = test2.annotations.find((item) => {
|
|
4841
|
+
return item.type === midsceneDumpAnnotationId;
|
|
4842
|
+
});
|
|
4843
|
+
if (currentAnnotation) {
|
|
4844
|
+
currentAnnotation.description = dump2;
|
|
4845
|
+
} else {
|
|
4846
|
+
test2.annotations.push({
|
|
4847
|
+
type: midsceneDumpAnnotationId,
|
|
4848
|
+
description: dump2
|
|
4849
|
+
});
|
|
4850
|
+
}
|
|
4851
|
+
};
|
|
4852
|
+
return {
|
|
4853
|
+
ai: async ({ page }, use, testInfo) => {
|
|
4854
|
+
const agent = agentForPage(page, testInfo);
|
|
4855
|
+
await use(
|
|
4856
|
+
async (taskPrompt, opts) => {
|
|
4857
|
+
return new Promise((resolve, reject) => {
|
|
4858
|
+
const { type: type2 = "action" } = opts || {};
|
|
4859
|
+
import_test.test.step(`ai - ${taskPrompt}`, async () => {
|
|
4860
|
+
await waitForNetworkIdle(page);
|
|
4861
|
+
try {
|
|
4862
|
+
const result = await agent.ai(taskPrompt, type2);
|
|
4863
|
+
resolve(result);
|
|
4864
|
+
} catch (error) {
|
|
4865
|
+
reject(error);
|
|
4866
|
+
}
|
|
4867
|
+
});
|
|
4868
|
+
});
|
|
4869
|
+
}
|
|
4870
|
+
);
|
|
4871
|
+
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4872
|
+
},
|
|
4873
|
+
aiAction: async ({ page }, use, testInfo) => {
|
|
4874
|
+
const agent = agentForPage(page, testInfo);
|
|
4875
|
+
await use(async (taskPrompt) => {
|
|
4876
|
+
return new Promise((resolve, reject) => {
|
|
4877
|
+
import_test.test.step(`aiAction - ${taskPrompt}`, async () => {
|
|
4878
|
+
await waitForNetworkIdle(page);
|
|
4879
|
+
try {
|
|
4880
|
+
const result = await agent.aiAction(taskPrompt);
|
|
4881
|
+
resolve(result);
|
|
4882
|
+
} catch (error) {
|
|
4883
|
+
reject(error);
|
|
4884
|
+
}
|
|
4885
|
+
});
|
|
4886
|
+
});
|
|
4887
|
+
});
|
|
4888
|
+
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4889
|
+
},
|
|
4890
|
+
aiQuery: async ({ page }, use, testInfo) => {
|
|
4891
|
+
const agent = agentForPage(page, testInfo);
|
|
4892
|
+
await use(async (demand) => {
|
|
4893
|
+
return new Promise((resolve, reject) => {
|
|
4894
|
+
import_test.test.step(`aiQuery - ${JSON.stringify(demand)}`, async () => {
|
|
4895
|
+
await waitForNetworkIdle(page);
|
|
4896
|
+
try {
|
|
4897
|
+
const result = await agent.aiQuery(demand);
|
|
4898
|
+
resolve(result);
|
|
4899
|
+
} catch (error) {
|
|
4900
|
+
reject(error);
|
|
4901
|
+
}
|
|
4902
|
+
});
|
|
4903
|
+
});
|
|
4904
|
+
});
|
|
4905
|
+
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4906
|
+
},
|
|
4907
|
+
aiAssert: async ({ page }, use, testInfo) => {
|
|
4908
|
+
const agent = agentForPage(page, testInfo);
|
|
4909
|
+
await use(async (assertion, errorMsg) => {
|
|
4910
|
+
return new Promise((resolve, reject) => {
|
|
4911
|
+
import_test.test.step(`aiAssert - ${assertion}`, async () => {
|
|
4912
|
+
await waitForNetworkIdle(page);
|
|
4913
|
+
try {
|
|
4914
|
+
await agent.aiAssert(assertion, errorMsg);
|
|
4915
|
+
resolve(null);
|
|
4916
|
+
} catch (error) {
|
|
4917
|
+
reject(error);
|
|
4918
|
+
}
|
|
4919
|
+
});
|
|
4920
|
+
});
|
|
4921
|
+
});
|
|
4922
|
+
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4923
|
+
},
|
|
4924
|
+
aiWaitFor: async ({ page }, use, testInfo) => {
|
|
4925
|
+
const agent = agentForPage(page, testInfo);
|
|
4926
|
+
await use(async (assertion, opt) => {
|
|
4927
|
+
return new Promise((resolve, reject) => {
|
|
4928
|
+
import_test.test.step(`aiWaitFor - ${assertion}`, async () => {
|
|
4929
|
+
await waitForNetworkIdle(page);
|
|
4930
|
+
try {
|
|
4931
|
+
await agent.aiWaitFor(assertion, opt);
|
|
4932
|
+
resolve(null);
|
|
4933
|
+
} catch (error) {
|
|
4934
|
+
reject(error);
|
|
4935
|
+
}
|
|
4936
|
+
});
|
|
4937
|
+
});
|
|
4938
|
+
});
|
|
4939
|
+
updateDumpAnnotation(testInfo, agent.dumpDataString());
|
|
4940
|
+
}
|
|
4941
|
+
};
|
|
4942
|
+
};
|
|
4943
|
+
async function waitForNetworkIdle(page, timeout = 2e4) {
|
|
4944
|
+
try {
|
|
4945
|
+
await page.waitForLoadState("networkidle", { timeout });
|
|
4946
|
+
} catch (error) {
|
|
4947
|
+
console.warn(
|
|
4948
|
+
`Network idle timeout exceeded: ${error instanceof Error ? error.message : String(error)}`
|
|
4949
|
+
);
|
|
4950
|
+
}
|
|
4951
|
+
}
|
|
4952
|
+
|
|
4926
4953
|
// src/playwright/index.ts
|
|
4927
4954
|
var import_env4 = require("@midscene/core/env");
|
|
4955
|
+
var PlaywrightAgent = class extends PageAgent {
|
|
4956
|
+
constructor(page, opts) {
|
|
4957
|
+
const webPage = new WebPage(page);
|
|
4958
|
+
super(webPage, opts);
|
|
4959
|
+
const { forceSameTabNavigation = true } = opts != null ? opts : {};
|
|
4960
|
+
if (forceSameTabNavigation) {
|
|
4961
|
+
page.on("popup", async (popup) => {
|
|
4962
|
+
if (!popup) {
|
|
4963
|
+
console.warn(
|
|
4964
|
+
"got a popup event, but the popup is not ready yet, skip"
|
|
4965
|
+
);
|
|
4966
|
+
return;
|
|
4967
|
+
}
|
|
4968
|
+
const url = await popup.url();
|
|
4969
|
+
console.log(`Popup opened: ${url}`);
|
|
4970
|
+
await popup.close();
|
|
4971
|
+
await page.goto(url);
|
|
4972
|
+
});
|
|
4973
|
+
}
|
|
4974
|
+
}
|
|
4975
|
+
};
|
|
4928
4976
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4929
4977
|
0 && (module.exports = {
|
|
4930
4978
|
PlaywrightAgent,
|