@godscene/web 1.7.11

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 (129) hide show
  1. package/README.md +7 -0
  2. package/bin/midscene-playground +3 -0
  3. package/bin/midscene-web +2 -0
  4. package/dist/es/bin.mjs +14 -0
  5. package/dist/es/bridge-mode/agent-cli-side.mjs +135 -0
  6. package/dist/es/bridge-mode/browser.mjs +2 -0
  7. package/dist/es/bridge-mode/common.mjs +41 -0
  8. package/dist/es/bridge-mode/index.mjs +4 -0
  9. package/dist/es/bridge-mode/io-client.mjs +99 -0
  10. package/dist/es/bridge-mode/io-server.mjs +218 -0
  11. package/dist/es/bridge-mode/page-browser-side.mjs +119 -0
  12. package/dist/es/cdp-proxy-constants.mjs +7 -0
  13. package/dist/es/cdp-proxy-manager.mjs +217 -0
  14. package/dist/es/cdp-proxy.mjs +151 -0
  15. package/dist/es/cdp-target-store.mjs +26 -0
  16. package/dist/es/chrome-extension/agent.mjs +8 -0
  17. package/dist/es/chrome-extension/cdpInput.mjs +172 -0
  18. package/dist/es/chrome-extension/cdpInput.mjs.LICENSE.txt +5 -0
  19. package/dist/es/chrome-extension/dynamic-scripts.mjs +36 -0
  20. package/dist/es/chrome-extension/index.mjs +5 -0
  21. package/dist/es/chrome-extension/page.mjs +733 -0
  22. package/dist/es/cli-options.mjs +97 -0
  23. package/dist/es/cli.mjs +26 -0
  24. package/dist/es/common/cache-helper.mjs +26 -0
  25. package/dist/es/common/viewport.mjs +36 -0
  26. package/dist/es/index.mjs +8 -0
  27. package/dist/es/mcp-server.mjs +33 -0
  28. package/dist/es/mcp-tools-cdp.mjs +164 -0
  29. package/dist/es/mcp-tools-puppeteer.mjs +246 -0
  30. package/dist/es/mcp-tools.mjs +81 -0
  31. package/dist/es/platform.mjs +37 -0
  32. package/dist/es/playwright/ai-fixture.mjs +364 -0
  33. package/dist/es/playwright/index.mjs +36 -0
  34. package/dist/es/playwright/page.mjs +42 -0
  35. package/dist/es/playwright/reporter/index.mjs +178 -0
  36. package/dist/es/puppeteer/agent-launcher.mjs +172 -0
  37. package/dist/es/puppeteer/base-page.mjs +830 -0
  38. package/dist/es/puppeteer/index.mjs +35 -0
  39. package/dist/es/puppeteer/page.mjs +7 -0
  40. package/dist/es/static/index.mjs +3 -0
  41. package/dist/es/static/static-agent.mjs +10 -0
  42. package/dist/es/static/static-page.mjs +123 -0
  43. package/dist/es/utils.mjs +6 -0
  44. package/dist/es/web-element.mjs +57 -0
  45. package/dist/es/web-page.mjs +272 -0
  46. package/dist/lib/bin.js +20 -0
  47. package/dist/lib/bridge-mode/agent-cli-side.js +172 -0
  48. package/dist/lib/bridge-mode/browser.js +36 -0
  49. package/dist/lib/bridge-mode/common.js +105 -0
  50. package/dist/lib/bridge-mode/index.js +44 -0
  51. package/dist/lib/bridge-mode/io-client.js +133 -0
  52. package/dist/lib/bridge-mode/io-server.js +255 -0
  53. package/dist/lib/bridge-mode/page-browser-side.js +163 -0
  54. package/dist/lib/cdp-proxy-constants.js +50 -0
  55. package/dist/lib/cdp-proxy-manager.js +273 -0
  56. package/dist/lib/cdp-proxy.js +179 -0
  57. package/dist/lib/cdp-target-store.js +66 -0
  58. package/dist/lib/chrome-extension/agent.js +42 -0
  59. package/dist/lib/chrome-extension/cdpInput.js +206 -0
  60. package/dist/lib/chrome-extension/cdpInput.js.LICENSE.txt +5 -0
  61. package/dist/lib/chrome-extension/dynamic-scripts.js +86 -0
  62. package/dist/lib/chrome-extension/index.js +58 -0
  63. package/dist/lib/chrome-extension/page.js +767 -0
  64. package/dist/lib/cli-options.js +131 -0
  65. package/dist/lib/cli.js +54 -0
  66. package/dist/lib/common/cache-helper.js +66 -0
  67. package/dist/lib/common/viewport.js +88 -0
  68. package/dist/lib/index.js +66 -0
  69. package/dist/lib/mcp-server.js +73 -0
  70. package/dist/lib/mcp-tools-cdp.js +208 -0
  71. package/dist/lib/mcp-tools-puppeteer.js +296 -0
  72. package/dist/lib/mcp-tools.js +115 -0
  73. package/dist/lib/platform.js +71 -0
  74. package/dist/lib/playwright/ai-fixture.js +401 -0
  75. package/dist/lib/playwright/index.js +89 -0
  76. package/dist/lib/playwright/page.js +76 -0
  77. package/dist/lib/playwright/reporter/index.js +212 -0
  78. package/dist/lib/puppeteer/agent-launcher.js +240 -0
  79. package/dist/lib/puppeteer/base-page.js +876 -0
  80. package/dist/lib/puppeteer/index.js +85 -0
  81. package/dist/lib/puppeteer/page.js +41 -0
  82. package/dist/lib/static/index.js +50 -0
  83. package/dist/lib/static/static-agent.js +44 -0
  84. package/dist/lib/static/static-page.js +157 -0
  85. package/dist/lib/utils.js +38 -0
  86. package/dist/lib/web-element.js +94 -0
  87. package/dist/lib/web-page.js +322 -0
  88. package/dist/types/bin.d.ts +1 -0
  89. package/dist/types/bridge-mode/agent-cli-side.d.ts +49 -0
  90. package/dist/types/bridge-mode/browser.d.ts +2 -0
  91. package/dist/types/bridge-mode/common.d.ts +74 -0
  92. package/dist/types/bridge-mode/index.d.ts +4 -0
  93. package/dist/types/bridge-mode/io-client.d.ts +10 -0
  94. package/dist/types/bridge-mode/io-server.d.ts +27 -0
  95. package/dist/types/bridge-mode/page-browser-side.d.ts +21 -0
  96. package/dist/types/cdp-proxy-constants.d.ts +4 -0
  97. package/dist/types/cdp-proxy-manager.d.ts +53 -0
  98. package/dist/types/cdp-proxy.d.ts +37 -0
  99. package/dist/types/cdp-target-store.d.ts +26 -0
  100. package/dist/types/chrome-extension/agent.d.ts +4 -0
  101. package/dist/types/chrome-extension/cdpInput.d.ts +52 -0
  102. package/dist/types/chrome-extension/dynamic-scripts.d.ts +3 -0
  103. package/dist/types/chrome-extension/index.d.ts +5 -0
  104. package/dist/types/chrome-extension/page.d.ts +120 -0
  105. package/dist/types/cli-options.d.ts +8 -0
  106. package/dist/types/cli.d.ts +1 -0
  107. package/dist/types/common/cache-helper.d.ts +20 -0
  108. package/dist/types/common/viewport.d.ts +17 -0
  109. package/dist/types/index.d.ts +9 -0
  110. package/dist/types/mcp-server.d.ts +26 -0
  111. package/dist/types/mcp-tools-cdp.d.ts +23 -0
  112. package/dist/types/mcp-tools-puppeteer.d.ts +23 -0
  113. package/dist/types/mcp-tools.d.ts +14 -0
  114. package/dist/types/platform.d.ts +10 -0
  115. package/dist/types/playwright/ai-fixture.d.ts +133 -0
  116. package/dist/types/playwright/index.d.ts +13 -0
  117. package/dist/types/playwright/page.d.ts +11 -0
  118. package/dist/types/playwright/reporter/index.d.ts +28 -0
  119. package/dist/types/puppeteer/agent-launcher.d.ts +59 -0
  120. package/dist/types/puppeteer/base-page.d.ts +123 -0
  121. package/dist/types/puppeteer/index.d.ts +11 -0
  122. package/dist/types/puppeteer/page.d.ts +6 -0
  123. package/dist/types/static/index.d.ts +2 -0
  124. package/dist/types/static/static-agent.d.ts +5 -0
  125. package/dist/types/static/static-page.d.ts +46 -0
  126. package/dist/types/utils.d.ts +6 -0
  127. package/dist/types/web-element.d.ts +48 -0
  128. package/dist/types/web-page.d.ts +69 -0
  129. package/package.json +173 -0
