@donggui/web 1.5.5-donggui.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 (166) hide show
  1. package/README.md +9 -0
  2. package/bin/midscene-playground +3 -0
  3. package/bin/midscene-web +2 -0
  4. package/dist/es/bin.mjs +23 -0
  5. package/dist/es/bin.mjs.map +1 -0
  6. package/dist/es/bridge-mode/agent-cli-side.mjs +137 -0
  7. package/dist/es/bridge-mode/agent-cli-side.mjs.map +1 -0
  8. package/dist/es/bridge-mode/browser.mjs +2 -0
  9. package/dist/es/bridge-mode/common.mjs +43 -0
  10. package/dist/es/bridge-mode/common.mjs.map +1 -0
  11. package/dist/es/bridge-mode/index.mjs +4 -0
  12. package/dist/es/bridge-mode/io-client.mjs +101 -0
  13. package/dist/es/bridge-mode/io-client.mjs.map +1 -0
  14. package/dist/es/bridge-mode/io-server.mjs +210 -0
  15. package/dist/es/bridge-mode/io-server.mjs.map +1 -0
  16. package/dist/es/bridge-mode/page-browser-side.mjs +118 -0
  17. package/dist/es/bridge-mode/page-browser-side.mjs.map +1 -0
  18. package/dist/es/chrome-extension/agent.mjs +9 -0
  19. package/dist/es/chrome-extension/agent.mjs.map +1 -0
  20. package/dist/es/chrome-extension/cdpInput.mjs +174 -0
  21. package/dist/es/chrome-extension/cdpInput.mjs.LICENSE.txt +5 -0
  22. package/dist/es/chrome-extension/cdpInput.mjs.map +1 -0
  23. package/dist/es/chrome-extension/dynamic-scripts.mjs +38 -0
  24. package/dist/es/chrome-extension/dynamic-scripts.mjs.map +1 -0
  25. package/dist/es/chrome-extension/index.mjs +5 -0
  26. package/dist/es/chrome-extension/page.mjs +651 -0
  27. package/dist/es/chrome-extension/page.mjs.map +1 -0
  28. package/dist/es/cli.mjs +16 -0
  29. package/dist/es/cli.mjs.map +1 -0
  30. package/dist/es/common/cache-helper.mjs +28 -0
  31. package/dist/es/common/cache-helper.mjs.map +1 -0
  32. package/dist/es/index.mjs +6 -0
  33. package/dist/es/mcp-server.mjs +35 -0
  34. package/dist/es/mcp-server.mjs.map +1 -0
  35. package/dist/es/mcp-tools-puppeteer.mjs +215 -0
  36. package/dist/es/mcp-tools-puppeteer.mjs.map +1 -0
  37. package/dist/es/mcp-tools.mjs +78 -0
  38. package/dist/es/mcp-tools.mjs.map +1 -0
  39. package/dist/es/playwright/ai-fixture.mjs +367 -0
  40. package/dist/es/playwright/ai-fixture.mjs.map +1 -0
  41. package/dist/es/playwright/index.mjs +40 -0
  42. package/dist/es/playwright/index.mjs.map +1 -0
  43. package/dist/es/playwright/page.mjs +44 -0
  44. package/dist/es/playwright/page.mjs.map +1 -0
  45. package/dist/es/playwright/reporter/index.mjs +216 -0
  46. package/dist/es/playwright/reporter/index.mjs.map +1 -0
  47. package/dist/es/puppeteer/agent-launcher.mjs +185 -0
  48. package/dist/es/puppeteer/agent-launcher.mjs.map +1 -0
  49. package/dist/es/puppeteer/base-page.mjs +564 -0
  50. package/dist/es/puppeteer/base-page.mjs.map +1 -0
  51. package/dist/es/puppeteer/index.mjs +34 -0
  52. package/dist/es/puppeteer/index.mjs.map +1 -0
  53. package/dist/es/puppeteer/page.mjs +9 -0
  54. package/dist/es/puppeteer/page.mjs.map +1 -0
  55. package/dist/es/static/index.mjs +3 -0
  56. package/dist/es/static/static-agent.mjs +12 -0
  57. package/dist/es/static/static-agent.mjs.map +1 -0
  58. package/dist/es/static/static-page.mjs +122 -0
  59. package/dist/es/static/static-page.mjs.map +1 -0
  60. package/dist/es/utils.mjs +8 -0
  61. package/dist/es/utils.mjs.map +1 -0
  62. package/dist/es/web-element.mjs +59 -0
  63. package/dist/es/web-element.mjs.map +1 -0
  64. package/dist/es/web-page.mjs +260 -0
  65. package/dist/es/web-page.mjs.map +1 -0
  66. package/dist/lib/bin.js +29 -0
  67. package/dist/lib/bin.js.map +1 -0
  68. package/dist/lib/bridge-mode/agent-cli-side.js +174 -0
  69. package/dist/lib/bridge-mode/agent-cli-side.js.map +1 -0
  70. package/dist/lib/bridge-mode/browser.js +38 -0
  71. package/dist/lib/bridge-mode/browser.js.map +1 -0
  72. package/dist/lib/bridge-mode/common.js +107 -0
  73. package/dist/lib/bridge-mode/common.js.map +1 -0
  74. package/dist/lib/bridge-mode/index.js +46 -0
  75. package/dist/lib/bridge-mode/index.js.map +1 -0
  76. package/dist/lib/bridge-mode/io-client.js +135 -0
  77. package/dist/lib/bridge-mode/io-client.js.map +1 -0
  78. package/dist/lib/bridge-mode/io-server.js +247 -0
  79. package/dist/lib/bridge-mode/io-server.js.map +1 -0
  80. package/dist/lib/bridge-mode/page-browser-side.js +162 -0
  81. package/dist/lib/bridge-mode/page-browser-side.js.map +1 -0
  82. package/dist/lib/chrome-extension/agent.js +43 -0
  83. package/dist/lib/chrome-extension/agent.js.map +1 -0
  84. package/dist/lib/chrome-extension/cdpInput.js +208 -0
  85. package/dist/lib/chrome-extension/cdpInput.js.LICENSE.txt +5 -0
  86. package/dist/lib/chrome-extension/cdpInput.js.map +1 -0
  87. package/dist/lib/chrome-extension/dynamic-scripts.js +88 -0
  88. package/dist/lib/chrome-extension/dynamic-scripts.js.map +1 -0
  89. package/dist/lib/chrome-extension/index.js +60 -0
  90. package/dist/lib/chrome-extension/index.js.map +1 -0
  91. package/dist/lib/chrome-extension/page.js +685 -0
  92. package/dist/lib/chrome-extension/page.js.map +1 -0
  93. package/dist/lib/cli.js +22 -0
  94. package/dist/lib/cli.js.map +1 -0
  95. package/dist/lib/common/cache-helper.js +68 -0
  96. package/dist/lib/common/cache-helper.js.map +1 -0
  97. package/dist/lib/index.js +60 -0
  98. package/dist/lib/index.js.map +1 -0
  99. package/dist/lib/mcp-server.js +75 -0
  100. package/dist/lib/mcp-server.js.map +1 -0
  101. package/dist/lib/mcp-tools-puppeteer.js +259 -0
  102. package/dist/lib/mcp-tools-puppeteer.js.map +1 -0
  103. package/dist/lib/mcp-tools.js +112 -0
  104. package/dist/lib/mcp-tools.js.map +1 -0
  105. package/dist/lib/playwright/ai-fixture.js +404 -0
  106. package/dist/lib/playwright/ai-fixture.js.map +1 -0
  107. package/dist/lib/playwright/index.js +93 -0
  108. package/dist/lib/playwright/index.js.map +1 -0
  109. package/dist/lib/playwright/page.js +78 -0
  110. package/dist/lib/playwright/page.js.map +1 -0
  111. package/dist/lib/playwright/reporter/index.js +250 -0
  112. package/dist/lib/playwright/reporter/index.js.map +1 -0
  113. package/dist/lib/puppeteer/agent-launcher.js +253 -0
  114. package/dist/lib/puppeteer/agent-launcher.js.map +1 -0
  115. package/dist/lib/puppeteer/base-page.js +607 -0
  116. package/dist/lib/puppeteer/base-page.js.map +1 -0
  117. package/dist/lib/puppeteer/index.js +84 -0
  118. package/dist/lib/puppeteer/index.js.map +1 -0
  119. package/dist/lib/puppeteer/page.js +43 -0
  120. package/dist/lib/puppeteer/page.js.map +1 -0
  121. package/dist/lib/static/index.js +52 -0
  122. package/dist/lib/static/index.js.map +1 -0
  123. package/dist/lib/static/static-agent.js +46 -0
  124. package/dist/lib/static/static-agent.js.map +1 -0
  125. package/dist/lib/static/static-page.js +156 -0
  126. package/dist/lib/static/static-page.js.map +1 -0
  127. package/dist/lib/utils.js +40 -0
  128. package/dist/lib/utils.js.map +1 -0
  129. package/dist/lib/web-element.js +96 -0
  130. package/dist/lib/web-element.js.map +1 -0
  131. package/dist/lib/web-page.js +310 -0
  132. package/dist/lib/web-page.js.map +1 -0
  133. package/dist/types/bin.d.ts +1 -0
  134. package/dist/types/bridge-mode/agent-cli-side.d.ts +49 -0
  135. package/dist/types/bridge-mode/browser.d.ts +2 -0
  136. package/dist/types/bridge-mode/common.d.ts +74 -0
  137. package/dist/types/bridge-mode/index.d.ts +4 -0
  138. package/dist/types/bridge-mode/io-client.d.ts +10 -0
  139. package/dist/types/bridge-mode/io-server.d.ts +27 -0
  140. package/dist/types/bridge-mode/page-browser-side.d.ts +21 -0
  141. package/dist/types/chrome-extension/agent.d.ts +5 -0
  142. package/dist/types/chrome-extension/cdpInput.d.ts +52 -0
  143. package/dist/types/chrome-extension/dynamic-scripts.d.ts +3 -0
  144. package/dist/types/chrome-extension/index.d.ts +5 -0
  145. package/dist/types/chrome-extension/page.d.ts +110 -0
  146. package/dist/types/cli.d.ts +1 -0
  147. package/dist/types/common/cache-helper.d.ts +20 -0
  148. package/dist/types/index.d.ts +7 -0
  149. package/dist/types/mcp-server.d.ts +26 -0
  150. package/dist/types/mcp-tools-puppeteer.d.ts +13 -0
  151. package/dist/types/mcp-tools.d.ts +12 -0
  152. package/dist/types/playwright/ai-fixture.d.ts +131 -0
  153. package/dist/types/playwright/index.d.ts +13 -0
  154. package/dist/types/playwright/page.d.ts +11 -0
  155. package/dist/types/playwright/reporter/index.d.ts +42 -0
  156. package/dist/types/puppeteer/agent-launcher.d.ts +61 -0
  157. package/dist/types/puppeteer/base-page.d.ts +106 -0
  158. package/dist/types/puppeteer/index.d.ts +10 -0
  159. package/dist/types/puppeteer/page.d.ts +6 -0
  160. package/dist/types/static/index.d.ts +2 -0
  161. package/dist/types/static/static-agent.d.ts +5 -0
  162. package/dist/types/static/static-page.d.ts +42 -0
  163. package/dist/types/utils.d.ts +6 -0
  164. package/dist/types/web-element.d.ts +48 -0
  165. package/dist/types/web-page.d.ts +62 -0
  166. package/package.json +166 -0
