@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.
Files changed (38) hide show
  1. package/dist/es/appium.js +85 -39
  2. package/dist/es/bridge-mode-browser.js +58 -19
  3. package/dist/es/bridge-mode.js +62 -43
  4. package/dist/es/chrome-extension.js +105 -51
  5. package/dist/es/index.js +292 -218
  6. package/dist/es/midscene-playground.js +57 -38
  7. package/dist/es/playground.js +57 -38
  8. package/dist/es/playwright-report.js +4 -0
  9. package/dist/es/playwright.js +252 -203
  10. package/dist/es/puppeteer.js +86 -60
  11. package/dist/es/ui-utils.js +43 -0
  12. package/dist/lib/appium.js +85 -39
  13. package/dist/lib/bridge-mode-browser.js +58 -19
  14. package/dist/lib/bridge-mode.js +62 -43
  15. package/dist/lib/chrome-extension.js +105 -51
  16. package/dist/lib/index.js +292 -218
  17. package/dist/lib/midscene-playground.js +57 -38
  18. package/dist/lib/playground.js +57 -38
  19. package/dist/lib/playwright-report.js +4 -0
  20. package/dist/lib/playwright.js +252 -203
  21. package/dist/lib/puppeteer.js +86 -60
  22. package/dist/lib/ui-utils.js +43 -0
  23. package/dist/types/{tasks-d5a01262.d.ts → agent-ae110e80.d.ts} +43 -43
  24. package/dist/types/appium.d.ts +3 -3
  25. package/dist/types/bridge-mode-browser.d.ts +3 -3
  26. package/dist/types/bridge-mode.d.ts +4 -4
  27. package/dist/types/{browser-7d5614fb.d.ts → browser-9d620553.d.ts} +4 -4
  28. package/dist/types/chrome-extension.d.ts +4 -4
  29. package/dist/types/index.d.ts +8 -8
  30. package/dist/types/{page-77af8d5f.d.ts → page-97720803.d.ts} +34 -8
  31. package/dist/types/playground.d.ts +4 -4
  32. package/dist/types/playwright.d.ts +13 -7
  33. package/dist/types/puppeteer.d.ts +3 -3
  34. package/dist/types/ui-utils.d.ts +6 -1
  35. package/dist/types/{utils-1a3bc661.d.ts → utils-93b3f5f3.d.ts} +1 -1
  36. package/dist/types/utils.d.ts +2 -2
  37. package/dist/types/yaml.d.ts +4 -4
  38. 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: () => PageAgent,
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
- if (jsonData.pkgName !== this.midscenePkgInfo.name || jsonData.pkgVersion !== this.midscenePkgInfo.version) {
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
- (0, import_node_assert3.default)(taskParam == null ? void 0 : taskParam.value, "No key to press");
3658
- await this.page.keyboard.press(taskParam.value);
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 = 20;
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 (key) => {
4865
- const keys = Array.isArray(key) ? key : [key];
4866
- for (const key2 of keys) {
4867
- await this.underlyingPage.keyboard.down(key2);
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 key2 of [...keys].reverse()) {
4870
- await this.underlyingPage.keyboard.up(key2);
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
- if (opts == null ? void 0 : opts.trackingActiveTab) {
4998
- const browser = this.page.underlyingPage.browser();
4999
- browser.on("targetcreated", async (target) => {
5000
- if (target.type() === "page") {
5001
- const targetPage = await target.page();
5002
- if (!targetPage) {
5003
- console.warn(
5004
- "got a targetPage event, but the page is not ready yet, skip"
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: (key) => this.keyboardPress(key)
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([