@@ -0,0 +1,81 @@
1
+ import { ScreenshotItem, z } from "@godscene/core";
2
+ import { BaseMidsceneTools } from "@godscene/shared/mcp/base-tools";
3
+ import { AgentOverChromeBridge } from "./bridge-mode/index.mjs";
4
+ import { defaultStaticPageViewportSize } from "./common/viewport.mjs";
5
+ import { StaticPage } from "./static/index.mjs";
6
+ class WebMidsceneTools extends BaseMidsceneTools {
7
+ getCliReportSessionName() {
8
+ return 'midscene-web';
9
+ }
10
+ createTemporaryDevice() {
11
+ return new StaticPage({
12
+ screenshot: ScreenshotItem.create('', Date.now()),
13
+ shotSize: defaultStaticPageViewportSize,
14
+ shrunkShotToLogicalRatio: 1
15
+ });
16
+ }
17
+ async ensureAgent(openNewTabWithUrl) {
18
+ if (this.agent && openNewTabWithUrl) {
19
+ try {
20
+ await this.agent?.destroy?.();
21
+ } catch (error) {
22
+ console.debug('Failed to destroy agent during re-init:', error);
23
+ }
24
+ this.agent = void 0;
25
+ }
26
+ if (this.agent) return this.agent;
27
+ this.agent = await this.initBridgeModeAgent(openNewTabWithUrl);
28
+ return this.agent;
29
+ }
30
+ async initBridgeModeAgent(url) {
31
+ const reportOptions = this.readCliReportAgentOptions();
32
+ const agent = new AgentOverChromeBridge({
33
+ closeConflictServer: true,
34
+ ...reportOptions ?? {}
35
+ });
36
+ if (url) await agent.connectNewTabWithUrl(url);
37
+ else await agent.connectCurrentTab();
38
+ return agent;
39
+ }
40
+ preparePlatformTools() {
41
+ return [
42
+ {
43
+ name: 'web_connect',
44
+ description: 'Connect to web page. If URL provided, opens new tab; otherwise connects to current tab.',
45
+ schema: {
46
+ url: z.string().url().optional().describe('URL to open in new tab (omit to connect current tab)')
47
+ },
48
+ handler: async (args)=>{
49
+ const { url } = args;
50
+ if (this.agent) {
51
+ try {
52
+ await this.agent.destroy?.();
53
+ } catch {}
54
+ this.agent = void 0;
55
+ }
56
+ const reportSession = this.createNewCliReportSession(url ?? 'current-tab');
57
+ this.commitCliReportSession(reportSession);
58
+ this.agent = await this.initBridgeModeAgent(url);
59
+ const screenshot = await this.agent.page?.screenshotBase64();
60
+ const label = url ?? 'current tab';
61
+ return {
62
+ content: [
63
+ {
64
+ type: 'text',
65
+ text: `Connected to: ${label}`
66
+ },
67
+ ...screenshot ? this.buildScreenshotContent(screenshot) : []
68
+ ]
69
+ };
70
+ }
71
+ },
72
+ {
73
+ name: 'web_disconnect',
74
+ description: 'Disconnect from current web page and release browser resources',
75
+ schema: {},
76
+ handler: this.createDisconnectHandler('web page')
77
+ }
78
+ ];
79
+ }
80
+ }
81
+ export { WebMidsceneTools };
@@ -0,0 +1,37 @@
1
+ import { ScreenshotItem } from "@godscene/core";
2
+ import { createMjpegPreviewDescriptor, definePlaygroundPlatform } from "@godscene/playground";
3
+ import { StaticPage, StaticPageAgent } from "./static/index.mjs";
4
+ function createDefaultWebAgent() {
5
+ const page = new StaticPage({
6
+ shotSize: {
7
+ width: 800,
8
+ height: 600
9
+ },
10
+ screenshot: ScreenshotItem.create('', Date.now()),
11
+ shrunkShotToLogicalRatio: 1
12
+ });
13
+ return new StaticPageAgent(page);
14
+ }
15
+ const webPlaygroundPlatform = definePlaygroundPlatform({
16
+ id: 'web',
17
+ title: 'Midscene Web Playground',
18
+ description: "Web playground platform descriptor",
19
+ async prepare (options) {
20
+ const agent = options?.agent;
21
+ const agentFactory = options?.agentFactory || (options?.agent || options?.agentFactory ? void 0 : ()=>createDefaultWebAgent());
22
+ return {
23
+ platformId: 'web',
24
+ title: options?.title || 'Midscene Web Playground',
25
+ agent: agent || (agentFactory ? void 0 : createDefaultWebAgent()),
26
+ agentFactory,
27
+ launchOptions: options?.launchOptions,
28
+ preview: options?.preview || createMjpegPreviewDescriptor({
29
+ title: 'Web page preview'
30
+ }),
31
+ metadata: {
32
+ interfaceType: agent?.interface?.interfaceType || 'web'
33
+ }
34
+ };
35
+ }
36
+ });
37
+ export { webPlaygroundPlatform };
@@ -0,0 +1,364 @@
1
+ import { PlaywrightAgent } from "./index.mjs";
2
+ import { processCacheConfig } from "@godscene/core/utils";
3
+ import { DEFAULT_WAIT_FOR_NAVIGATION_TIMEOUT, DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT } from "@godscene/shared/constants";
4
+ import { getDebug } from "@godscene/shared/logger";
5
+ import { replaceIllegalPathCharsAndSpace, uuid } from "@godscene/shared/utils";
6
+ import { test } from "@playwright/test";
7
+ const debugPage = getDebug('web:playwright:ai-fixture');
8
+ const groupAndCaseForTest = (testInfo)=>{
9
+ let taskFile;
10
+ let taskTitle;
11
+ const titlePath = [
12
+ ...testInfo.titlePath
13
+ ];
14
+ if (titlePath.length > 1) {
15
+ taskFile = titlePath.shift() || 'unnamed';
16
+ taskTitle = titlePath.join('__');
17
+ } else if (1 === titlePath.length) {
18
+ taskTitle = titlePath[0];
19
+ taskFile = `${taskTitle}`;
20
+ } else {
21
+ taskTitle = 'unnamed';
22
+ taskFile = 'unnamed';
23
+ }
24
+ const taskTitleWithRetry = `${taskTitle}${testInfo.retry ? `(retry #${testInfo.retry})` : ''}`;
25
+ return {
26
+ file: taskFile,
27
+ id: replaceIllegalPathCharsAndSpace(`${taskFile}(${taskTitle})`),
28
+ title: replaceIllegalPathCharsAndSpace(taskTitleWithRetry)
29
+ };
30
+ };
31
+ const midsceneAgentKeyId = '_midsceneAgentId';
32
+ const midsceneDumpAnnotationId = 'MIDSCENE_DUMP_ANNOTATION';
33
+ const PlaywrightAiFixture = (options)=>{
34
+ const { forceSameTabNavigation = true, waitForNetworkIdleTimeout = DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT, waitForNavigationTimeout = DEFAULT_WAIT_FOR_NAVIGATION_TIMEOUT, cache, ...sharedAgentOptions } = options ?? {};
35
+ const processTestCacheConfig = (testInfo)=>{
36
+ const { id } = groupAndCaseForTest(testInfo);
37
+ return processCacheConfig(cache, id);
38
+ };
39
+ const pageAgentMap = {};
40
+ const testAgentRecords = new Map();
41
+ const getAgentRecordsForTest = (testInfo)=>{
42
+ let records = testAgentRecords.get(testInfo.testId);
43
+ if (!records) {
44
+ records = new Map();
45
+ testAgentRecords.set(testInfo.testId, records);
46
+ }
47
+ return records;
48
+ };
49
+ const setReportAnnotation = (testInfo, reportPaths)=>{
50
+ testInfo.annotations = testInfo.annotations.filter((item)=>item.type !== midsceneDumpAnnotationId);
51
+ for (const reportPath of reportPaths)testInfo.annotations.push({
52
+ type: midsceneDumpAnnotationId,
53
+ description: reportPath
54
+ });
55
+ };
56
+ const finalizeAgentRecord = async (record)=>{
57
+ if (!record.finalizePromise) record.finalizePromise = (async ()=>{
58
+ await record.agent.destroy();
59
+ const reportPath = record.agent.reportFile || void 0;
60
+ record.finalReportPath = reportPath;
61
+ return reportPath;
62
+ })();
63
+ return await record.finalizePromise;
64
+ };
65
+ const createOrReuseAgentForPage = (page, testInfo, opts)=>{
66
+ let idForPage = page[midsceneAgentKeyId];
67
+ if (!idForPage) {
68
+ idForPage = uuid();
69
+ page[midsceneAgentKeyId] = idForPage;
70
+ const { file, title } = groupAndCaseForTest(testInfo);
71
+ const cacheConfig = processTestCacheConfig(testInfo);
72
+ const reportTag = `playwright-${title.replace(/[\\/]/g, '-')}-${idForPage}`;
73
+ const agent = new PlaywrightAgent(page, {
74
+ testId: reportTag,
75
+ reportFileName: reportTag,
76
+ forceSameTabNavigation,
77
+ cache: cacheConfig,
78
+ groupName: title,
79
+ groupDescription: file,
80
+ generateReport: true,
81
+ ...sharedAgentOptions,
82
+ ...opts
83
+ });
84
+ pageAgentMap[idForPage] = agent;
85
+ const records = getAgentRecordsForTest(testInfo);
86
+ const record = {
87
+ agent
88
+ };
89
+ records.set(idForPage, record);
90
+ page.on('close', async ()=>{
91
+ debugPage('page closed');
92
+ try {
93
+ await finalizeAgentRecord(record);
94
+ } finally{
95
+ delete pageAgentMap[idForPage];
96
+ }
97
+ });
98
+ }
99
+ return pageAgentMap[idForPage];
100
+ };
101
+ async function generateAiFunction(options) {
102
+ const { page, testInfo, use, aiActionType } = options;
103
+ const agent = createOrReuseAgentForPage(page, testInfo, {
104
+ waitForNavigationTimeout,
105
+ waitForNetworkIdleTimeout
106
+ });
107
+ await use(async (taskPrompt, ...args)=>new Promise((resolve, reject)=>{
108
+ test.step(`ai-${aiActionType} - ${JSON.stringify(taskPrompt)}`, async ()=>{
109
+ try {
110
+ const result = await agent[aiActionType].bind(agent)(taskPrompt, ...args);
111
+ resolve(result);
112
+ } catch (error) {
113
+ reject(error);
114
+ }
115
+ });
116
+ }));
117
+ }
118
+ return {
119
+ _midsceneFinalizeReports: [
120
+ async ({}, use, testInfo)=>{
121
+ await use();
122
+ const records = testAgentRecords.get(testInfo.testId);
123
+ if (!records || 0 === records.size) return;
124
+ const reportPaths = (await Promise.all(Array.from(records.values()).map((record)=>finalizeAgentRecord(record)))).filter((reportPath)=>Boolean(reportPath));
125
+ if (reportPaths.length > 0) setReportAnnotation(testInfo, reportPaths);
126
+ testAgentRecords.delete(testInfo.testId);
127
+ },
128
+ {
129
+ auto: true
130
+ }
131
+ ],
132
+ agentForPage: async ({ page }, use, testInfo)=>{
133
+ await use(async (propsPage, opts)=>{
134
+ const cacheConfig = processTestCacheConfig(testInfo);
135
+ let finalCacheConfig = cacheConfig;
136
+ if (opts?.cache !== void 0) {
137
+ const userCache = opts.cache;
138
+ if (false === userCache) finalCacheConfig = false;
139
+ else if (true === userCache) {
140
+ const { id } = groupAndCaseForTest(testInfo);
141
+ finalCacheConfig = {
142
+ id
143
+ };
144
+ } else if ('object' == typeof userCache) if (userCache.id) finalCacheConfig = userCache;
145
+ else {
146
+ const { id } = groupAndCaseForTest(testInfo);
147
+ finalCacheConfig = {
148
+ ...userCache,
149
+ id
150
+ };
151
+ }
152
+ }
153
+ const agent = createOrReuseAgentForPage(propsPage || page, testInfo, {
154
+ waitForNavigationTimeout,
155
+ waitForNetworkIdleTimeout,
156
+ cache: finalCacheConfig,
157
+ ...opts
158
+ });
159
+ return agent;
160
+ });
161
+ },
162
+ ai: async ({ page }, use, testInfo)=>{
163
+ await generateAiFunction({
164
+ page,
165
+ testInfo,
166
+ use,
167
+ aiActionType: 'ai'
168
+ });
169
+ },
170
+ aiAct: async ({ page }, use, testInfo)=>{
171
+ await generateAiFunction({
172
+ page,
173
+ testInfo,
174
+ use,
175
+ aiActionType: 'aiAct'
176
+ });
177
+ },
178
+ aiAction: async ({ page }, use, testInfo)=>{
179
+ await generateAiFunction({
180
+ page,
181
+ testInfo,
182
+ use,
183
+ aiActionType: 'aiAction'
184
+ });
185
+ },
186
+ aiTap: async ({ page }, use, testInfo)=>{
187
+ await generateAiFunction({
188
+ page,
189
+ testInfo,
190
+ use,
191
+ aiActionType: 'aiTap'
192
+ });
193
+ },
194
+ aiRightClick: async ({ page }, use, testInfo)=>{
195
+ await generateAiFunction({
196
+ page,
197
+ testInfo,
198
+ use,
199
+ aiActionType: 'aiRightClick'
200
+ });
201
+ },
202
+ aiDoubleClick: async ({ page }, use, testInfo)=>{
203
+ await generateAiFunction({
204
+ page,
205
+ testInfo,
206
+ use,
207
+ aiActionType: 'aiDoubleClick'
208
+ });
209
+ },
210
+ aiHover: async ({ page }, use, testInfo)=>{
211
+ await generateAiFunction({
212
+ page,
213
+ testInfo,
214
+ use,
215
+ aiActionType: 'aiHover'
216
+ });
217
+ },
218
+ aiInput: async ({ page }, use, testInfo)=>{
219
+ await generateAiFunction({
220
+ page,
221
+ testInfo,
222
+ use,
223
+ aiActionType: 'aiInput'
224
+ });
225
+ },
226
+ aiKeyboardPress: async ({ page }, use, testInfo)=>{
227
+ await generateAiFunction({
228
+ page,
229
+ testInfo,
230
+ use,
231
+ aiActionType: 'aiKeyboardPress'
232
+ });
233
+ },
234
+ aiScroll: async ({ page }, use, testInfo)=>{
235
+ await generateAiFunction({
236
+ page,
237
+ testInfo,
238
+ use,
239
+ aiActionType: 'aiScroll'
240
+ });
241
+ },
242
+ aiQuery: async ({ page }, use, testInfo)=>{
243
+ await generateAiFunction({
244
+ page,
245
+ testInfo,
246
+ use,
247
+ aiActionType: 'aiQuery'
248
+ });
249
+ },
250
+ aiAssert: async ({ page }, use, testInfo)=>{
251
+ await generateAiFunction({
252
+ page,
253
+ testInfo,
254
+ use,
255
+ aiActionType: 'aiAssert'
256
+ });
257
+ },
258
+ aiWaitFor: async ({ page }, use, testInfo)=>{
259
+ await generateAiFunction({
260
+ page,
261
+ testInfo,
262
+ use,
263
+ aiActionType: 'aiWaitFor'
264
+ });
265
+ },
266
+ aiLocate: async ({ page }, use, testInfo)=>{
267
+ await generateAiFunction({
268
+ page,
269
+ testInfo,
270
+ use,
271
+ aiActionType: 'aiLocate'
272
+ });
273
+ },
274
+ aiNumber: async ({ page }, use, testInfo)=>{
275
+ await generateAiFunction({
276
+ page,
277
+ testInfo,
278
+ use,
279
+ aiActionType: 'aiNumber'
280
+ });
281
+ },
282
+ aiString: async ({ page }, use, testInfo)=>{
283
+ await generateAiFunction({
284
+ page,
285
+ testInfo,
286
+ use,
287
+ aiActionType: 'aiString'
288
+ });
289
+ },
290
+ aiBoolean: async ({ page }, use, testInfo)=>{
291
+ await generateAiFunction({
292
+ page,
293
+ testInfo,
294
+ use,
295
+ aiActionType: 'aiBoolean'
296
+ });
297
+ },
298
+ aiAsk: async ({ page }, use, testInfo)=>{
299
+ await generateAiFunction({
300
+ page,
301
+ testInfo,
302
+ use,
303
+ aiActionType: 'aiAsk'
304
+ });
305
+ },
306
+ runYaml: async ({ page }, use, testInfo)=>{
307
+ await generateAiFunction({
308
+ page,
309
+ testInfo,
310
+ use,
311
+ aiActionType: 'runYaml'
312
+ });
313
+ },
314
+ setAIActionContext: async ({ page }, use, testInfo)=>{
315
+ await generateAiFunction({
316
+ page,
317
+ testInfo,
318
+ use,
319
+ aiActionType: 'setAIActionContext'
320
+ });
321
+ },
322
+ evaluateJavaScript: async ({ page }, use, testInfo)=>{
323
+ await generateAiFunction({
324
+ page,
325
+ testInfo,
326
+ use,
327
+ aiActionType: 'evaluateJavaScript'
328
+ });
329
+ },
330
+ recordToReport: async ({ page }, use, testInfo)=>{
331
+ await generateAiFunction({
332
+ page,
333
+ testInfo,
334
+ use,
335
+ aiActionType: 'recordToReport'
336
+ });
337
+ },
338
+ logScreenshot: async ({ page }, use, testInfo)=>{
339
+ await generateAiFunction({
340
+ page,
341
+ testInfo,
342
+ use,
343
+ aiActionType: 'logScreenshot'
344
+ });
345
+ },
346
+ freezePageContext: async ({ page }, use, testInfo)=>{
347
+ await generateAiFunction({
348
+ page,
349
+ testInfo,
350
+ use,
351
+ aiActionType: 'freezePageContext'
352
+ });
353
+ },
354
+ unfreezePageContext: async ({ page }, use, testInfo)=>{
355
+ await generateAiFunction({
356
+ page,
357
+ testInfo,
358
+ use,
359
+ aiActionType: 'unfreezePageContext'
360
+ });
361
+ }
362
+ };
363
+ };
364
+ export { PlaywrightAiFixture, midsceneDumpAnnotationId };
@@ -0,0 +1,36 @@
1
+ import { Agent } from "@godscene/core/agent";
2
+ import { WebPage } from "./page.mjs";
3
+ import { PlaywrightAiFixture } from "./ai-fixture.mjs";
4
+ import { overrideAIConfig } from "@godscene/shared/env";
5
+ import { getDebug } from "@godscene/shared/logger";
6
+ import semver from "semver";
7
+ import { BROWSER_NAVIGATION_ERROR_PATTERN, forceChromeSelectRendering as base_page_mjs_forceChromeSelectRendering, forceClosePopup } from "../puppeteer/base-page.mjs";
8
+ import { getWebpackRequire } from "../utils.mjs";
9
+ const debug = getDebug('playwright:agent');
10
+ function getPlaywrightVersion() {
11
+ try {
12
+ const playwrightPkg = getWebpackRequire()('playwright/package.json');
13
+ return playwrightPkg.version || null;
14
+ } catch (error) {
15
+ console.error('[midscene:error] Failed to get Playwright version', error);
16
+ return null;
17
+ }
18
+ }
19
+ class PlaywrightAgent extends Agent {
20
+ isRetryableContextError(error) {
21
+ return error instanceof Error && BROWSER_NAVIGATION_ERROR_PATTERN.test(error.message);
22
+ }
23
+ constructor(page, opts){
24
+ if (!page) throw new Error('[midscene] PlaywrightAgent requires a valid Playwright page instance. Please make sure to pass a valid page object.');
25
+ const webPage = new WebPage(page, opts);
26
+ super(webPage, opts);
27
+ const { forceSameTabNavigation = true, forceChromeSelectRendering } = opts ?? {};
28
+ if (forceSameTabNavigation) forceClosePopup(page, debug);
29
+ if (forceChromeSelectRendering) {
30
+ const playwrightVersion = getPlaywrightVersion();
31
+ if (playwrightVersion && !semver.gte(playwrightVersion, '1.52.0')) console.warn(`[midscene:error] forceChromeSelectRendering requires Playwright >= 1.52.0, but current version is ${playwrightVersion}. This feature may not work correctly.`);
32
+ base_page_mjs_forceChromeSelectRendering(page);
33
+ }
34
+ }
35
+ }
36
+ export { PlaywrightAgent, PlaywrightAiFixture, WebPage as PlaywrightWebPage, overrideAIConfig };
@@ -0,0 +1,42 @@
1
+ import { Page } from "../puppeteer/base-page.mjs";
2
+ function _define_property(obj, key, value) {
3
+ if (key in obj) Object.defineProperty(obj, key, {
4
+ value: value,
5
+ enumerable: true,
6
+ configurable: true,
7
+ writable: true
8
+ });
9
+ else obj[key] = value;
10
+ return obj;
11
+ }
12
+ class WebPage extends Page {
13
+ async registerFileChooserListener(handler) {
14
+ const page = this.underlyingPage;
15
+ let capturedError;
16
+ this.playwrightFileChooserHandler = async (chooser)=>{
17
+ try {
18
+ await handler({
19
+ accept: async (files)=>{
20
+ await chooser.setFiles(files);
21
+ }
22
+ });
23
+ } catch (error) {
24
+ capturedError = error;
25
+ }
26
+ };
27
+ page.on('filechooser', this.playwrightFileChooserHandler);
28
+ return {
29
+ dispose: ()=>{
30
+ if (this.playwrightFileChooserHandler) {
31
+ page.off('filechooser', this.playwrightFileChooserHandler);
32
+ this.playwrightFileChooserHandler = void 0;
33
+ }
34
+ },
35
+ getError: ()=>capturedError
36
+ };
37
+ }
38
+ constructor(page, opts){
39
+ super(page, 'playwright', opts), _define_property(this, "playwrightFileChooserHandler", void 0);
40
+ }
41
+ }
42
+ export { WebPage };