@@ -0,0 +1,564 @@
1
+ import { sleep } from "@midscene/core/utils";
2
+ import { DEFAULT_WAIT_FOR_NAVIGATION_TIMEOUT, DEFAULT_WAIT_FOR_NETWORK_IDLE_CONCURRENCY, DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT } from "@midscene/shared/constants";
3
+ import { treeToList } from "@midscene/shared/extractor";
4
+ import { createImgBase64ByFormat } from "@midscene/shared/img";
5
+ import { getDebug } from "@midscene/shared/logger";
6
+ import { getElementInfosScriptContent, getExtraReturnLogic } from "@midscene/shared/node";
7
+ import { assert } from "@midscene/shared/utils";
8
+ import { buildRectFromElementInfo, judgeOrderSensitive, sanitizeXpaths } from "../common/cache-helper.mjs";
9
+ import { commonWebActionsForWebPage } from "../web-page.mjs";
10
+ function _define_property(obj, key, value) {
11
+ if (key in obj) Object.defineProperty(obj, key, {
12
+ value: value,
13
+ enumerable: true,
14
+ configurable: true,
15
+ writable: true
16
+ });
17
+ else obj[key] = value;
18
+ return obj;
19
+ }
20
+ const debugPage = getDebug('web:page');
21
+ class Page {
22
+ actionSpace() {
23
+ const defaultActions = commonWebActionsForWebPage(this, this.enableTouchEventsInActionSpace);
24
+ const customActions = this.customActions || [];
25
+ return [
26
+ ...defaultActions,
27
+ ...customActions
28
+ ];
29
+ }
30
+ async evaluate(pageFunction, arg) {
31
+ let result;
32
+ debugPage('evaluate function begin');
33
+ this.interfaceType, result = await this.underlyingPage.evaluate(pageFunction, arg);
34
+ debugPage('evaluate function end');
35
+ return result;
36
+ }
37
+ async evaluateJavaScript(script) {
38
+ return this.evaluate(script);
39
+ }
40
+ async waitForNavigation(moment, actionName) {
41
+ if (0 === this.waitForNavigationTimeout) return void debugPage('waitForNavigation timeout is 0, skip waiting');
42
+ if ('puppeteer' === this.interfaceType || 'playwright' === this.interfaceType) {
43
+ debugPage(`waitForNavigation begin at moment ${moment} with timeout: ${this.waitForNavigationTimeout} and actionName: ${actionName}`);
44
+ try {
45
+ await this.underlyingPage.waitForSelector('html', {
46
+ timeout: this.waitForNavigationTimeout
47
+ });
48
+ } catch (error) {
49
+ console.warn('[midscene:warning] Waiting for the "navigation" has timed out, but Midscene will continue execution. Please check https://midscenejs.com/faq.html#customize-the-network-timeout for more information on customizing the network timeout');
50
+ }
51
+ debugPage('waitForNavigation end');
52
+ }
53
+ }
54
+ async waitForNetworkIdle(moment, actionName) {
55
+ if ('puppeteer' === this.interfaceType) {
56
+ if (0 === this.waitForNetworkIdleTimeout) return void debugPage('waitForNetworkIdle timeout is 0, skip waiting');
57
+ debugPage(`waitForNetworkIdle begin at moment ${moment} with timeout: ${this.waitForNetworkIdleTimeout} and concurrency: ${DEFAULT_WAIT_FOR_NETWORK_IDLE_CONCURRENCY} and actionName: ${actionName}`);
58
+ try {
59
+ await this.underlyingPage.waitForNetworkIdle({
60
+ idleTime: 200,
61
+ concurrency: DEFAULT_WAIT_FOR_NETWORK_IDLE_CONCURRENCY,
62
+ timeout: this.waitForNetworkIdleTimeout
63
+ });
64
+ } catch (error) {
65
+ console.warn('[midscene:warning] Waiting for the "network idle" has timed out, but Midscene will continue execution. Please check https://midscenejs.com/faq.html#customize-the-network-timeout for more information on customizing the network timeout');
66
+ }
67
+ debugPage('waitForNetworkIdle end');
68
+ }
69
+ }
70
+ async getElementsInfo() {
71
+ await this.waitForNavigation('getElementsInfo');
72
+ debugPage('getElementsInfo begin');
73
+ const tree = await this.getElementsNodeTree();
74
+ debugPage('getElementsInfo end');
75
+ return treeToList(tree);
76
+ }
77
+ async getXpathsByPoint(point, isOrderSensitive) {
78
+ const elementInfosScriptContent = getElementInfosScriptContent();
79
+ return this.evaluateJavaScript(`${elementInfosScriptContent}midscene_element_inspector.getXpathsByPoint({left: ${point.left}, top: ${point.top}}, ${isOrderSensitive})`);
80
+ }
81
+ async getElementInfoByXpath(xpath) {
82
+ const elementInfosScriptContent = getElementInfosScriptContent();
83
+ return this.evaluateJavaScript(`${elementInfosScriptContent}midscene_element_inspector.getElementInfoByXpath(${JSON.stringify(xpath)})`);
84
+ }
85
+ async cacheFeatureForPoint(center, options) {
86
+ const point = {
87
+ left: center[0],
88
+ top: center[1]
89
+ };
90
+ try {
91
+ const isOrderSensitive = await judgeOrderSensitive(options, debugPage);
92
+ const xpaths = await this.getXpathsByPoint(point, isOrderSensitive);
93
+ const sanitized = sanitizeXpaths(xpaths);
94
+ if (!sanitized.length) debugPage('cacheFeatureForPoint: no xpath found at point %o', center);
95
+ return {
96
+ xpaths: sanitized
97
+ };
98
+ } catch (error) {
99
+ debugPage('cacheFeatureForPoint failed: %s', error);
100
+ return {
101
+ xpaths: []
102
+ };
103
+ }
104
+ }
105
+ async rectMatchesCacheFeature(feature) {
106
+ const xpaths = sanitizeXpaths(feature.xpaths);
107
+ debugPage('rectMatchesCacheFeature: trying %d xpath(s)', xpaths.length);
108
+ for (const xpath of xpaths)try {
109
+ debugPage('rectMatchesCacheFeature: evaluating xpath: %s', xpath);
110
+ const elementInfo = await this.getElementInfoByXpath(xpath);
111
+ if (elementInfo?.rect) {
112
+ debugPage('rectMatchesCacheFeature: found element, rect: %o', elementInfo.rect);
113
+ return buildRectFromElementInfo(elementInfo);
114
+ }
115
+ debugPage('rectMatchesCacheFeature: element found but no rect (elementInfo: %o)', elementInfo);
116
+ } catch (error) {
117
+ debugPage('rectMatchesCacheFeature failed for xpath %s: %s', xpath, error);
118
+ }
119
+ throw new Error(`No matching element rect found for the provided cache feature (tried ${xpaths.length} xpath(s): ${xpaths.join(', ')})`);
120
+ }
121
+ async getElementsNodeTree() {
122
+ await this.waitForNavigation('getElementsNodeTree');
123
+ const scripts = await getExtraReturnLogic(true);
124
+ assert(scripts, "scripts should be set before writing report in browser");
125
+ const startTime = Date.now();
126
+ const captureElementSnapshot = await this.evaluate(scripts);
127
+ const endTime = Date.now();
128
+ debugPage(`getElementsNodeTree end, cost: ${endTime - startTime}ms`);
129
+ return captureElementSnapshot;
130
+ }
131
+ async size() {
132
+ if (this.viewportSize) return this.viewportSize;
133
+ const sizeInfo = await this.evaluate(()=>({
134
+ width: window.innerWidth,
135
+ height: window.innerHeight
136
+ }));
137
+ this.viewportSize = sizeInfo;
138
+ return sizeInfo;
139
+ }
140
+ async screenshotBase64() {
141
+ const imgType = 'jpeg';
142
+ const quality = 90;
143
+ const startTime = Date.now();
144
+ debugPage('screenshotBase64 begin');
145
+ let base64;
146
+ if ('puppeteer' === this.interfaceType) {
147
+ const result = await this.underlyingPage.screenshot({
148
+ type: imgType,
149
+ quality,
150
+ encoding: 'base64'
151
+ });
152
+ base64 = createImgBase64ByFormat(imgType, result);
153
+ } else if ('playwright' === this.interfaceType) {
154
+ const buffer = await this.underlyingPage.screenshot({
155
+ type: imgType,
156
+ quality,
157
+ timeout: 10000
158
+ });
159
+ base64 = createImgBase64ByFormat(imgType, buffer.toString('base64'));
160
+ } else throw new Error('Unsupported page type for screenshot');
161
+ const endTime = Date.now();
162
+ debugPage(`screenshotBase64 end, cost: ${endTime - startTime}ms`);
163
+ return base64;
164
+ }
165
+ async url() {
166
+ return this.underlyingPage.url();
167
+ }
168
+ describe() {
169
+ const url = this.underlyingPage.url();
170
+ return url || '';
171
+ }
172
+ get mouse() {
173
+ return {
174
+ click: async (x, y, options)=>{
175
+ await this.mouse.move(x, y);
176
+ const { button = 'left', count = 1 } = options || {};
177
+ debugPage(`mouse click ${x}, ${y}, ${button}, ${count}`);
178
+ if (2 === count && 'playwright' === this.interfaceType) await this.underlyingPage.mouse.dblclick(x, y, {
179
+ button
180
+ });
181
+ else if ('puppeteer' === this.interfaceType) {
182
+ const page = this.underlyingPage;
183
+ if ('left' === button && 1 === count) await page.mouse.click(x, y);
184
+ else await page.mouse.click(x, y, {
185
+ button,
186
+ count
187
+ });
188
+ } else if ('playwright' === this.interfaceType) await this.underlyingPage.mouse.click(x, y, {
189
+ button,
190
+ clickCount: count
191
+ });
192
+ },
193
+ wheel: async (deltaX, deltaY)=>{
194
+ debugPage(`mouse wheel ${deltaX}, ${deltaY}`);
195
+ if ('puppeteer' === this.interfaceType) await this.underlyingPage.mouse.wheel({
196
+ deltaX,
197
+ deltaY
198
+ });
199
+ else if ('playwright' === this.interfaceType) await this.underlyingPage.mouse.wheel(deltaX, deltaY);
200
+ },
201
+ move: async (x, y)=>{
202
+ this.everMoved = true;
203
+ debugPage(`mouse move to ${x}, ${y}`);
204
+ return this.underlyingPage.mouse.move(x, y);
205
+ },
206
+ drag: async (from, to)=>{
207
+ debugPage(`begin mouse drag from ${from.x}, ${from.y} to ${to.x}, ${to.y}`);
208
+ await this.underlyingPage.mouse.move(from.x, from.y);
209
+ await sleep(200);
210
+ await this.underlyingPage.mouse.down();
211
+ await sleep(300);
212
+ await this.underlyingPage.mouse.move(to.x, to.y, {
213
+ steps: 20
214
+ });
215
+ await sleep(500);
216
+ await this.underlyingPage.mouse.up();
217
+ await sleep(200);
218
+ debugPage(`end mouse drag from ${from.x}, ${from.y} to ${to.x}, ${to.y}`);
219
+ }
220
+ };
221
+ }
222
+ get keyboard() {
223
+ return {
224
+ type: async (text)=>{
225
+ debugPage(`keyboard type ${text}`);
226
+ return this.underlyingPage.keyboard.type(text, {
227
+ delay: 80
228
+ });
229
+ },
230
+ press: async (action)=>{
231
+ const keys = Array.isArray(action) ? action : [
232
+ action
233
+ ];
234
+ debugPage('keyboard press', keys);
235
+ for (const k of keys){
236
+ const commands = k.command ? [
237
+ k.command
238
+ ] : [];
239
+ await this.underlyingPage.keyboard.down(k.key, {
240
+ commands
241
+ });
242
+ }
243
+ for (const k of [
244
+ ...keys
245
+ ].reverse())await this.underlyingPage.keyboard.up(k.key);
246
+ },
247
+ down: async (key)=>{
248
+ debugPage(`keyboard down ${key}`);
249
+ return this.underlyingPage.keyboard.down(key);
250
+ },
251
+ up: async (key)=>{
252
+ debugPage(`keyboard up ${key}`);
253
+ return this.underlyingPage.keyboard.up(key);
254
+ }
255
+ };
256
+ }
257
+ async clearInput(element) {
258
+ const backspace = async ()=>{
259
+ await sleep(100);
260
+ await this.keyboard.press([
261
+ {
262
+ key: 'Backspace'
263
+ }
264
+ ]);
265
+ };
266
+ const isMac = 'darwin' === process.platform;
267
+ debugPage('clearInput begin');
268
+ if (isMac) {
269
+ if ('puppeteer' === this.interfaceType) {
270
+ element && await this.mouse.click(element.center[0], element.center[1], {
271
+ count: 3
272
+ });
273
+ await backspace();
274
+ }
275
+ element && await this.mouse.click(element.center[0], element.center[1]);
276
+ await this.underlyingPage.keyboard.down('Meta');
277
+ await this.underlyingPage.keyboard.press('a');
278
+ await this.underlyingPage.keyboard.up('Meta');
279
+ await backspace();
280
+ } else {
281
+ element && await this.mouse.click(element.center[0], element.center[1]);
282
+ await this.underlyingPage.keyboard.down('Control');
283
+ await this.underlyingPage.keyboard.press('a');
284
+ await this.underlyingPage.keyboard.up('Control');
285
+ await backspace();
286
+ }
287
+ debugPage('clearInput end');
288
+ }
289
+ async moveToPointBeforeScroll(point) {
290
+ if (point) await this.mouse.move(point.left, point.top);
291
+ else if (!this.everMoved) {
292
+ const size = await this.size();
293
+ const targetX = Math.floor(size.width / 2);
294
+ const targetY = Math.floor(size.height / 2);
295
+ await this.mouse.move(targetX, targetY);
296
+ }
297
+ }
298
+ async scrollUntilTop(startingPoint) {
299
+ await this.moveToPointBeforeScroll(startingPoint);
300
+ return this.mouse.wheel(0, -9999999);
301
+ }
302
+ async scrollUntilBottom(startingPoint) {
303
+ await this.moveToPointBeforeScroll(startingPoint);
304
+ return this.mouse.wheel(0, 9999999);
305
+ }
306
+ async scrollUntilLeft(startingPoint) {
307
+ await this.moveToPointBeforeScroll(startingPoint);
308
+ return this.mouse.wheel(-9999999, 0);
309
+ }
310
+ async scrollUntilRight(startingPoint) {
311
+ await this.moveToPointBeforeScroll(startingPoint);
312
+ return this.mouse.wheel(9999999, 0);
313
+ }
314
+ async scrollUp(distance, startingPoint) {
315
+ const innerHeight = await this.evaluate(()=>window.innerHeight);
316
+ const scrollDistance = distance || 0.7 * innerHeight;
317
+ await this.moveToPointBeforeScroll(startingPoint);
318
+ return this.mouse.wheel(0, -scrollDistance);
319
+ }
320
+ async scrollDown(distance, startingPoint) {
321
+ const innerHeight = await this.evaluate(()=>window.innerHeight);
322
+ const scrollDistance = distance || 0.7 * innerHeight;
323
+ await this.moveToPointBeforeScroll(startingPoint);
324
+ return this.mouse.wheel(0, scrollDistance);
325
+ }
326
+ async scrollLeft(distance, startingPoint) {
327
+ const innerWidth = await this.evaluate(()=>window.innerWidth);
328
+ const scrollDistance = distance || 0.7 * innerWidth;
329
+ await this.moveToPointBeforeScroll(startingPoint);
330
+ return this.mouse.wheel(-scrollDistance, 0);
331
+ }
332
+ async scrollRight(distance, startingPoint) {
333
+ const innerWidth = await this.evaluate(()=>window.innerWidth);
334
+ const scrollDistance = distance || 0.7 * innerWidth;
335
+ await this.moveToPointBeforeScroll(startingPoint);
336
+ return this.mouse.wheel(scrollDistance, 0);
337
+ }
338
+ async navigate(url) {
339
+ debugPage(`navigate to ${url}`);
340
+ if ('puppeteer' === this.interfaceType) await this.underlyingPage.goto(url);
341
+ else if ('playwright' === this.interfaceType) await this.underlyingPage.goto(url);
342
+ else throw new Error('Unsupported page type for navigate');
343
+ }
344
+ async reload() {
345
+ debugPage('reload page');
346
+ if ('puppeteer' === this.interfaceType) await this.underlyingPage.reload();
347
+ else if ('playwright' === this.interfaceType) await this.underlyingPage.reload();
348
+ else throw new Error('Unsupported page type for reload');
349
+ }
350
+ async goBack() {
351
+ debugPage('go back');
352
+ if ('puppeteer' === this.interfaceType) await this.underlyingPage.goBack();
353
+ else if ('playwright' === this.interfaceType) await this.underlyingPage.goBack();
354
+ else throw new Error('Unsupported page type for go back');
355
+ }
356
+ async beforeInvokeAction(name, param) {
357
+ if (this.onBeforeInvokeAction) await this.onBeforeInvokeAction(name, param);
358
+ }
359
+ async afterInvokeAction(name, param) {
360
+ await Promise.all([
361
+ this.waitForNavigation('afterInvokeAction', name),
362
+ this.waitForNetworkIdle('afterInvokeAction', name)
363
+ ]);
364
+ if (this.onAfterInvokeAction) await this.onAfterInvokeAction(name, param);
365
+ }
366
+ async destroy() {}
367
+ async swipe(from, to, duration) {
368
+ const LONG_PRESS_THRESHOLD = 500;
369
+ const MIN_PRESS_THRESHOLD = 150;
370
+ duration = duration || 100;
371
+ if (duration < MIN_PRESS_THRESHOLD) duration = MIN_PRESS_THRESHOLD;
372
+ if (duration > LONG_PRESS_THRESHOLD) duration = LONG_PRESS_THRESHOLD;
373
+ debugPage(`mouse swipe from ${from.x}, ${from.y} to ${to.x}, ${to.y} with duration ${duration}ms`);
374
+ if ('puppeteer' === this.interfaceType) {
375
+ const page = this.underlyingPage;
376
+ await page.mouse.move(from.x, from.y);
377
+ await page.mouse.down({
378
+ button: 'left'
379
+ });
380
+ const steps = 30;
381
+ const delay = duration / steps;
382
+ for(let i = 1; i <= steps; i++){
383
+ const x = from.x + (to.x - from.x) * (i / steps);
384
+ const y = from.y + (to.y - from.y) * (i / steps);
385
+ await page.mouse.move(x, y);
386
+ await new Promise((resolve)=>setTimeout(resolve, delay));
387
+ }
388
+ await page.mouse.up({
389
+ button: 'left'
390
+ });
391
+ } else if ('playwright' === this.interfaceType) {
392
+ const page = this.underlyingPage;
393
+ await page.mouse.move(from.x, from.y);
394
+ await page.mouse.down();
395
+ const steps = 30;
396
+ const delay = duration / steps;
397
+ for(let i = 1; i <= steps; i++){
398
+ const x = from.x + (to.x - from.x) * (i / steps);
399
+ const y = from.y + (to.y - from.y) * (i / steps);
400
+ await page.mouse.move(x, y);
401
+ await page.waitForTimeout(delay);
402
+ }
403
+ await page.mouse.up({
404
+ button: 'left'
405
+ });
406
+ }
407
+ }
408
+ async longPress(x, y, duration) {
409
+ duration = duration || 500;
410
+ const LONG_PRESS_THRESHOLD = 600;
411
+ const MIN_PRESS_THRESHOLD = 300;
412
+ if (duration > LONG_PRESS_THRESHOLD) duration = LONG_PRESS_THRESHOLD;
413
+ if (duration < MIN_PRESS_THRESHOLD) duration = MIN_PRESS_THRESHOLD;
414
+ debugPage(`mouse longPress at ${x}, ${y} for ${duration}ms`);
415
+ if ('puppeteer' === this.interfaceType) {
416
+ const page = this.underlyingPage;
417
+ await page.mouse.move(x, y);
418
+ await page.mouse.down({
419
+ button: 'left'
420
+ });
421
+ await new Promise((res)=>setTimeout(res, duration));
422
+ await page.mouse.up({
423
+ button: 'left'
424
+ });
425
+ } else if ('playwright' === this.interfaceType) {
426
+ const page = this.underlyingPage;
427
+ await page.mouse.move(x, y);
428
+ await page.mouse.down({
429
+ button: 'left'
430
+ });
431
+ await page.waitForTimeout(duration);
432
+ await page.mouse.up({
433
+ button: 'left'
434
+ });
435
+ }
436
+ }
437
+ async ensurePuppeteerFileChooserSession(page) {
438
+ if (this.puppeteerFileChooserSession) return this.puppeteerFileChooserSession;
439
+ const session = await page.target().createCDPSession();
440
+ await session.send('Page.enable');
441
+ await session.send('DOM.enable');
442
+ await session.send('Page.setInterceptFileChooserDialog', {
443
+ enabled: true
444
+ });
445
+ this.puppeteerFileChooserSession = session;
446
+ return session;
447
+ }
448
+ async registerFileChooserListener(handler) {
449
+ if ('puppeteer' !== this.interfaceType) throw new Error('registerFileChooserListener is only supported in Puppeteer');
450
+ const page = this.underlyingPage;
451
+ const session = await this.ensurePuppeteerFileChooserSession(page);
452
+ if (this.puppeteerFileChooserHandler) session.off('Page.fileChooserOpened', this.puppeteerFileChooserHandler);
453
+ let capturedError;
454
+ this.puppeteerFileChooserHandler = async (event)=>{
455
+ if (void 0 === event.backendNodeId) return void debugPage('puppeteer file chooser opened without backendNodeId, skip');
456
+ try {
457
+ await handler({
458
+ accept: async (files)=>{
459
+ const { node } = await session.send('DOM.describeNode', {
460
+ backendNodeId: event.backendNodeId
461
+ });
462
+ const hasWebkitDirectory = node.attributes?.includes('webkitdirectory') || node.attributes?.includes('directory');
463
+ if (hasWebkitDirectory) throw new Error('Directory upload (webkitdirectory) is not supported in Puppeteer. Please use Playwright instead, which supports directory upload since version 1.45.');
464
+ if (files.length > 1) {
465
+ const hasMultiple = node.attributes?.includes('multiple');
466
+ if (!hasMultiple) throw new Error('Non-multiple file input can only accept single file');
467
+ }
468
+ await session.send('DOM.setFileInputFiles', {
469
+ files,
470
+ backendNodeId: event.backendNodeId
471
+ });
472
+ }
473
+ });
474
+ } catch (error) {
475
+ capturedError = error;
476
+ }
477
+ };
478
+ session.on('Page.fileChooserOpened', this.puppeteerFileChooserHandler);
479
+ return {
480
+ dispose: ()=>{
481
+ if (this.puppeteerFileChooserHandler) session.off('Page.fileChooserOpened', this.puppeteerFileChooserHandler);
482
+ session.detach();
483
+ this.puppeteerFileChooserHandler = void 0;
484
+ if (this.puppeteerFileChooserSession === session) this.puppeteerFileChooserSession = void 0;
485
+ },
486
+ getError: ()=>capturedError
487
+ };
488
+ }
489
+ constructor(underlyingPage, interfaceType, opts){
490
+ _define_property(this, "underlyingPage", void 0);
491
+ _define_property(this, "waitForNavigationTimeout", void 0);
492
+ _define_property(this, "waitForNetworkIdleTimeout", void 0);
493
+ _define_property(this, "viewportSize", void 0);
494
+ _define_property(this, "onBeforeInvokeAction", void 0);
495
+ _define_property(this, "onAfterInvokeAction", void 0);
496
+ _define_property(this, "customActions", void 0);
497
+ _define_property(this, "enableTouchEventsInActionSpace", void 0);
498
+ _define_property(this, "puppeteerFileChooserSession", void 0);
499
+ _define_property(this, "puppeteerFileChooserHandler", void 0);
500
+ _define_property(this, "interfaceType", void 0);
501
+ _define_property(this, "everMoved", false);
502
+ this.underlyingPage = underlyingPage;
503
+ this.interfaceType = interfaceType;
504
+ this.waitForNavigationTimeout = opts?.waitForNavigationTimeout ?? DEFAULT_WAIT_FOR_NAVIGATION_TIMEOUT;
505
+ this.waitForNetworkIdleTimeout = opts?.waitForNetworkIdleTimeout ?? DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT;
506
+ this.onBeforeInvokeAction = opts?.beforeInvokeAction;
507
+ this.onAfterInvokeAction = opts?.afterInvokeAction;
508
+ this.customActions = opts?.customActions;
509
+ this.enableTouchEventsInActionSpace = opts?.enableTouchEventsInActionSpace ?? false;
510
+ }
511
+ }
512
+ function forceClosePopup(page, debugProfile) {
513
+ page.on('popup', async (popup)=>{
514
+ if (!popup) return void console.warn('got a popup event, but the popup is not ready yet, skip');
515
+ const url = await popup.url();
516
+ console.log(`Popup opened: ${url}`);
517
+ if (popup.isClosed()) debugProfile(`popup is already closed, skip close ${url}`);
518
+ else try {
519
+ await popup.close();
520
+ } catch (error) {
521
+ debugProfile(`failed to close popup ${url}, error: ${error}`);
522
+ }
523
+ if (page.isClosed()) debugProfile(`page is already closed, skip goto ${url}`);
524
+ else try {
525
+ await page.goto(url);
526
+ } catch (error) {
527
+ debugProfile(`failed to goto ${url}, error: ${error}`);
528
+ }
529
+ });
530
+ }
531
+ function forceChromeSelectRendering(page) {
532
+ const styleContent = `
533
+ /* Add by Midscene because of forceChromeSelectRendering is enabled*/
534
+ select {
535
+ &, &::picker(select) {
536
+ appearance: base-select !important;
537
+ }
538
+ }`;
539
+ const styleId = 'midscene-force-select-rendering';
540
+ const injectStyle = async ()=>{
541
+ try {
542
+ await page.evaluate(({ id, content })=>{
543
+ if (document.getElementById(id)) return;
544
+ const style = document.createElement('style');
545
+ style.id = id;
546
+ style.textContent = content;
547
+ document.head.appendChild(style);
548
+ }, {
549
+ id: styleId,
550
+ content: styleContent
551
+ });
552
+ debugPage('Midscene - Added base-select appearance style for select elements because of forceChromeSelectRendering is enabled');
553
+ } catch (err) {
554
+ console.log('Midscene - Failed to add base-select appearance style:', err);
555
+ }
556
+ };
557
+ injectStyle();
558
+ page.on('load', ()=>{
559
+ injectStyle();
560
+ });
561
+ }
562
+ export { Page, debugPage, forceChromeSelectRendering, forceClosePopup };
563
+
564
+ //# sourceMappingURL=base-page.mjs.map