@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.
Files changed (36) hide show
  1. package/dist/es/appium.js +84 -39
  2. package/dist/es/bridge-mode-browser.js +58 -19
  3. package/dist/es/bridge-mode.js +61 -43
  4. package/dist/es/chrome-extension.js +104 -51
  5. package/dist/es/index.js +291 -218
  6. package/dist/es/midscene-playground.js +56 -38
  7. package/dist/es/playground.js +56 -38
  8. package/dist/es/playwright.js +251 -203
  9. package/dist/es/puppeteer.js +85 -60
  10. package/dist/es/ui-utils.js +43 -0
  11. package/dist/lib/appium.js +84 -39
  12. package/dist/lib/bridge-mode-browser.js +58 -19
  13. package/dist/lib/bridge-mode.js +61 -43
  14. package/dist/lib/chrome-extension.js +104 -51
  15. package/dist/lib/index.js +291 -218
  16. package/dist/lib/midscene-playground.js +56 -38
  17. package/dist/lib/playground.js +56 -38
  18. package/dist/lib/playwright.js +251 -203
  19. package/dist/lib/puppeteer.js +85 -60
  20. package/dist/lib/ui-utils.js +43 -0
  21. package/dist/types/{tasks-d5a01262.d.ts → agent-ac363fa3.d.ts} +41 -41
  22. package/dist/types/appium.d.ts +2 -2
  23. package/dist/types/bridge-mode-browser.d.ts +2 -2
  24. package/dist/types/bridge-mode.d.ts +3 -3
  25. package/dist/types/{browser-7d5614fb.d.ts → browser-eae1a5c1.d.ts} +4 -4
  26. package/dist/types/chrome-extension.d.ts +3 -3
  27. package/dist/types/index.d.ts +8 -8
  28. package/dist/types/{page-77af8d5f.d.ts → page-cf0f892e.d.ts} +32 -6
  29. package/dist/types/playground.d.ts +3 -3
  30. package/dist/types/playwright.d.ts +12 -6
  31. package/dist/types/puppeteer.d.ts +2 -2
  32. package/dist/types/ui-utils.d.ts +6 -1
  33. package/dist/types/{utils-1a3bc661.d.ts → utils-9a29bfa0.d.ts} +1 -1
  34. package/dist/types/utils.d.ts +1 -1
  35. package/dist/types/yaml.d.ts +3 -3
  36. package/package.json +6 -6
package/dist/lib/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) {
@@ -3654,8 +3703,8 @@ var PageTaskExecutor = class {
3654
3703
  thought: plan2.thought,
3655
3704
  locate: plan2.locate,
3656
3705
  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);
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 = 20;
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 (key) => {
4865
- const keys = Array.isArray(key) ? key : [key];
4866
- for (const key2 of keys) {
4867
- await this.underlyingPage.keyboard.down(key2);
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 key2 of [...keys].reverse()) {
4870
- await this.underlyingPage.keyboard.up(key2);
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
- 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;
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: (key) => this.keyboardPress(key)
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([