@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.
- package/README.md +9 -0
- package/bin/midscene-playground +3 -0
- package/bin/midscene-web +2 -0
- package/dist/es/bin.mjs +23 -0
- package/dist/es/bin.mjs.map +1 -0
- package/dist/es/bridge-mode/agent-cli-side.mjs +137 -0
- package/dist/es/bridge-mode/agent-cli-side.mjs.map +1 -0
- package/dist/es/bridge-mode/browser.mjs +2 -0
- package/dist/es/bridge-mode/common.mjs +43 -0
- package/dist/es/bridge-mode/common.mjs.map +1 -0
- package/dist/es/bridge-mode/index.mjs +4 -0
- package/dist/es/bridge-mode/io-client.mjs +101 -0
- package/dist/es/bridge-mode/io-client.mjs.map +1 -0
- package/dist/es/bridge-mode/io-server.mjs +210 -0
- package/dist/es/bridge-mode/io-server.mjs.map +1 -0
- package/dist/es/bridge-mode/page-browser-side.mjs +118 -0
- package/dist/es/bridge-mode/page-browser-side.mjs.map +1 -0
- package/dist/es/chrome-extension/agent.mjs +9 -0
- package/dist/es/chrome-extension/agent.mjs.map +1 -0
- package/dist/es/chrome-extension/cdpInput.mjs +174 -0
- package/dist/es/chrome-extension/cdpInput.mjs.LICENSE.txt +5 -0
- package/dist/es/chrome-extension/cdpInput.mjs.map +1 -0
- package/dist/es/chrome-extension/dynamic-scripts.mjs +38 -0
- package/dist/es/chrome-extension/dynamic-scripts.mjs.map +1 -0
- package/dist/es/chrome-extension/index.mjs +5 -0
- package/dist/es/chrome-extension/page.mjs +651 -0
- package/dist/es/chrome-extension/page.mjs.map +1 -0
- package/dist/es/cli.mjs +16 -0
- package/dist/es/cli.mjs.map +1 -0
- package/dist/es/common/cache-helper.mjs +28 -0
- package/dist/es/common/cache-helper.mjs.map +1 -0
- package/dist/es/index.mjs +6 -0
- package/dist/es/mcp-server.mjs +35 -0
- package/dist/es/mcp-server.mjs.map +1 -0
- package/dist/es/mcp-tools-puppeteer.mjs +215 -0
- package/dist/es/mcp-tools-puppeteer.mjs.map +1 -0
- package/dist/es/mcp-tools.mjs +78 -0
- package/dist/es/mcp-tools.mjs.map +1 -0
- package/dist/es/playwright/ai-fixture.mjs +367 -0
- package/dist/es/playwright/ai-fixture.mjs.map +1 -0
- package/dist/es/playwright/index.mjs +40 -0
- package/dist/es/playwright/index.mjs.map +1 -0
- package/dist/es/playwright/page.mjs +44 -0
- package/dist/es/playwright/page.mjs.map +1 -0
- package/dist/es/playwright/reporter/index.mjs +216 -0
- package/dist/es/playwright/reporter/index.mjs.map +1 -0
- package/dist/es/puppeteer/agent-launcher.mjs +185 -0
- package/dist/es/puppeteer/agent-launcher.mjs.map +1 -0
- package/dist/es/puppeteer/base-page.mjs +564 -0
- package/dist/es/puppeteer/base-page.mjs.map +1 -0
- package/dist/es/puppeteer/index.mjs +34 -0
- package/dist/es/puppeteer/index.mjs.map +1 -0
- package/dist/es/puppeteer/page.mjs +9 -0
- package/dist/es/puppeteer/page.mjs.map +1 -0
- package/dist/es/static/index.mjs +3 -0
- package/dist/es/static/static-agent.mjs +12 -0
- package/dist/es/static/static-agent.mjs.map +1 -0
- package/dist/es/static/static-page.mjs +122 -0
- package/dist/es/static/static-page.mjs.map +1 -0
- package/dist/es/utils.mjs +8 -0
- package/dist/es/utils.mjs.map +1 -0
- package/dist/es/web-element.mjs +59 -0
- package/dist/es/web-element.mjs.map +1 -0
- package/dist/es/web-page.mjs +260 -0
- package/dist/es/web-page.mjs.map +1 -0
- package/dist/lib/bin.js +29 -0
- package/dist/lib/bin.js.map +1 -0
- package/dist/lib/bridge-mode/agent-cli-side.js +174 -0
- package/dist/lib/bridge-mode/agent-cli-side.js.map +1 -0
- package/dist/lib/bridge-mode/browser.js +38 -0
- package/dist/lib/bridge-mode/browser.js.map +1 -0
- package/dist/lib/bridge-mode/common.js +107 -0
- package/dist/lib/bridge-mode/common.js.map +1 -0
- package/dist/lib/bridge-mode/index.js +46 -0
- package/dist/lib/bridge-mode/index.js.map +1 -0
- package/dist/lib/bridge-mode/io-client.js +135 -0
- package/dist/lib/bridge-mode/io-client.js.map +1 -0
- package/dist/lib/bridge-mode/io-server.js +247 -0
- package/dist/lib/bridge-mode/io-server.js.map +1 -0
- package/dist/lib/bridge-mode/page-browser-side.js +162 -0
- package/dist/lib/bridge-mode/page-browser-side.js.map +1 -0
- package/dist/lib/chrome-extension/agent.js +43 -0
- package/dist/lib/chrome-extension/agent.js.map +1 -0
- package/dist/lib/chrome-extension/cdpInput.js +208 -0
- package/dist/lib/chrome-extension/cdpInput.js.LICENSE.txt +5 -0
- package/dist/lib/chrome-extension/cdpInput.js.map +1 -0
- package/dist/lib/chrome-extension/dynamic-scripts.js +88 -0
- package/dist/lib/chrome-extension/dynamic-scripts.js.map +1 -0
- package/dist/lib/chrome-extension/index.js +60 -0
- package/dist/lib/chrome-extension/index.js.map +1 -0
- package/dist/lib/chrome-extension/page.js +685 -0
- package/dist/lib/chrome-extension/page.js.map +1 -0
- package/dist/lib/cli.js +22 -0
- package/dist/lib/cli.js.map +1 -0
- package/dist/lib/common/cache-helper.js +68 -0
- package/dist/lib/common/cache-helper.js.map +1 -0
- package/dist/lib/index.js +60 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/mcp-server.js +75 -0
- package/dist/lib/mcp-server.js.map +1 -0
- package/dist/lib/mcp-tools-puppeteer.js +259 -0
- package/dist/lib/mcp-tools-puppeteer.js.map +1 -0
- package/dist/lib/mcp-tools.js +112 -0
- package/dist/lib/mcp-tools.js.map +1 -0
- package/dist/lib/playwright/ai-fixture.js +404 -0
- package/dist/lib/playwright/ai-fixture.js.map +1 -0
- package/dist/lib/playwright/index.js +93 -0
- package/dist/lib/playwright/index.js.map +1 -0
- package/dist/lib/playwright/page.js +78 -0
- package/dist/lib/playwright/page.js.map +1 -0
- package/dist/lib/playwright/reporter/index.js +250 -0
- package/dist/lib/playwright/reporter/index.js.map +1 -0
- package/dist/lib/puppeteer/agent-launcher.js +253 -0
- package/dist/lib/puppeteer/agent-launcher.js.map +1 -0
- package/dist/lib/puppeteer/base-page.js +607 -0
- package/dist/lib/puppeteer/base-page.js.map +1 -0
- package/dist/lib/puppeteer/index.js +84 -0
- package/dist/lib/puppeteer/index.js.map +1 -0
- package/dist/lib/puppeteer/page.js +43 -0
- package/dist/lib/puppeteer/page.js.map +1 -0
- package/dist/lib/static/index.js +52 -0
- package/dist/lib/static/index.js.map +1 -0
- package/dist/lib/static/static-agent.js +46 -0
- package/dist/lib/static/static-agent.js.map +1 -0
- package/dist/lib/static/static-page.js +156 -0
- package/dist/lib/static/static-page.js.map +1 -0
- package/dist/lib/utils.js +40 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/lib/web-element.js +96 -0
- package/dist/lib/web-element.js.map +1 -0
- package/dist/lib/web-page.js +310 -0
- package/dist/lib/web-page.js.map +1 -0
- package/dist/types/bin.d.ts +1 -0
- package/dist/types/bridge-mode/agent-cli-side.d.ts +49 -0
- package/dist/types/bridge-mode/browser.d.ts +2 -0
- package/dist/types/bridge-mode/common.d.ts +74 -0
- package/dist/types/bridge-mode/index.d.ts +4 -0
- package/dist/types/bridge-mode/io-client.d.ts +10 -0
- package/dist/types/bridge-mode/io-server.d.ts +27 -0
- package/dist/types/bridge-mode/page-browser-side.d.ts +21 -0
- package/dist/types/chrome-extension/agent.d.ts +5 -0
- package/dist/types/chrome-extension/cdpInput.d.ts +52 -0
- package/dist/types/chrome-extension/dynamic-scripts.d.ts +3 -0
- package/dist/types/chrome-extension/index.d.ts +5 -0
- package/dist/types/chrome-extension/page.d.ts +110 -0
- package/dist/types/cli.d.ts +1 -0
- package/dist/types/common/cache-helper.d.ts +20 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/mcp-server.d.ts +26 -0
- package/dist/types/mcp-tools-puppeteer.d.ts +13 -0
- package/dist/types/mcp-tools.d.ts +12 -0
- package/dist/types/playwright/ai-fixture.d.ts +131 -0
- package/dist/types/playwright/index.d.ts +13 -0
- package/dist/types/playwright/page.d.ts +11 -0
- package/dist/types/playwright/reporter/index.d.ts +42 -0
- package/dist/types/puppeteer/agent-launcher.d.ts +61 -0
- package/dist/types/puppeteer/base-page.d.ts +106 -0
- package/dist/types/puppeteer/index.d.ts +10 -0
- package/dist/types/puppeteer/page.d.ts +6 -0
- package/dist/types/static/index.d.ts +2 -0
- package/dist/types/static/static-agent.d.ts +5 -0
- package/dist/types/static/static-page.d.ts +42 -0
- package/dist/types/utils.d.ts +6 -0
- package/dist/types/web-element.d.ts +48 -0
- package/dist/types/web-page.d.ts +62 -0
- package/package.json +166 -0
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import { rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { PlaywrightAgent } from "./index.mjs";
|
|
5
|
+
import { processCacheConfig } from "@midscene/core/utils";
|
|
6
|
+
import { DEFAULT_WAIT_FOR_NAVIGATION_TIMEOUT, DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT } from "@midscene/shared/constants";
|
|
7
|
+
import { getDebug } from "@midscene/shared/logger";
|
|
8
|
+
import { replaceIllegalPathCharsAndSpace, uuid } from "@midscene/shared/utils";
|
|
9
|
+
import { test as test_test } from "@playwright/test";
|
|
10
|
+
const debugPage = getDebug('web:playwright:ai-fixture');
|
|
11
|
+
const groupAndCaseForTest = (testInfo)=>{
|
|
12
|
+
let taskFile;
|
|
13
|
+
let taskTitle;
|
|
14
|
+
const titlePath = [
|
|
15
|
+
...testInfo.titlePath
|
|
16
|
+
];
|
|
17
|
+
if (titlePath.length > 1) {
|
|
18
|
+
taskFile = titlePath.shift() || 'unnamed';
|
|
19
|
+
taskTitle = titlePath.join('__');
|
|
20
|
+
} else if (1 === titlePath.length) {
|
|
21
|
+
taskTitle = titlePath[0];
|
|
22
|
+
taskFile = `${taskTitle}`;
|
|
23
|
+
} else {
|
|
24
|
+
taskTitle = 'unnamed';
|
|
25
|
+
taskFile = 'unnamed';
|
|
26
|
+
}
|
|
27
|
+
const taskTitleWithRetry = `${taskTitle}${testInfo.retry ? `(retry #${testInfo.retry})` : ''}`;
|
|
28
|
+
return {
|
|
29
|
+
file: taskFile,
|
|
30
|
+
id: replaceIllegalPathCharsAndSpace(`${taskFile}(${taskTitle})`),
|
|
31
|
+
title: replaceIllegalPathCharsAndSpace(taskTitleWithRetry)
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
const midsceneAgentKeyId = '_midsceneAgentId';
|
|
35
|
+
const midsceneDumpAnnotationId = 'MIDSCENE_DUMP_ANNOTATION';
|
|
36
|
+
const pageTempFiles = new Map();
|
|
37
|
+
const PlaywrightAiFixture = (options)=>{
|
|
38
|
+
const { forceSameTabNavigation = true, waitForNetworkIdleTimeout = DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT, waitForNavigationTimeout = DEFAULT_WAIT_FOR_NAVIGATION_TIMEOUT, cache } = options ?? {};
|
|
39
|
+
const processTestCacheConfig = (testInfo)=>{
|
|
40
|
+
const { id } = groupAndCaseForTest(testInfo);
|
|
41
|
+
return processCacheConfig(cache, id);
|
|
42
|
+
};
|
|
43
|
+
const pageAgentMap = {};
|
|
44
|
+
const createOrReuseAgentForPage = (page, testInfo, opts)=>{
|
|
45
|
+
let idForPage = page[midsceneAgentKeyId];
|
|
46
|
+
if (!idForPage) {
|
|
47
|
+
idForPage = uuid();
|
|
48
|
+
page[midsceneAgentKeyId] = idForPage;
|
|
49
|
+
const { testId } = testInfo;
|
|
50
|
+
const { file, title } = groupAndCaseForTest(testInfo);
|
|
51
|
+
const cacheConfig = processTestCacheConfig(testInfo);
|
|
52
|
+
pageAgentMap[idForPage] = new PlaywrightAgent(page, {
|
|
53
|
+
testId: `playwright-${testId}-${idForPage}`,
|
|
54
|
+
forceSameTabNavigation,
|
|
55
|
+
cache: cacheConfig,
|
|
56
|
+
groupName: title,
|
|
57
|
+
groupDescription: file,
|
|
58
|
+
generateReport: false,
|
|
59
|
+
...opts
|
|
60
|
+
});
|
|
61
|
+
pageAgentMap[idForPage].onDumpUpdate = (dump)=>{
|
|
62
|
+
updateDumpAnnotation(testInfo, dump, idForPage);
|
|
63
|
+
};
|
|
64
|
+
page.on('close', ()=>{
|
|
65
|
+
debugPage('page closed');
|
|
66
|
+
pageTempFiles.delete(idForPage);
|
|
67
|
+
pageAgentMap[idForPage]?.destroy();
|
|
68
|
+
delete pageAgentMap[idForPage];
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return pageAgentMap[idForPage];
|
|
72
|
+
};
|
|
73
|
+
async function generateAiFunction(options) {
|
|
74
|
+
const { page, testInfo, use, aiActionType } = options;
|
|
75
|
+
const agent = createOrReuseAgentForPage(page, testInfo, {
|
|
76
|
+
waitForNavigationTimeout,
|
|
77
|
+
waitForNetworkIdleTimeout
|
|
78
|
+
});
|
|
79
|
+
await use(async (taskPrompt, ...args)=>new Promise((resolve, reject)=>{
|
|
80
|
+
test_test.step(`ai-${aiActionType} - ${JSON.stringify(taskPrompt)}`, async ()=>{
|
|
81
|
+
try {
|
|
82
|
+
debugPage(`waitForNetworkIdle timeout: ${waitForNetworkIdleTimeout}`);
|
|
83
|
+
await agent.waitForNetworkIdle(waitForNetworkIdleTimeout);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
console.warn('[midscene:warning] Waiting for 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');
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
const result = await agent[aiActionType].bind(agent)(taskPrompt, ...args);
|
|
89
|
+
resolve(result);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
reject(error);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
const updateDumpAnnotation = (test, dump, pageId)=>{
|
|
97
|
+
const oldTempFilePath = pageTempFiles.get(pageId);
|
|
98
|
+
if (oldTempFilePath) try {
|
|
99
|
+
rmSync(oldTempFilePath, {
|
|
100
|
+
force: true
|
|
101
|
+
});
|
|
102
|
+
rmSync(`${oldTempFilePath}.screenshots`, {
|
|
103
|
+
force: true,
|
|
104
|
+
recursive: true
|
|
105
|
+
});
|
|
106
|
+
rmSync(`${oldTempFilePath}.screenshots.json`, {
|
|
107
|
+
force: true
|
|
108
|
+
});
|
|
109
|
+
} catch (error) {}
|
|
110
|
+
const tempFileName = `midscene-dump-${test.testId || uuid()}-${pageId}.json`;
|
|
111
|
+
const tempFilePath = join(tmpdir(), tempFileName);
|
|
112
|
+
try {
|
|
113
|
+
const agent = pageAgentMap[pageId];
|
|
114
|
+
if (agent) {
|
|
115
|
+
agent.dump.serializeToFiles(tempFilePath);
|
|
116
|
+
debugPage(`Dump with screenshots serialized to: ${tempFilePath}`);
|
|
117
|
+
} else {
|
|
118
|
+
writeFileSync(tempFilePath, dump, 'utf-8');
|
|
119
|
+
debugPage(`Dump written to temp file: ${tempFilePath}`);
|
|
120
|
+
}
|
|
121
|
+
pageTempFiles.set(pageId, tempFilePath);
|
|
122
|
+
const currentAnnotation = test.annotations.find((item)=>item.type === midsceneDumpAnnotationId);
|
|
123
|
+
if (currentAnnotation) currentAnnotation.description = tempFilePath;
|
|
124
|
+
else test.annotations.push({
|
|
125
|
+
type: midsceneDumpAnnotationId,
|
|
126
|
+
description: tempFilePath
|
|
127
|
+
});
|
|
128
|
+
} catch (error) {
|
|
129
|
+
debugPage(`Failed to write temp file: ${tempFilePath}. Skipping annotation.`, error);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
return {
|
|
133
|
+
agentForPage: async ({ page }, use, testInfo)=>{
|
|
134
|
+
await use(async (propsPage, opts)=>{
|
|
135
|
+
const cacheConfig = processTestCacheConfig(testInfo);
|
|
136
|
+
let finalCacheConfig = cacheConfig;
|
|
137
|
+
if (opts?.cache !== void 0) {
|
|
138
|
+
const userCache = opts.cache;
|
|
139
|
+
if (false === userCache) finalCacheConfig = false;
|
|
140
|
+
else if (true === userCache) {
|
|
141
|
+
const { id } = groupAndCaseForTest(testInfo);
|
|
142
|
+
finalCacheConfig = {
|
|
143
|
+
id
|
|
144
|
+
};
|
|
145
|
+
} else if ('object' == typeof userCache) if (userCache.id) finalCacheConfig = userCache;
|
|
146
|
+
else {
|
|
147
|
+
const { id } = groupAndCaseForTest(testInfo);
|
|
148
|
+
finalCacheConfig = {
|
|
149
|
+
...userCache,
|
|
150
|
+
id
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const agent = createOrReuseAgentForPage(propsPage || page, testInfo, {
|
|
155
|
+
waitForNavigationTimeout,
|
|
156
|
+
waitForNetworkIdleTimeout,
|
|
157
|
+
cache: finalCacheConfig,
|
|
158
|
+
...opts
|
|
159
|
+
});
|
|
160
|
+
return agent;
|
|
161
|
+
});
|
|
162
|
+
},
|
|
163
|
+
ai: async ({ page }, use, testInfo)=>{
|
|
164
|
+
await generateAiFunction({
|
|
165
|
+
page,
|
|
166
|
+
testInfo,
|
|
167
|
+
use,
|
|
168
|
+
aiActionType: 'ai'
|
|
169
|
+
});
|
|
170
|
+
},
|
|
171
|
+
aiAct: async ({ page }, use, testInfo)=>{
|
|
172
|
+
await generateAiFunction({
|
|
173
|
+
page,
|
|
174
|
+
testInfo,
|
|
175
|
+
use,
|
|
176
|
+
aiActionType: 'aiAct'
|
|
177
|
+
});
|
|
178
|
+
},
|
|
179
|
+
aiAction: async ({ page }, use, testInfo)=>{
|
|
180
|
+
await generateAiFunction({
|
|
181
|
+
page,
|
|
182
|
+
testInfo,
|
|
183
|
+
use,
|
|
184
|
+
aiActionType: 'aiAction'
|
|
185
|
+
});
|
|
186
|
+
},
|
|
187
|
+
aiTap: async ({ page }, use, testInfo)=>{
|
|
188
|
+
await generateAiFunction({
|
|
189
|
+
page,
|
|
190
|
+
testInfo,
|
|
191
|
+
use,
|
|
192
|
+
aiActionType: 'aiTap'
|
|
193
|
+
});
|
|
194
|
+
},
|
|
195
|
+
aiRightClick: async ({ page }, use, testInfo)=>{
|
|
196
|
+
await generateAiFunction({
|
|
197
|
+
page,
|
|
198
|
+
testInfo,
|
|
199
|
+
use,
|
|
200
|
+
aiActionType: 'aiRightClick'
|
|
201
|
+
});
|
|
202
|
+
},
|
|
203
|
+
aiDoubleClick: async ({ page }, use, testInfo)=>{
|
|
204
|
+
await generateAiFunction({
|
|
205
|
+
page,
|
|
206
|
+
testInfo,
|
|
207
|
+
use,
|
|
208
|
+
aiActionType: 'aiDoubleClick'
|
|
209
|
+
});
|
|
210
|
+
},
|
|
211
|
+
aiHover: async ({ page }, use, testInfo)=>{
|
|
212
|
+
await generateAiFunction({
|
|
213
|
+
page,
|
|
214
|
+
testInfo,
|
|
215
|
+
use,
|
|
216
|
+
aiActionType: 'aiHover'
|
|
217
|
+
});
|
|
218
|
+
},
|
|
219
|
+
aiInput: async ({ page }, use, testInfo)=>{
|
|
220
|
+
await generateAiFunction({
|
|
221
|
+
page,
|
|
222
|
+
testInfo,
|
|
223
|
+
use,
|
|
224
|
+
aiActionType: 'aiInput'
|
|
225
|
+
});
|
|
226
|
+
},
|
|
227
|
+
aiKeyboardPress: async ({ page }, use, testInfo)=>{
|
|
228
|
+
await generateAiFunction({
|
|
229
|
+
page,
|
|
230
|
+
testInfo,
|
|
231
|
+
use,
|
|
232
|
+
aiActionType: 'aiKeyboardPress'
|
|
233
|
+
});
|
|
234
|
+
},
|
|
235
|
+
aiScroll: async ({ page }, use, testInfo)=>{
|
|
236
|
+
await generateAiFunction({
|
|
237
|
+
page,
|
|
238
|
+
testInfo,
|
|
239
|
+
use,
|
|
240
|
+
aiActionType: 'aiScroll'
|
|
241
|
+
});
|
|
242
|
+
},
|
|
243
|
+
aiQuery: async ({ page }, use, testInfo)=>{
|
|
244
|
+
await generateAiFunction({
|
|
245
|
+
page,
|
|
246
|
+
testInfo,
|
|
247
|
+
use,
|
|
248
|
+
aiActionType: 'aiQuery'
|
|
249
|
+
});
|
|
250
|
+
},
|
|
251
|
+
aiAssert: async ({ page }, use, testInfo)=>{
|
|
252
|
+
await generateAiFunction({
|
|
253
|
+
page,
|
|
254
|
+
testInfo,
|
|
255
|
+
use,
|
|
256
|
+
aiActionType: 'aiAssert'
|
|
257
|
+
});
|
|
258
|
+
},
|
|
259
|
+
aiWaitFor: async ({ page }, use, testInfo)=>{
|
|
260
|
+
await generateAiFunction({
|
|
261
|
+
page,
|
|
262
|
+
testInfo,
|
|
263
|
+
use,
|
|
264
|
+
aiActionType: 'aiWaitFor'
|
|
265
|
+
});
|
|
266
|
+
},
|
|
267
|
+
aiLocate: async ({ page }, use, testInfo)=>{
|
|
268
|
+
await generateAiFunction({
|
|
269
|
+
page,
|
|
270
|
+
testInfo,
|
|
271
|
+
use,
|
|
272
|
+
aiActionType: 'aiLocate'
|
|
273
|
+
});
|
|
274
|
+
},
|
|
275
|
+
aiNumber: async ({ page }, use, testInfo)=>{
|
|
276
|
+
await generateAiFunction({
|
|
277
|
+
page,
|
|
278
|
+
testInfo,
|
|
279
|
+
use,
|
|
280
|
+
aiActionType: 'aiNumber'
|
|
281
|
+
});
|
|
282
|
+
},
|
|
283
|
+
aiString: async ({ page }, use, testInfo)=>{
|
|
284
|
+
await generateAiFunction({
|
|
285
|
+
page,
|
|
286
|
+
testInfo,
|
|
287
|
+
use,
|
|
288
|
+
aiActionType: 'aiString'
|
|
289
|
+
});
|
|
290
|
+
},
|
|
291
|
+
aiBoolean: async ({ page }, use, testInfo)=>{
|
|
292
|
+
await generateAiFunction({
|
|
293
|
+
page,
|
|
294
|
+
testInfo,
|
|
295
|
+
use,
|
|
296
|
+
aiActionType: 'aiBoolean'
|
|
297
|
+
});
|
|
298
|
+
},
|
|
299
|
+
aiAsk: async ({ page }, use, testInfo)=>{
|
|
300
|
+
await generateAiFunction({
|
|
301
|
+
page,
|
|
302
|
+
testInfo,
|
|
303
|
+
use,
|
|
304
|
+
aiActionType: 'aiAsk'
|
|
305
|
+
});
|
|
306
|
+
},
|
|
307
|
+
runYaml: async ({ page }, use, testInfo)=>{
|
|
308
|
+
await generateAiFunction({
|
|
309
|
+
page,
|
|
310
|
+
testInfo,
|
|
311
|
+
use,
|
|
312
|
+
aiActionType: 'runYaml'
|
|
313
|
+
});
|
|
314
|
+
},
|
|
315
|
+
setAIActionContext: async ({ page }, use, testInfo)=>{
|
|
316
|
+
await generateAiFunction({
|
|
317
|
+
page,
|
|
318
|
+
testInfo,
|
|
319
|
+
use,
|
|
320
|
+
aiActionType: 'setAIActionContext'
|
|
321
|
+
});
|
|
322
|
+
},
|
|
323
|
+
evaluateJavaScript: async ({ page }, use, testInfo)=>{
|
|
324
|
+
await generateAiFunction({
|
|
325
|
+
page,
|
|
326
|
+
testInfo,
|
|
327
|
+
use,
|
|
328
|
+
aiActionType: 'evaluateJavaScript'
|
|
329
|
+
});
|
|
330
|
+
},
|
|
331
|
+
recordToReport: async ({ page }, use, testInfo)=>{
|
|
332
|
+
await generateAiFunction({
|
|
333
|
+
page,
|
|
334
|
+
testInfo,
|
|
335
|
+
use,
|
|
336
|
+
aiActionType: 'recordToReport'
|
|
337
|
+
});
|
|
338
|
+
},
|
|
339
|
+
logScreenshot: async ({ page }, use, testInfo)=>{
|
|
340
|
+
await generateAiFunction({
|
|
341
|
+
page,
|
|
342
|
+
testInfo,
|
|
343
|
+
use,
|
|
344
|
+
aiActionType: 'logScreenshot'
|
|
345
|
+
});
|
|
346
|
+
},
|
|
347
|
+
freezePageContext: async ({ page }, use, testInfo)=>{
|
|
348
|
+
await generateAiFunction({
|
|
349
|
+
page,
|
|
350
|
+
testInfo,
|
|
351
|
+
use,
|
|
352
|
+
aiActionType: 'freezePageContext'
|
|
353
|
+
});
|
|
354
|
+
},
|
|
355
|
+
unfreezePageContext: async ({ page }, use, testInfo)=>{
|
|
356
|
+
await generateAiFunction({
|
|
357
|
+
page,
|
|
358
|
+
testInfo,
|
|
359
|
+
use,
|
|
360
|
+
aiActionType: 'unfreezePageContext'
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
};
|
|
365
|
+
export { PlaywrightAiFixture, midsceneDumpAnnotationId };
|
|
366
|
+
|
|
367
|
+
//# sourceMappingURL=ai-fixture.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playwright/ai-fixture.mjs","sources":["../../../src/playwright/ai-fixture.ts"],"sourcesContent":["import { rmSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { PlaywrightAgent, type PlaywrightWebPage } from '@/playwright/index';\nimport type { WebPageAgentOpt } from '@/web-element';\nimport type { Cache } from '@midscene/core';\nimport type { AgentOpt, Agent as PageAgent } from '@midscene/core/agent';\nimport { processCacheConfig } from '@midscene/core/utils';\nimport {\n DEFAULT_WAIT_FOR_NAVIGATION_TIMEOUT,\n DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT,\n} from '@midscene/shared/constants';\nimport { getDebug } from '@midscene/shared/logger';\nimport { uuid } from '@midscene/shared/utils';\nimport { replaceIllegalPathCharsAndSpace } from '@midscene/shared/utils';\nimport { type TestInfo, type TestType, test } from '@playwright/test';\nimport type { Page as OriginPlaywrightPage } from 'playwright';\nexport type APITestType = Pick<TestType<any, any>, 'step'>;\n\nconst debugPage = getDebug('web:playwright:ai-fixture');\n\nconst groupAndCaseForTest = (testInfo: TestInfo) => {\n let taskFile: string;\n let taskTitle: string;\n const titlePath = [...testInfo.titlePath];\n\n if (titlePath.length > 1) {\n taskFile = titlePath.shift() || 'unnamed';\n taskTitle = titlePath.join('__');\n } else if (titlePath.length === 1) {\n taskTitle = titlePath[0];\n taskFile = `${taskTitle}`;\n } else {\n taskTitle = 'unnamed';\n taskFile = 'unnamed';\n }\n\n const taskTitleWithRetry = `${taskTitle}${testInfo.retry ? `(retry #${testInfo.retry})` : ''}`;\n\n return {\n file: taskFile,\n id: replaceIllegalPathCharsAndSpace(`${taskFile}(${taskTitle})`),\n title: replaceIllegalPathCharsAndSpace(taskTitleWithRetry),\n };\n};\n\nconst midsceneAgentKeyId = '_midsceneAgentId';\nexport const midsceneDumpAnnotationId = 'MIDSCENE_DUMP_ANNOTATION';\n\n// Track temporary dump files per page for cleanup\nconst pageTempFiles = new Map<string, string>();\n\ntype PlaywrightCacheConfig = {\n strategy?: 'read-only' | 'read-write' | 'write-only';\n id?: string;\n};\ntype PlaywrightCache = false | true | PlaywrightCacheConfig;\n\nexport const PlaywrightAiFixture = (options?: {\n forceSameTabNavigation?: boolean;\n waitForNetworkIdleTimeout?: number;\n waitForNavigationTimeout?: number;\n cache?: PlaywrightCache;\n}) => {\n const {\n forceSameTabNavigation = true,\n waitForNetworkIdleTimeout = DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT,\n waitForNavigationTimeout = DEFAULT_WAIT_FOR_NAVIGATION_TIMEOUT,\n cache,\n } = options ?? {};\n\n // Helper function to process cache configuration and auto-generate ID from test info\n const processTestCacheConfig = (testInfo: TestInfo): Cache | undefined => {\n // Generate ID from test info\n const { id } = groupAndCaseForTest(testInfo);\n\n // Use shared processCacheConfig with generated ID as fallback\n return processCacheConfig(cache as Cache, id);\n };\n\n const pageAgentMap: Record<string, PageAgent<PlaywrightWebPage>> = {};\n const createOrReuseAgentForPage = (\n page: OriginPlaywrightPage,\n testInfo: TestInfo, // { testId: string; taskFile: string; taskTitle: string },\n opts?: WebPageAgentOpt,\n ) => {\n let idForPage = (page as any)[midsceneAgentKeyId];\n if (!idForPage) {\n idForPage = uuid();\n (page as any)[midsceneAgentKeyId] = idForPage;\n const { testId } = testInfo;\n const { file, title } = groupAndCaseForTest(testInfo);\n const cacheConfig = processTestCacheConfig(testInfo);\n\n pageAgentMap[idForPage] = new PlaywrightAgent(page, {\n testId: `playwright-${testId}-${idForPage}`,\n forceSameTabNavigation,\n cache: cacheConfig,\n groupName: title,\n groupDescription: file,\n generateReport: false, // we will generate it in the reporter\n ...opts,\n });\n\n pageAgentMap[idForPage].onDumpUpdate = (dump: string) => {\n updateDumpAnnotation(testInfo, dump, idForPage);\n };\n\n page.on('close', () => {\n debugPage('page closed');\n\n // Clean up agent and temp file tracking\n // Note: serializeToFiles is already called in updateDumpAnnotation,\n // so we don't need to write files again here\n pageTempFiles.delete(idForPage);\n pageAgentMap[idForPage]?.destroy();\n delete pageAgentMap[idForPage];\n });\n }\n\n return pageAgentMap[idForPage];\n };\n\n async function generateAiFunction(options: {\n page: OriginPlaywrightPage;\n testInfo: TestInfo;\n use: any;\n aiActionType:\n | 'ai'\n | 'aiAct'\n | 'aiAction'\n | 'aiHover'\n | 'aiInput'\n | 'aiKeyboardPress'\n | 'aiScroll'\n | 'aiTap'\n | 'aiRightClick'\n | 'aiDoubleClick'\n | 'aiQuery'\n | 'aiAssert'\n | 'aiWaitFor'\n | 'aiLocate'\n | 'aiNumber'\n | 'aiString'\n | 'aiBoolean'\n | 'aiAsk'\n | 'runYaml'\n | 'setAIActionContext'\n | 'evaluateJavaScript'\n | 'recordToReport'\n | 'logScreenshot'\n | 'freezePageContext'\n | 'unfreezePageContext';\n }) {\n const { page, testInfo, use, aiActionType } = options;\n const agent = createOrReuseAgentForPage(page, testInfo, {\n waitForNavigationTimeout,\n waitForNetworkIdleTimeout,\n }) as PlaywrightAgent;\n\n await use(async (taskPrompt: string, ...args: any[]) => {\n return new Promise((resolve, reject) => {\n test.step(`ai-${aiActionType} - ${JSON.stringify(taskPrompt)}`, async () => {\n try {\n debugPage(\n `waitForNetworkIdle timeout: ${waitForNetworkIdleTimeout}`,\n );\n await agent.waitForNetworkIdle(waitForNetworkIdleTimeout);\n } catch (error) {\n console.warn(\n '[midscene:warning] Waiting for 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',\n );\n }\n try {\n type AgentMethod = (\n prompt: string,\n ...restArgs: any[]\n ) => Promise<any>;\n const result = await (agent[aiActionType] as AgentMethod).bind(\n agent,\n )(taskPrompt, ...args);\n resolve(result);\n } catch (error) {\n reject(error);\n }\n });\n });\n });\n }\n\n const updateDumpAnnotation = (\n test: TestInfo,\n dump: string,\n pageId: string,\n ) => {\n // 1. First, clean up the old temp files if they exist\n const oldTempFilePath = pageTempFiles.get(pageId);\n if (oldTempFilePath) {\n try {\n rmSync(oldTempFilePath, { force: true });\n rmSync(`${oldTempFilePath}.screenshots`, {\n force: true,\n recursive: true,\n });\n rmSync(`${oldTempFilePath}.screenshots.json`, { force: true });\n } catch (error) {\n // Silently ignore if old files are already cleaned up\n }\n }\n\n // 2. Create new temp file with predictable name using pageId\n const tempFileName = `midscene-dump-${test.testId || uuid()}-${pageId}.json`;\n const tempFilePath = join(tmpdir(), tempFileName);\n\n // 3. Serialize dump with screenshots as separate files\n // This ensures Reporter can copy screenshots when outputFormat is 'html-and-external-assets'\n try {\n const agent = pageAgentMap[pageId];\n if (agent) {\n agent.dump.serializeToFiles(tempFilePath);\n debugPage(`Dump with screenshots serialized to: ${tempFilePath}`);\n } else {\n // Fallback: write dump string directly if agent not available\n writeFileSync(tempFilePath, dump, 'utf-8');\n debugPage(`Dump written to temp file: ${tempFilePath}`);\n }\n\n // 4. Track the new temp file (only if write succeeded)\n pageTempFiles.set(pageId, tempFilePath);\n\n // Store only the file path in annotation (only if write succeeded)\n const currentAnnotation = test.annotations.find((item) => {\n return item.type === midsceneDumpAnnotationId;\n });\n if (currentAnnotation) {\n // Store file path instead of dump content\n currentAnnotation.description = tempFilePath;\n } else {\n test.annotations.push({\n type: midsceneDumpAnnotationId,\n description: tempFilePath,\n });\n }\n } catch (error) {\n // If write fails (e.g., disk full), don't track the file or add annotation\n // This prevents reporter from trying to read a non-existent file\n debugPage(\n `Failed to write temp file: ${tempFilePath}. Skipping annotation.`,\n error,\n );\n }\n };\n\n return {\n agentForPage: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await use(\n async (\n propsPage?: OriginPlaywrightPage | undefined,\n opts?: AgentOpt,\n ) => {\n const cacheConfig = processTestCacheConfig(testInfo);\n\n // Handle cache configuration priority:\n // 1. If user provides cache in opts, use it (but auto-generate ID if missing)\n // 2. Otherwise use fixture's cache config\n let finalCacheConfig = cacheConfig;\n if (opts?.cache !== undefined) {\n const userCache = opts.cache;\n if (userCache === false) {\n finalCacheConfig = false;\n } else if (userCache === true) {\n // Auto-generate ID for user's cache: true\n const { id } = groupAndCaseForTest(testInfo);\n finalCacheConfig = { id };\n } else if (typeof userCache === 'object') {\n if (!userCache.id) {\n // Auto-generate ID for user's cache object without ID\n const { id } = groupAndCaseForTest(testInfo);\n finalCacheConfig = { ...userCache, id };\n } else {\n finalCacheConfig = userCache;\n }\n }\n }\n\n const agent = createOrReuseAgentForPage(propsPage || page, testInfo, {\n waitForNavigationTimeout,\n waitForNetworkIdleTimeout,\n cache: finalCacheConfig,\n ...opts,\n });\n return agent;\n },\n );\n },\n ai: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'ai',\n });\n },\n aiAct: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'aiAct',\n });\n },\n /**\n * @deprecated Use {@link PlaywrightAiFixture.aiAct} instead.\n */\n aiAction: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'aiAction',\n });\n },\n aiTap: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'aiTap',\n });\n },\n aiRightClick: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'aiRightClick',\n });\n },\n aiDoubleClick: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'aiDoubleClick',\n });\n },\n aiHover: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'aiHover',\n });\n },\n aiInput: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'aiInput',\n });\n },\n aiKeyboardPress: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'aiKeyboardPress',\n });\n },\n aiScroll: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'aiScroll',\n });\n },\n aiQuery: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'aiQuery',\n });\n },\n aiAssert: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'aiAssert',\n });\n },\n aiWaitFor: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'aiWaitFor',\n });\n },\n aiLocate: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'aiLocate',\n });\n },\n aiNumber: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'aiNumber',\n });\n },\n aiString: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'aiString',\n });\n },\n aiBoolean: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'aiBoolean',\n });\n },\n aiAsk: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'aiAsk',\n });\n },\n runYaml: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'runYaml',\n });\n },\n setAIActionContext: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'setAIActionContext',\n });\n },\n evaluateJavaScript: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'evaluateJavaScript',\n });\n },\n recordToReport: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'recordToReport',\n });\n },\n logScreenshot: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'logScreenshot',\n });\n },\n freezePageContext: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'freezePageContext',\n });\n },\n unfreezePageContext: async (\n { page }: { page: OriginPlaywrightPage },\n use: any,\n testInfo: TestInfo,\n ) => {\n await generateAiFunction({\n page,\n testInfo,\n use,\n aiActionType: 'unfreezePageContext',\n });\n },\n };\n};\n\nexport type PlayWrightAiFixtureType = {\n agentForPage: (\n page?: any,\n opts?: any,\n ) => Promise<PageAgent<PlaywrightWebPage>>;\n ai: <T = any>(...args: Parameters<PageAgent['ai']>) => Promise<T>;\n aiAct: (\n ...args: Parameters<PageAgent['aiAct']>\n ) => ReturnType<PageAgent['aiAct']>;\n /**\n * @deprecated Use {@link PlayWrightAiFixtureType.aiAct} instead.\n */\n aiAction: (\n ...args: Parameters<PageAgent['aiAction']>\n ) => ReturnType<PageAgent['aiAction']>;\n aiTap: (\n ...args: Parameters<PageAgent['aiTap']>\n ) => ReturnType<PageAgent['aiTap']>;\n aiRightClick: (\n ...args: Parameters<PageAgent['aiRightClick']>\n ) => ReturnType<PageAgent['aiRightClick']>;\n aiDoubleClick: (\n ...args: Parameters<PageAgent['aiDoubleClick']>\n ) => ReturnType<PageAgent['aiDoubleClick']>;\n aiHover: (\n ...args: Parameters<PageAgent['aiHover']>\n ) => ReturnType<PageAgent['aiHover']>;\n aiInput: (\n ...args: Parameters<PageAgent['aiInput']>\n ) => ReturnType<PageAgent['aiInput']>;\n aiKeyboardPress: (\n ...args: Parameters<PageAgent['aiKeyboardPress']>\n ) => ReturnType<PageAgent['aiKeyboardPress']>;\n aiScroll: (\n ...args: Parameters<PageAgent['aiScroll']>\n ) => ReturnType<PageAgent['aiScroll']>;\n aiQuery: <T = any>(...args: Parameters<PageAgent['aiQuery']>) => Promise<T>;\n aiAssert: (\n ...args: Parameters<PageAgent['aiAssert']>\n ) => ReturnType<PageAgent['aiAssert']>;\n aiWaitFor: (...args: Parameters<PageAgent['aiWaitFor']>) => Promise<void>;\n aiLocate: (\n ...args: Parameters<PageAgent['aiLocate']>\n ) => ReturnType<PageAgent['aiLocate']>;\n aiNumber: (\n ...args: Parameters<PageAgent['aiNumber']>\n ) => ReturnType<PageAgent['aiNumber']>;\n aiString: (\n ...args: Parameters<PageAgent['aiString']>\n ) => ReturnType<PageAgent['aiString']>;\n aiBoolean: (\n ...args: Parameters<PageAgent['aiBoolean']>\n ) => ReturnType<PageAgent['aiBoolean']>;\n aiAsk: (\n ...args: Parameters<PageAgent['aiAsk']>\n ) => ReturnType<PageAgent['aiAsk']>;\n runYaml: (\n ...args: Parameters<PageAgent['runYaml']>\n ) => ReturnType<PageAgent['runYaml']>;\n setAIActionContext: (\n ...args: Parameters<PageAgent['setAIActionContext']>\n ) => ReturnType<PageAgent['setAIActionContext']>;\n evaluateJavaScript: (\n ...args: Parameters<PageAgent['evaluateJavaScript']>\n ) => ReturnType<PageAgent['evaluateJavaScript']>;\n recordToReport: (\n ...args: Parameters<PageAgent['recordToReport']>\n ) => ReturnType<PageAgent['recordToReport']>;\n logScreenshot: (\n ...args: Parameters<PageAgent['logScreenshot']>\n ) => ReturnType<PageAgent['logScreenshot']>;\n freezePageContext: (\n ...args: Parameters<PageAgent['freezePageContext']>\n ) => ReturnType<PageAgent['freezePageContext']>;\n unfreezePageContext: (\n ...args: Parameters<PageAgent['unfreezePageContext']>\n ) => ReturnType<PageAgent['unfreezePageContext']>;\n};\n"],"names":["debugPage","getDebug","groupAndCaseForTest","testInfo","taskFile","taskTitle","titlePath","taskTitleWithRetry","replaceIllegalPathCharsAndSpace","midsceneAgentKeyId","midsceneDumpAnnotationId","pageTempFiles","Map","PlaywrightAiFixture","options","forceSameTabNavigation","waitForNetworkIdleTimeout","DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT","waitForNavigationTimeout","DEFAULT_WAIT_FOR_NAVIGATION_TIMEOUT","cache","processTestCacheConfig","id","processCacheConfig","pageAgentMap","createOrReuseAgentForPage","page","opts","idForPage","uuid","testId","file","title","cacheConfig","PlaywrightAgent","dump","updateDumpAnnotation","generateAiFunction","use","aiActionType","agent","taskPrompt","args","Promise","resolve","reject","test","JSON","error","console","result","pageId","oldTempFilePath","rmSync","tempFileName","tempFilePath","join","tmpdir","writeFileSync","currentAnnotation","item","propsPage","finalCacheConfig","undefined","userCache"],"mappings":";;;;;;;;;AAmBA,MAAMA,YAAYC,SAAS;AAE3B,MAAMC,sBAAsB,CAACC;IAC3B,IAAIC;IACJ,IAAIC;IACJ,MAAMC,YAAY;WAAIH,SAAS,SAAS;KAAC;IAEzC,IAAIG,UAAU,MAAM,GAAG,GAAG;QACxBF,WAAWE,UAAU,KAAK,MAAM;QAChCD,YAAYC,UAAU,IAAI,CAAC;IAC7B,OAAO,IAAIA,AAAqB,MAArBA,UAAU,MAAM,EAAQ;QACjCD,YAAYC,SAAS,CAAC,EAAE;QACxBF,WAAW,GAAGC,WAAW;IAC3B,OAAO;QACLA,YAAY;QACZD,WAAW;IACb;IAEA,MAAMG,qBAAqB,GAAGF,YAAYF,SAAS,KAAK,GAAG,CAAC,QAAQ,EAAEA,SAAS,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI;IAE9F,OAAO;QACL,MAAMC;QACN,IAAII,gCAAgC,GAAGJ,SAAS,CAAC,EAAEC,UAAU,CAAC,CAAC;QAC/D,OAAOG,gCAAgCD;IACzC;AACF;AAEA,MAAME,qBAAqB;AACpB,MAAMC,2BAA2B;AAGxC,MAAMC,gBAAgB,IAAIC;AAQnB,MAAMC,sBAAsB,CAACC;IAMlC,MAAM,EACJC,yBAAyB,IAAI,EAC7BC,4BAA4BC,qCAAqC,EACjEC,2BAA2BC,mCAAmC,EAC9DC,KAAK,EACN,GAAGN,WAAW,CAAC;IAGhB,MAAMO,yBAAyB,CAAClB;QAE9B,MAAM,EAAEmB,EAAE,EAAE,GAAGpB,oBAAoBC;QAGnC,OAAOoB,mBAAmBH,OAAgBE;IAC5C;IAEA,MAAME,eAA6D,CAAC;IACpE,MAAMC,4BAA4B,CAChCC,MACAvB,UACAwB;QAEA,IAAIC,YAAaF,IAAY,CAACjB,mBAAmB;QACjD,IAAI,CAACmB,WAAW;YACdA,YAAYC;YACXH,IAAY,CAACjB,mBAAmB,GAAGmB;YACpC,MAAM,EAAEE,MAAM,EAAE,GAAG3B;YACnB,MAAM,EAAE4B,IAAI,EAAEC,KAAK,EAAE,GAAG9B,oBAAoBC;YAC5C,MAAM8B,cAAcZ,uBAAuBlB;YAE3CqB,YAAY,CAACI,UAAU,GAAG,IAAIM,gBAAgBR,MAAM;gBAClD,QAAQ,CAAC,WAAW,EAAEI,OAAO,CAAC,EAAEF,WAAW;gBAC3Cb;gBACA,OAAOkB;gBACP,WAAWD;gBACX,kBAAkBD;gBAClB,gBAAgB;gBAChB,GAAGJ,IAAI;YACT;YAEAH,YAAY,CAACI,UAAU,CAAC,YAAY,GAAG,CAACO;gBACtCC,qBAAqBjC,UAAUgC,MAAMP;YACvC;YAEAF,KAAK,EAAE,CAAC,SAAS;gBACf1B,UAAU;gBAKVW,cAAc,MAAM,CAACiB;gBACrBJ,YAAY,CAACI,UAAU,EAAE;gBACzB,OAAOJ,YAAY,CAACI,UAAU;YAChC;QACF;QAEA,OAAOJ,YAAY,CAACI,UAAU;IAChC;IAEA,eAAeS,mBAAmBvB,OA8BjC;QACC,MAAM,EAAEY,IAAI,EAAEvB,QAAQ,EAAEmC,GAAG,EAAEC,YAAY,EAAE,GAAGzB;QAC9C,MAAM0B,QAAQf,0BAA0BC,MAAMvB,UAAU;YACtDe;YACAF;QACF;QAEA,MAAMsB,IAAI,OAAOG,YAAoB,GAAGC,OAC/B,IAAIC,QAAQ,CAACC,SAASC;gBAC3BC,UAAAA,IAAS,CAAC,CAAC,GAAG,EAAEP,aAAa,GAAG,EAAEQ,KAAK,SAAS,CAACN,aAAa,EAAE;oBAC9D,IAAI;wBACFzC,UACE,CAAC,4BAA4B,EAAEgB,2BAA2B;wBAE5D,MAAMwB,MAAM,kBAAkB,CAACxB;oBACjC,EAAE,OAAOgC,OAAO;wBACdC,QAAQ,IAAI,CACV;oBAEJ;oBACA,IAAI;wBAKF,MAAMC,SAAS,MAAOV,KAAK,CAACD,aAAa,CAAiB,IAAI,CAC5DC,OACAC,eAAeC;wBACjBE,QAAQM;oBACV,EAAE,OAAOF,OAAO;wBACdH,OAAOG;oBACT;gBACF;YACF;IAEJ;IAEA,MAAMZ,uBAAuB,CAC3BU,MACAX,MACAgB;QAGA,MAAMC,kBAAkBzC,cAAc,GAAG,CAACwC;QAC1C,IAAIC,iBACF,IAAI;YACFC,OAAOD,iBAAiB;gBAAE,OAAO;YAAK;YACtCC,OAAO,GAAGD,gBAAgB,YAAY,CAAC,EAAE;gBACvC,OAAO;gBACP,WAAW;YACb;YACAC,OAAO,GAAGD,gBAAgB,iBAAiB,CAAC,EAAE;gBAAE,OAAO;YAAK;QAC9D,EAAE,OAAOJ,OAAO,CAEhB;QAIF,MAAMM,eAAe,CAAC,cAAc,EAAER,KAAK,MAAM,IAAIjB,OAAO,CAAC,EAAEsB,OAAO,KAAK,CAAC;QAC5E,MAAMI,eAAeC,KAAKC,UAAUH;QAIpC,IAAI;YACF,MAAMd,QAAQhB,YAAY,CAAC2B,OAAO;YAClC,IAAIX,OAAO;gBACTA,MAAM,IAAI,CAAC,gBAAgB,CAACe;gBAC5BvD,UAAU,CAAC,qCAAqC,EAAEuD,cAAc;YAClE,OAAO;gBAELG,cAAcH,cAAcpB,MAAM;gBAClCnC,UAAU,CAAC,2BAA2B,EAAEuD,cAAc;YACxD;YAGA5C,cAAc,GAAG,CAACwC,QAAQI;YAG1B,MAAMI,oBAAoBb,KAAK,WAAW,CAAC,IAAI,CAAC,CAACc,OACxCA,KAAK,IAAI,KAAKlD;YAEvB,IAAIiD,mBAEFA,kBAAkB,WAAW,GAAGJ;iBAEhCT,KAAK,WAAW,CAAC,IAAI,CAAC;gBACpB,MAAMpC;gBACN,aAAa6C;YACf;QAEJ,EAAE,OAAOP,OAAO;YAGdhD,UACE,CAAC,2BAA2B,EAAEuD,aAAa,sBAAsB,CAAC,EAClEP;QAEJ;IACF;IAEA,OAAO;QACL,cAAc,OACZ,EAAEtB,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMmC,IACJ,OACEuB,WACAlC;gBAEA,MAAMM,cAAcZ,uBAAuBlB;gBAK3C,IAAI2D,mBAAmB7B;gBACvB,IAAIN,MAAM,UAAUoC,QAAW;oBAC7B,MAAMC,YAAYrC,KAAK,KAAK;oBAC5B,IAAIqC,AAAc,UAAdA,WACFF,mBAAmB;yBACd,IAAIE,AAAc,SAAdA,WAAoB;wBAE7B,MAAM,EAAE1C,EAAE,EAAE,GAAGpB,oBAAoBC;wBACnC2D,mBAAmB;4BAAExC;wBAAG;oBAC1B,OAAO,IAAI,AAAqB,YAArB,OAAO0C,WAChB,IAAKA,UAAU,EAAE,EAKfF,mBAAmBE;yBALF;wBAEjB,MAAM,EAAE1C,EAAE,EAAE,GAAGpB,oBAAoBC;wBACnC2D,mBAAmB;4BAAE,GAAGE,SAAS;4BAAE1C;wBAAG;oBACxC;gBAIJ;gBAEA,MAAMkB,QAAQf,0BAA0BoC,aAAanC,MAAMvB,UAAU;oBACnEe;oBACAF;oBACA,OAAO8C;oBACP,GAAGnC,IAAI;gBACT;gBACA,OAAOa;YACT;QAEJ;QACA,IAAI,OACF,EAAEd,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,OAAO,OACL,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QAIA,UAAU,OACR,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,OAAO,OACL,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,cAAc,OACZ,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,eAAe,OACb,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,SAAS,OACP,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,SAAS,OACP,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,iBAAiB,OACf,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,UAAU,OACR,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,SAAS,OACP,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,UAAU,OACR,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,WAAW,OACT,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,UAAU,OACR,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,UAAU,OACR,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,UAAU,OACR,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,WAAW,OACT,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,OAAO,OACL,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,SAAS,OACP,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,oBAAoB,OAClB,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,oBAAoB,OAClB,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,gBAAgB,OACd,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,eAAe,OACb,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,mBAAmB,OACjB,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;QACA,qBAAqB,OACnB,EAAEZ,IAAI,EAAkC,EACxCY,KACAnC;YAEA,MAAMkC,mBAAmB;gBACvBX;gBACAvB;gBACAmC;gBACA,cAAc;YAChB;QACF;IACF;AACF"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Agent } from "@midscene/core/agent";
|
|
2
|
+
import { WebPage } from "./page.mjs";
|
|
3
|
+
import { PlaywrightAiFixture } from "./ai-fixture.mjs";
|
|
4
|
+
import { overrideAIConfig } from "@midscene/shared/env";
|
|
5
|
+
import { getDebug } from "@midscene/shared/logger";
|
|
6
|
+
import semver from "semver";
|
|
7
|
+
import { 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
|
+
async waitForNetworkIdle(timeout = 1000) {
|
|
21
|
+
await this.page.underlyingPage.waitForLoadState('networkidle', {
|
|
22
|
+
timeout
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
constructor(page, opts){
|
|
26
|
+
if (!page) throw new Error('[midscene] PlaywrightAgent requires a valid Playwright page instance. Please make sure to pass a valid page object.');
|
|
27
|
+
const webPage = new WebPage(page, opts);
|
|
28
|
+
super(webPage, opts);
|
|
29
|
+
const { forceSameTabNavigation = true, forceChromeSelectRendering } = opts ?? {};
|
|
30
|
+
if (forceSameTabNavigation) forceClosePopup(page, debug);
|
|
31
|
+
if (forceChromeSelectRendering) {
|
|
32
|
+
const playwrightVersion = getPlaywrightVersion();
|
|
33
|
+
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.`);
|
|
34
|
+
base_page_mjs_forceChromeSelectRendering(page);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export { PlaywrightAgent, PlaywrightAiFixture, WebPage as PlaywrightWebPage, overrideAIConfig };
|
|
39
|
+
|
|
40
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playwright/index.mjs","sources":["../../../src/playwright/index.ts"],"sourcesContent":["import { Agent as PageAgent } from '@midscene/core/agent';\nimport type { Page as PlaywrightPage } from 'playwright';\nimport { WebPage as PlaywrightWebPage } from './page';\n\nexport type { PlayWrightAiFixtureType } from './ai-fixture';\nexport { PlaywrightAiFixture } from './ai-fixture';\nexport { overrideAIConfig } from '@midscene/shared/env';\nexport { WebPage as PlaywrightWebPage } from './page';\nexport type { WebPageAgentOpt } from '@/web-element';\nimport type { WebPageAgentOpt } from '@/web-element';\nimport { getDebug } from '@midscene/shared/logger';\nimport semver from 'semver';\nimport {\n forceChromeSelectRendering as applyChromeSelectRendering,\n forceClosePopup,\n} from '../puppeteer/base-page';\nimport { getWebpackRequire } from '../utils';\n\nconst debug = getDebug('playwright:agent');\n\n/**\n * Get Playwright version from package.json\n */\nfunction getPlaywrightVersion(): string | null {\n try {\n const playwrightPkg = getWebpackRequire()('playwright/package.json');\n return playwrightPkg.version || null;\n } catch (error) {\n console.error('[midscene:error] Failed to get Playwright version', error);\n return null;\n }\n}\n\nexport class PlaywrightAgent extends PageAgent<PlaywrightWebPage> {\n constructor(page: PlaywrightPage, opts?: WebPageAgentOpt) {\n if (!page) {\n throw new Error(\n '[midscene] PlaywrightAgent requires a valid Playwright page instance. Please make sure to pass a valid page object.',\n );\n }\n const webPage = new PlaywrightWebPage(page, opts);\n super(webPage, opts);\n\n const { forceSameTabNavigation = true, forceChromeSelectRendering } =\n opts ?? {};\n\n if (forceSameTabNavigation) {\n forceClosePopup(page, debug);\n }\n\n if (forceChromeSelectRendering) {\n // Check Playwright version requirement (>= 1.52)\n const playwrightVersion = getPlaywrightVersion();\n if (playwrightVersion && !semver.gte(playwrightVersion, '1.52.0')) {\n console.warn(\n `[midscene:error] forceChromeSelectRendering requires Playwright >= 1.52.0, but current version is ${playwrightVersion}. This feature may not work correctly.`,\n );\n }\n applyChromeSelectRendering(page);\n }\n }\n\n async waitForNetworkIdle(timeout = 1000) {\n await this.page.underlyingPage.waitForLoadState('networkidle', { timeout });\n }\n}\n"],"names":["debug","getDebug","getPlaywrightVersion","playwrightPkg","getWebpackRequire","error","console","PlaywrightAgent","PageAgent","timeout","page","opts","Error","webPage","PlaywrightWebPage","forceSameTabNavigation","forceChromeSelectRendering","forceClosePopup","playwrightVersion","semver","applyChromeSelectRendering"],"mappings":";;;;;;;;AAkBA,MAAMA,QAAQC,SAAS;AAKvB,SAASC;IACP,IAAI;QACF,MAAMC,gBAAgBC,oBAAoB;QAC1C,OAAOD,cAAc,OAAO,IAAI;IAClC,EAAE,OAAOE,OAAO;QACdC,QAAQ,KAAK,CAAC,qDAAqDD;QACnE,OAAO;IACT;AACF;AAEO,MAAME,wBAAwBC;IA6BnC,MAAM,mBAAmBC,UAAU,IAAI,EAAE;QACvC,MAAM,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,gBAAgB,CAAC,eAAe;YAAEA;QAAQ;IAC3E;IA9BA,YAAYC,IAAoB,EAAEC,IAAsB,CAAE;QACxD,IAAI,CAACD,MACH,MAAM,IAAIE,MACR;QAGJ,MAAMC,UAAU,IAAIC,QAAkBJ,MAAMC;QAC5C,KAAK,CAACE,SAASF;QAEf,MAAM,EAAEI,yBAAyB,IAAI,EAAEC,0BAA0B,EAAE,GACjEL,QAAQ,CAAC;QAEX,IAAII,wBACFE,gBAAgBP,MAAMV;QAGxB,IAAIgB,4BAA4B;YAE9B,MAAME,oBAAoBhB;YAC1B,IAAIgB,qBAAqB,CAACC,OAAO,GAAG,CAACD,mBAAmB,WACtDZ,QAAQ,IAAI,CACV,CAAC,kGAAkG,EAAEY,kBAAkB,sCAAsC,CAAC;YAGlKE,yCAA2BV;QAC7B;IACF;AAKF"}
|
|
@@ -0,0 +1,44 @@
|
|
|
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 };
|
|
43
|
+
|
|
44
|
+
//# sourceMappingURL=page.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playwright/page.mjs","sources":["../../../src/playwright/page.ts"],"sourcesContent":["import type { FileChooser, Page as PlaywrightPageType } from 'playwright';\nimport { Page as BasePage } from '../puppeteer/base-page';\nimport type { WebPageOpt } from '../web-element';\n\nexport class WebPage extends BasePage<'playwright', PlaywrightPageType> {\n private playwrightFileChooserHandler?: (\n chooser: FileChooser,\n ) => Promise<void>;\n\n constructor(page: PlaywrightPageType, opts?: WebPageOpt) {\n super(page, 'playwright', opts);\n }\n\n async registerFileChooserListener(\n handler: (\n chooser: import('@midscene/core/device').FileChooserHandler,\n ) => Promise<void>,\n ): Promise<{ dispose: () => void; getError: () => Error | undefined }> {\n const page = this.underlyingPage as PlaywrightPageType;\n\n let capturedError: Error | undefined;\n\n this.playwrightFileChooserHandler = async (chooser: FileChooser) => {\n try {\n await handler({\n accept: async (files: string[]) => {\n await chooser.setFiles(files);\n },\n });\n } catch (error) {\n capturedError = error as Error;\n }\n };\n\n page.on('filechooser', this.playwrightFileChooserHandler);\n\n return {\n dispose: () => {\n if (this.playwrightFileChooserHandler) {\n page.off('filechooser', this.playwrightFileChooserHandler);\n this.playwrightFileChooserHandler = undefined;\n }\n },\n getError: () => capturedError,\n };\n }\n}\n"],"names":["WebPage","BasePage","handler","page","capturedError","chooser","files","error","undefined","opts"],"mappings":";;;;;;;;;;;AAIO,MAAMA,gBAAgBC;IAS3B,MAAM,4BACJC,OAEkB,EACmD;QACrE,MAAMC,OAAO,IAAI,CAAC,cAAc;QAEhC,IAAIC;QAEJ,IAAI,CAAC,4BAA4B,GAAG,OAAOC;YACzC,IAAI;gBACF,MAAMH,QAAQ;oBACZ,QAAQ,OAAOI;wBACb,MAAMD,QAAQ,QAAQ,CAACC;oBACzB;gBACF;YACF,EAAE,OAAOC,OAAO;gBACdH,gBAAgBG;YAClB;QACF;QAEAJ,KAAK,EAAE,CAAC,eAAe,IAAI,CAAC,4BAA4B;QAExD,OAAO;YACL,SAAS;gBACP,IAAI,IAAI,CAAC,4BAA4B,EAAE;oBACrCA,KAAK,GAAG,CAAC,eAAe,IAAI,CAAC,4BAA4B;oBACzD,IAAI,CAAC,4BAA4B,GAAGK;gBACtC;YACF;YACA,UAAU,IAAMJ;QAClB;IACF;IApCA,YAAYD,IAAwB,EAAEM,IAAiB,CAAE;QACvD,KAAK,CAACN,MAAM,cAAcM,OAL5B,uBAAQ,gCAAR;IAMA;AAmCF"}
|