@one2x/playwright 1.57.0-alpha.13 → 1.57.0-alpha.15
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/lib/mcp/browser/browserContextFactory.js +4 -9
- package/lib/mcp/browser/config.js +1 -2
- package/lib/mcp/browser/tools/mouse.js +109 -113
- package/lib/mcp/browser/tools/screenshot.js +1 -1
- package/lib/mcp/browser/tools/snapshot.js +36 -56
- package/lib/mcp/sdk/http.js +2 -4
- package/package.json +2 -2
|
@@ -63,9 +63,8 @@ class BaseContextFactory {
|
|
|
63
63
|
}
|
|
64
64
|
_obtainBrowser(clientInfo) {
|
|
65
65
|
const key = this._calcFingerprint();
|
|
66
|
-
if (BaseContextFactory._cache.has(key))
|
|
66
|
+
if (BaseContextFactory._cache.has(key))
|
|
67
67
|
return BaseContextFactory._cache.get(key);
|
|
68
|
-
}
|
|
69
68
|
(0, import_log.testDebug)(`obtain browser (${this._logName})`);
|
|
70
69
|
const browserPromise = this._doObtainBrowser(clientInfo);
|
|
71
70
|
void browserPromise.then((browser) => {
|
|
@@ -292,7 +291,6 @@ class SharedContextFactory {
|
|
|
292
291
|
static create(config) {
|
|
293
292
|
if (SharedContextFactory._instance)
|
|
294
293
|
return SharedContextFactory._instance;
|
|
295
|
-
;
|
|
296
294
|
const baseConfig = { ...config, sharedBrowserContext: false };
|
|
297
295
|
const baseFactory = contextFactory(baseConfig);
|
|
298
296
|
SharedContextFactory._instance = new SharedContextFactory(baseFactory);
|
|
@@ -335,15 +333,12 @@ async function computeTracesDir(config, clientInfo) {
|
|
|
335
333
|
return await (0, import_config.outputFile)(config, clientInfo, `traces`, { origin: "code", reason: "Collecting trace" });
|
|
336
334
|
}
|
|
337
335
|
function stableStringify(obj) {
|
|
338
|
-
if (obj === null || obj === void 0)
|
|
336
|
+
if (obj === null || obj === void 0)
|
|
339
337
|
return String(obj);
|
|
340
|
-
|
|
341
|
-
if (typeof obj !== "object") {
|
|
338
|
+
if (typeof obj !== "object")
|
|
342
339
|
return JSON.stringify(obj);
|
|
343
|
-
|
|
344
|
-
if (Array.isArray(obj)) {
|
|
340
|
+
if (Array.isArray(obj))
|
|
345
341
|
return "[" + obj.map((item) => stableStringify(item)).join(",") + "]";
|
|
346
|
-
}
|
|
347
342
|
const sortedKeys = Object.keys(obj).sort();
|
|
348
343
|
const pairs = sortedKeys.map((key) => {
|
|
349
344
|
return JSON.stringify(key) + ":" + stableStringify(obj[key]);
|
|
@@ -397,9 +397,8 @@ function configFromURLParams(url) {
|
|
|
397
397
|
const viewportSize = getParam("viewport-size");
|
|
398
398
|
if (viewportSize)
|
|
399
399
|
options.viewportSize = resolutionParser("--viewport-size", viewportSize);
|
|
400
|
-
if (!Object.values(options).some((v) => v !== void 0))
|
|
400
|
+
if (!Object.values(options).some((v) => v !== void 0))
|
|
401
401
|
return {};
|
|
402
|
-
}
|
|
403
402
|
return configFromCLIOptions(options);
|
|
404
403
|
}
|
|
405
404
|
function queryToBoolean(value) {
|
|
@@ -146,125 +146,117 @@ const inspectAtXY = (0, import_tool.defineTabTool)({
|
|
|
146
146
|
type: "readOnly"
|
|
147
147
|
},
|
|
148
148
|
handle: async (tab, params, response) => {
|
|
149
|
-
const
|
|
149
|
+
const elementHandlesData = await tab.page.evaluateHandle(({ x, y }) => {
|
|
150
150
|
const allElements = document.elementsFromPoint(x, y);
|
|
151
151
|
const meaningfulElements = allElements.filter((element, index) => {
|
|
152
152
|
for (let i = 0; i < allElements.length; i++) {
|
|
153
|
-
if (i !== index && element.contains(allElements[i]))
|
|
153
|
+
if (i !== index && element.contains(allElements[i]))
|
|
154
154
|
return false;
|
|
155
|
-
}
|
|
156
155
|
}
|
|
157
156
|
return true;
|
|
158
157
|
});
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const selfClosing = ["img", "input", "br", "hr", "meta", "link"];
|
|
183
|
-
if (selfClosing.includes(tag)) {
|
|
184
|
-
return `<${tag}${attrs} />`;
|
|
185
|
-
}
|
|
186
|
-
if (node.childNodes.length === 0) {
|
|
187
|
-
const text = node.element.textContent?.trim() || "";
|
|
188
|
-
if (text && text.length <= 50) {
|
|
189
|
-
return openTag + text + closeTag;
|
|
190
|
-
} else if (text) {
|
|
191
|
-
return openTag + text.substring(0, 47) + "..." + closeTag;
|
|
158
|
+
return meaningfulElements;
|
|
159
|
+
}, params);
|
|
160
|
+
const elementHandlesArray = await elementHandlesData.evaluateHandle((arr) => arr);
|
|
161
|
+
const elementHandles = [];
|
|
162
|
+
const length = await elementHandlesArray.evaluate((arr) => arr.length);
|
|
163
|
+
for (let i = 0; i < length; i++) {
|
|
164
|
+
const handle = await elementHandlesArray.evaluateHandle((arr, index) => arr[index], i);
|
|
165
|
+
const element = handle.asElement();
|
|
166
|
+
if (element)
|
|
167
|
+
elementHandles.push(element);
|
|
168
|
+
}
|
|
169
|
+
const elementsData = [];
|
|
170
|
+
for (const elementHandle of elementHandles) {
|
|
171
|
+
const pathToRoot = await elementHandle.getPathWithRefs().catch(() => "");
|
|
172
|
+
const elementData = await elementHandle.evaluate((element) => {
|
|
173
|
+
const computedStyle = window.getComputedStyle(element);
|
|
174
|
+
function serializeAttributes(el) {
|
|
175
|
+
const essentialAttrs = ["id", "class", "type", "name", "role", "aria-label"];
|
|
176
|
+
const attrs = [];
|
|
177
|
+
for (const attrName of essentialAttrs) {
|
|
178
|
+
const value = el.getAttribute(attrName);
|
|
179
|
+
if (value)
|
|
180
|
+
attrs.push(` ${attrName}="${value}"`);
|
|
192
181
|
}
|
|
193
|
-
return
|
|
182
|
+
return attrs.join("");
|
|
194
183
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
184
|
+
function buildTree(el) {
|
|
185
|
+
return {
|
|
186
|
+
element: el,
|
|
187
|
+
expanded: false,
|
|
188
|
+
childNodes: Array.from(el.children).map((child) => buildTree(child))
|
|
189
|
+
};
|
|
198
190
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
if (
|
|
208
|
-
|
|
191
|
+
function renderTree(node) {
|
|
192
|
+
const tag = node.element.tagName.toLowerCase();
|
|
193
|
+
const attrs = serializeAttributes(node.element);
|
|
194
|
+
const openTag = `<${tag}${attrs}>`;
|
|
195
|
+
const closeTag = `</${tag}>`;
|
|
196
|
+
const selfClosing = ["img", "input", "br", "hr", "meta", "link"];
|
|
197
|
+
if (selfClosing.includes(tag))
|
|
198
|
+
return `<${tag}${attrs} />`;
|
|
199
|
+
if (node.childNodes.length === 0) {
|
|
200
|
+
const text = node.element.textContent?.trim() || "";
|
|
201
|
+
if (text && text.length <= 50)
|
|
202
|
+
return openTag + text + closeTag;
|
|
203
|
+
else if (text)
|
|
204
|
+
return openTag + text.substring(0, 47) + "..." + closeTag;
|
|
205
|
+
return openTag + closeTag;
|
|
209
206
|
}
|
|
210
|
-
if (
|
|
211
|
-
|
|
207
|
+
if (!node.expanded) {
|
|
208
|
+
const count = node.element.children.length;
|
|
209
|
+
return `${openTag}<!-- ${count} child element${count !== 1 ? "s" : ""} removed -->${closeTag}`;
|
|
212
210
|
}
|
|
211
|
+
const childrenHtml = node.childNodes.map((child) => renderTree(child)).join("");
|
|
212
|
+
return openTag + childrenHtml + closeTag;
|
|
213
213
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
const expandable = getExpandableNodes(root);
|
|
224
|
-
if (expandable.length === 0) {
|
|
225
|
-
break;
|
|
214
|
+
function getExpandableNodes(node) {
|
|
215
|
+
const queue = [node];
|
|
216
|
+
const expandable = [];
|
|
217
|
+
while (queue.length > 0) {
|
|
218
|
+
const current = queue.shift();
|
|
219
|
+
if (current.childNodes.length > 0 && !current.expanded)
|
|
220
|
+
expandable.push(current);
|
|
221
|
+
if (current.expanded)
|
|
222
|
+
queue.push(...current.childNodes);
|
|
226
223
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
224
|
+
return expandable;
|
|
225
|
+
}
|
|
226
|
+
function truncateIterativeDeepening(el, maxBudget) {
|
|
227
|
+
if (el.outerHTML.length <= maxBudget)
|
|
228
|
+
return el.outerHTML;
|
|
229
|
+
const root = buildTree(el);
|
|
230
|
+
let currentHtml = renderTree(root);
|
|
231
|
+
while (currentHtml.length < maxBudget) {
|
|
232
|
+
const expandable = getExpandableNodes(root);
|
|
233
|
+
if (expandable.length === 0)
|
|
234
234
|
break;
|
|
235
|
-
|
|
236
|
-
|
|
235
|
+
let expanded = false;
|
|
236
|
+
for (const node of expandable) {
|
|
237
|
+
node.expanded = true;
|
|
238
|
+
const newHtml = renderTree(root);
|
|
239
|
+
if (newHtml.length <= maxBudget) {
|
|
240
|
+
currentHtml = newHtml;
|
|
241
|
+
expanded = true;
|
|
242
|
+
break;
|
|
243
|
+
} else {
|
|
244
|
+
node.expanded = false;
|
|
245
|
+
}
|
|
237
246
|
}
|
|
247
|
+
if (!expanded)
|
|
248
|
+
break;
|
|
238
249
|
}
|
|
239
|
-
|
|
240
|
-
break;
|
|
241
|
-
}
|
|
250
|
+
return currentHtml;
|
|
242
251
|
}
|
|
243
|
-
return currentHtml;
|
|
244
|
-
}
|
|
245
|
-
return meaningfulElements.map((element) => {
|
|
246
|
-
const computedStyle = window.getComputedStyle(element);
|
|
247
252
|
const ariaRef = element._ariaRef;
|
|
248
|
-
const path = [];
|
|
249
|
-
let current = element;
|
|
250
|
-
while (current && current !== document.documentElement) {
|
|
251
|
-
const ref = current._ariaRef;
|
|
252
|
-
const tagName = current.tagName?.toLowerCase() || "unknown";
|
|
253
|
-
let nodeInfo = tagName;
|
|
254
|
-
if (ref?.ref) {
|
|
255
|
-
nodeInfo += ` [${ref.ref}]`;
|
|
256
|
-
if (ref.role) nodeInfo += ` [${ref.role}]`;
|
|
257
|
-
}
|
|
258
|
-
path.unshift(nodeInfo);
|
|
259
|
-
current = current.parentElement;
|
|
260
|
-
}
|
|
261
253
|
return {
|
|
262
254
|
ref: ariaRef?.ref || null,
|
|
263
255
|
role: ariaRef?.role || null,
|
|
264
256
|
element: ariaRef?.name || element.tagName.toLowerCase(),
|
|
265
|
-
pathToRoot: path.join(" > "),
|
|
266
257
|
truncatedHTML: truncateIterativeDeepening(element, 300),
|
|
267
258
|
tagName: element.tagName.toLowerCase(),
|
|
259
|
+
bounds: element.getBoundingClientRect(),
|
|
268
260
|
computedStyles: {
|
|
269
261
|
display: computedStyle.display,
|
|
270
262
|
visibility: computedStyle.visibility,
|
|
@@ -286,7 +278,11 @@ const inspectAtXY = (0, import_tool.defineTabTool)({
|
|
|
286
278
|
readonly: element.readOnly || void 0
|
|
287
279
|
};
|
|
288
280
|
});
|
|
289
|
-
|
|
281
|
+
elementsData.push({
|
|
282
|
+
...elementData,
|
|
283
|
+
pathToRoot
|
|
284
|
+
});
|
|
285
|
+
}
|
|
290
286
|
let suggestedSelectors = "";
|
|
291
287
|
if (elementsData.length > 0 && elementsData[0].ref) {
|
|
292
288
|
try {
|
|
@@ -300,11 +296,10 @@ const inspectAtXY = (0, import_tool.defineTabTool)({
|
|
|
300
296
|
}
|
|
301
297
|
}
|
|
302
298
|
let result = "";
|
|
303
|
-
if (elementsData.length > 1)
|
|
299
|
+
if (elementsData.length > 1)
|
|
304
300
|
result += `\u26A0\uFE0F Warning: Found ${elementsData.length} elements at (${params.x}, ${params.y})
|
|
305
301
|
|
|
306
302
|
`;
|
|
307
|
-
}
|
|
308
303
|
elementsData.forEach((elementInfo, index) => {
|
|
309
304
|
const isTopmost = index === 0;
|
|
310
305
|
const header = isTopmost ? `**Element at (${params.x}, ${params.y}) - Topmost (will receive clicks):**` : `**Element ${index + 1} at (${params.x}, ${params.y}) - Below topmost:**`;
|
|
@@ -313,16 +308,26 @@ const inspectAtXY = (0, import_tool.defineTabTool)({
|
|
|
313
308
|
`;
|
|
314
309
|
result += `- Path to root: ${elementInfo.pathToRoot}
|
|
315
310
|
`;
|
|
316
|
-
if (isTopmost && suggestedSelectors)
|
|
311
|
+
if (isTopmost && suggestedSelectors)
|
|
317
312
|
result += `- Suggested Playwright Selector:
|
|
318
313
|
${suggestedSelectors}
|
|
319
314
|
`;
|
|
320
|
-
}
|
|
321
315
|
result += `
|
|
322
316
|
**HTML (truncated to 300 chars):**
|
|
323
317
|
\`\`\`html
|
|
324
318
|
${elementInfo.truncatedHTML}
|
|
325
319
|
\`\`\`
|
|
320
|
+
`;
|
|
321
|
+
result += `
|
|
322
|
+
**Bounding Box (viewport coordinates):**
|
|
323
|
+
`;
|
|
324
|
+
result += `- x: ${elementInfo.bounds.x}
|
|
325
|
+
`;
|
|
326
|
+
result += `- y: ${elementInfo.bounds.y}
|
|
327
|
+
`;
|
|
328
|
+
result += `- width: ${elementInfo.bounds.width}
|
|
329
|
+
`;
|
|
330
|
+
result += `- height: ${elementInfo.bounds.height}
|
|
326
331
|
`;
|
|
327
332
|
result += `
|
|
328
333
|
**Key Computed Styles:**
|
|
@@ -336,10 +341,6 @@ ${elementInfo.truncatedHTML}
|
|
|
336
341
|
result += `- Position: ${elementInfo.computedStyles.position}
|
|
337
342
|
`;
|
|
338
343
|
result += `- Z-Index: ${elementInfo.computedStyles.zIndex}
|
|
339
|
-
`;
|
|
340
|
-
result += `- Width: ${elementInfo.computedStyles.width}
|
|
341
|
-
`;
|
|
342
|
-
result += `- Height: ${elementInfo.computedStyles.height}
|
|
343
344
|
`;
|
|
344
345
|
result += `- Background Color: ${elementInfo.computedStyles.backgroundColor}
|
|
345
346
|
`;
|
|
@@ -354,25 +355,20 @@ ${elementInfo.truncatedHTML}
|
|
|
354
355
|
`;
|
|
355
356
|
result += `- Inner Text: "${elementInfo.innerText}"
|
|
356
357
|
`;
|
|
357
|
-
if (elementInfo.value !== void 0)
|
|
358
|
+
if (elementInfo.value !== void 0)
|
|
358
359
|
result += `- Value: "${elementInfo.value}"
|
|
359
360
|
`;
|
|
360
|
-
|
|
361
|
-
if (elementInfo.checked !== void 0) {
|
|
361
|
+
if (elementInfo.checked !== void 0)
|
|
362
362
|
result += `- Checked: ${elementInfo.checked}
|
|
363
363
|
`;
|
|
364
|
-
|
|
365
|
-
if (elementInfo.disabled !== void 0) {
|
|
364
|
+
if (elementInfo.disabled !== void 0)
|
|
366
365
|
result += `- Disabled: ${elementInfo.disabled}
|
|
367
366
|
`;
|
|
368
|
-
|
|
369
|
-
if (elementInfo.readonly !== void 0) {
|
|
367
|
+
if (elementInfo.readonly !== void 0)
|
|
370
368
|
result += `- Read Only: ${elementInfo.readonly}
|
|
371
369
|
`;
|
|
372
|
-
|
|
373
|
-
if (index < elementsData.length - 1) {
|
|
370
|
+
if (index < elementsData.length - 1)
|
|
374
371
|
result += "\n---\n\n";
|
|
375
|
-
}
|
|
376
372
|
});
|
|
377
373
|
response.addResult(result);
|
|
378
374
|
}
|
|
@@ -51,7 +51,7 @@ const screenshot = (0, import_tool.defineTabTool)({
|
|
|
51
51
|
schema: {
|
|
52
52
|
name: "browser_take_screenshot",
|
|
53
53
|
title: "Take a screenshot",
|
|
54
|
-
description: `Take a screenshot of the current page. You can
|
|
54
|
+
description: `Take a screenshot of the current page. You can call tools ends with '_xy' based on the screenshot coordinates.`,
|
|
55
55
|
inputSchema: screenshotSchema,
|
|
56
56
|
type: "readOnly"
|
|
57
57
|
},
|
|
@@ -88,9 +88,8 @@ const click = (0, import_tool.defineTabTool)({
|
|
|
88
88
|
options
|
|
89
89
|
);
|
|
90
90
|
});
|
|
91
|
-
if (!result)
|
|
91
|
+
if (!result)
|
|
92
92
|
return;
|
|
93
|
-
}
|
|
94
93
|
if (result.mode === "auto" && result.interceptorInfo) {
|
|
95
94
|
const actionName = params.doubleClick ? ".dblclick({ allowIntercept: true })" : ".click({ allowIntercept: true })";
|
|
96
95
|
(0, import_utils.addInterceptorWarning)(response, resolved, actionName, result.interceptorInfo);
|
|
@@ -133,9 +132,8 @@ const drag = (0, import_tool.defineTabTool)({
|
|
|
133
132
|
{}
|
|
134
133
|
);
|
|
135
134
|
});
|
|
136
|
-
if (!result)
|
|
135
|
+
if (!result)
|
|
137
136
|
return;
|
|
138
|
-
}
|
|
139
137
|
if (result.mode === "auto" && result.interceptorInfo)
|
|
140
138
|
(0, import_utils.addInterceptorWarning)(response, start.resolved, ".dragTo(target, { allowIntercept: true })", result.interceptorInfo);
|
|
141
139
|
const needsAllowIntercept = result.mode === "auto" && result.interceptorInfo || result.mode === "always";
|
|
@@ -163,9 +161,8 @@ const hover = (0, import_tool.defineTabTool)({
|
|
|
163
161
|
{}
|
|
164
162
|
);
|
|
165
163
|
});
|
|
166
|
-
if (!result)
|
|
164
|
+
if (!result)
|
|
167
165
|
return;
|
|
168
|
-
}
|
|
169
166
|
if (result.mode === "auto" && result.interceptorInfo)
|
|
170
167
|
(0, import_utils.addInterceptorWarning)(response, resolved, ".hover({ allowIntercept: true })", result.interceptorInfo);
|
|
171
168
|
const needsAllowIntercept = result.mode === "auto" && result.interceptorInfo || result.mode === "always";
|
|
@@ -226,31 +223,19 @@ const elementInspect = (0, import_tool.defineTool)({
|
|
|
226
223
|
let elementDetails;
|
|
227
224
|
const suggestedSelectors = (await (0, import_utils.generateLocators)(locator)).map((s) => `\`page.${s}\``).join("\n");
|
|
228
225
|
try {
|
|
226
|
+
const elementHandle = await locator.elementHandle();
|
|
227
|
+
if (!elementHandle)
|
|
228
|
+
throw new Error("Element not found");
|
|
229
|
+
const pathToRoot = await elementHandle.getPathWithRefs();
|
|
229
230
|
elementDetails = await locator.evaluate((element) => {
|
|
230
231
|
const computedStyle = window.getComputedStyle(element);
|
|
231
|
-
const path = [];
|
|
232
|
-
let current = element;
|
|
233
|
-
while (current && current !== document.documentElement) {
|
|
234
|
-
const ariaRef = current._ariaRef;
|
|
235
|
-
const tagName = current.tagName?.toLowerCase() || "unknown";
|
|
236
|
-
let nodeInfo = tagName;
|
|
237
|
-
if (ariaRef?.ref) {
|
|
238
|
-
nodeInfo += ` [${ariaRef.ref}]`;
|
|
239
|
-
if (ariaRef.role) {
|
|
240
|
-
nodeInfo += ` [${ariaRef.role}]`;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
path.unshift(nodeInfo);
|
|
244
|
-
current = current.parentElement;
|
|
245
|
-
}
|
|
246
232
|
function serializeAttributes(el) {
|
|
247
233
|
const essentialAttrs = ["id", "class", "type", "name", "role", "aria-label"];
|
|
248
234
|
const attrs = [];
|
|
249
235
|
for (const attrName of essentialAttrs) {
|
|
250
236
|
const value = el.getAttribute(attrName);
|
|
251
|
-
if (value)
|
|
237
|
+
if (value)
|
|
252
238
|
attrs.push(` ${attrName}="${value}"`);
|
|
253
|
-
}
|
|
254
239
|
}
|
|
255
240
|
return attrs.join("");
|
|
256
241
|
}
|
|
@@ -267,16 +252,14 @@ const elementInspect = (0, import_tool.defineTool)({
|
|
|
267
252
|
const openTag = `<${tag}${attrs}>`;
|
|
268
253
|
const closeTag = `</${tag}>`;
|
|
269
254
|
const selfClosing = ["img", "input", "br", "hr", "meta", "link"];
|
|
270
|
-
if (selfClosing.includes(tag))
|
|
255
|
+
if (selfClosing.includes(tag))
|
|
271
256
|
return `<${tag}${attrs} />`;
|
|
272
|
-
}
|
|
273
257
|
if (node.childNodes.length === 0) {
|
|
274
258
|
const text = node.element.textContent?.trim() || "";
|
|
275
|
-
if (text && text.length <= 50)
|
|
259
|
+
if (text && text.length <= 50)
|
|
276
260
|
return openTag + text + closeTag;
|
|
277
|
-
|
|
261
|
+
else if (text)
|
|
278
262
|
return openTag + text.substring(0, 47) + "..." + closeTag;
|
|
279
|
-
}
|
|
280
263
|
return openTag + closeTag;
|
|
281
264
|
}
|
|
282
265
|
if (!node.expanded) {
|
|
@@ -290,27 +273,23 @@ const elementInspect = (0, import_tool.defineTool)({
|
|
|
290
273
|
const queue = [node];
|
|
291
274
|
const expandable = [];
|
|
292
275
|
while (queue.length > 0) {
|
|
293
|
-
const
|
|
294
|
-
if (
|
|
295
|
-
expandable.push(
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
queue.push(...current2.childNodes);
|
|
299
|
-
}
|
|
276
|
+
const current = queue.shift();
|
|
277
|
+
if (current.childNodes.length > 0 && !current.expanded)
|
|
278
|
+
expandable.push(current);
|
|
279
|
+
if (current.expanded)
|
|
280
|
+
queue.push(...current.childNodes);
|
|
300
281
|
}
|
|
301
282
|
return expandable;
|
|
302
283
|
}
|
|
303
284
|
function truncateIterativeDeepening(el, maxBudget) {
|
|
304
|
-
if (el.outerHTML.length <= maxBudget)
|
|
285
|
+
if (el.outerHTML.length <= maxBudget)
|
|
305
286
|
return el.outerHTML;
|
|
306
|
-
}
|
|
307
287
|
const root = buildTree(el);
|
|
308
288
|
let currentHtml = renderTree(root);
|
|
309
289
|
while (currentHtml.length < maxBudget) {
|
|
310
290
|
const expandable = getExpandableNodes(root);
|
|
311
|
-
if (expandable.length === 0)
|
|
291
|
+
if (expandable.length === 0)
|
|
312
292
|
break;
|
|
313
|
-
}
|
|
314
293
|
let expanded = false;
|
|
315
294
|
for (const node of expandable) {
|
|
316
295
|
node.expanded = true;
|
|
@@ -323,16 +302,14 @@ const elementInspect = (0, import_tool.defineTool)({
|
|
|
323
302
|
node.expanded = false;
|
|
324
303
|
}
|
|
325
304
|
}
|
|
326
|
-
if (!expanded)
|
|
305
|
+
if (!expanded)
|
|
327
306
|
break;
|
|
328
|
-
}
|
|
329
307
|
}
|
|
330
308
|
return currentHtml;
|
|
331
309
|
}
|
|
332
310
|
return {
|
|
333
311
|
outerHTML: element.outerHTML,
|
|
334
312
|
truncatedHTML: truncateIterativeDeepening(element, 300),
|
|
335
|
-
pathToRoot: path.join(" > "),
|
|
336
313
|
tagName: element.tagName.toLowerCase(),
|
|
337
314
|
computedStyles: {
|
|
338
315
|
display: computedStyle.display,
|
|
@@ -354,10 +331,12 @@ const elementInspect = (0, import_tool.defineTool)({
|
|
|
354
331
|
zIndex: computedStyle.zIndex,
|
|
355
332
|
transform: computedStyle.transform
|
|
356
333
|
},
|
|
357
|
-
attributes:
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
334
|
+
attributes: (() => {
|
|
335
|
+
const attrs = {};
|
|
336
|
+
for (const attr of Array.from(element.attributes))
|
|
337
|
+
attrs[attr.name] = attr.value;
|
|
338
|
+
return attrs;
|
|
339
|
+
})(),
|
|
361
340
|
textContent: element.textContent?.trim() || "",
|
|
362
341
|
innerText: element.innerText?.trim() || "",
|
|
363
342
|
value: element.value || void 0,
|
|
@@ -367,6 +346,7 @@ const elementInspect = (0, import_tool.defineTool)({
|
|
|
367
346
|
bounds: element.getBoundingClientRect()
|
|
368
347
|
};
|
|
369
348
|
});
|
|
349
|
+
elementDetails.pathToRoot = pathToRoot;
|
|
370
350
|
} catch (error) {
|
|
371
351
|
response.addResult(`Error inspecting element "${params.element}": ${error instanceof Error ? error.message : String(error)}
|
|
372
352
|
|
|
@@ -389,13 +369,17 @@ ${suggestedSelectors}
|
|
|
389
369
|
${elementDetails.truncatedHTML}
|
|
390
370
|
\`\`\`
|
|
391
371
|
|
|
372
|
+
**Bounding Box (viewport coordinates):**
|
|
373
|
+
- x: ${elementDetails.bounds.x}
|
|
374
|
+
- y: ${elementDetails.bounds.y}
|
|
375
|
+
- width: ${elementDetails.bounds.width}
|
|
376
|
+
- height: ${elementDetails.bounds.height}
|
|
377
|
+
|
|
392
378
|
**Key Computed Styles:**
|
|
393
379
|
- Display: ${elementDetails.computedStyles.display}
|
|
394
380
|
- Visibility: ${elementDetails.computedStyles.visibility}
|
|
395
381
|
- Opacity: ${elementDetails.computedStyles.opacity}
|
|
396
382
|
- Position: ${elementDetails.computedStyles.position}
|
|
397
|
-
- Width: ${elementDetails.computedStyles.width}
|
|
398
|
-
- Height: ${elementDetails.computedStyles.height}
|
|
399
383
|
- Background Color: ${elementDetails.computedStyles.backgroundColor}
|
|
400
384
|
- Color: ${elementDetails.computedStyles.color}
|
|
401
385
|
|
|
@@ -403,22 +387,18 @@ ${elementDetails.truncatedHTML}
|
|
|
403
387
|
- Tag: ${elementDetails.tagName}
|
|
404
388
|
- Text Content: "${elementDetails.textContent}"
|
|
405
389
|
- Inner Text: "${elementDetails.innerText}"`;
|
|
406
|
-
if (elementDetails.value !== void 0)
|
|
390
|
+
if (elementDetails.value !== void 0)
|
|
407
391
|
result += `
|
|
408
392
|
- Value: "${elementDetails.value}"`;
|
|
409
|
-
|
|
410
|
-
if (elementDetails.checked !== void 0) {
|
|
393
|
+
if (elementDetails.checked !== void 0)
|
|
411
394
|
result += `
|
|
412
395
|
- Checked: ${elementDetails.checked}`;
|
|
413
|
-
|
|
414
|
-
if (elementDetails.disabled !== void 0) {
|
|
396
|
+
if (elementDetails.disabled !== void 0)
|
|
415
397
|
result += `
|
|
416
398
|
- Disabled: ${elementDetails.disabled}`;
|
|
417
|
-
|
|
418
|
-
if (elementDetails.readonly !== void 0) {
|
|
399
|
+
if (elementDetails.readonly !== void 0)
|
|
419
400
|
result += `
|
|
420
401
|
- Read Only: ${elementDetails.readonly}`;
|
|
421
|
-
}
|
|
422
402
|
response.addResult(result);
|
|
423
403
|
}
|
|
424
404
|
});
|
package/lib/mcp/sdk/http.js
CHANGED
|
@@ -241,16 +241,14 @@ function configFromInitRequest(body) {
|
|
|
241
241
|
for (const [snakeKey, camelKey] of Object.entries(keyMap)) {
|
|
242
242
|
if (playwrightConfig[snakeKey] !== void 0) {
|
|
243
243
|
let value = playwrightConfig[snakeKey];
|
|
244
|
-
if (snakeKey === "no_sandbox")
|
|
244
|
+
if (snakeKey === "no_sandbox")
|
|
245
245
|
value = !value;
|
|
246
|
-
}
|
|
247
246
|
options[camelKey] = value;
|
|
248
247
|
}
|
|
249
248
|
}
|
|
250
249
|
for (const key of Object.keys(playwrightConfig)) {
|
|
251
|
-
if (!key.includes("_") && options[key] === void 0)
|
|
250
|
+
if (!key.includes("_") && options[key] === void 0)
|
|
252
251
|
options[key] = playwrightConfig[key];
|
|
253
|
-
}
|
|
254
252
|
}
|
|
255
253
|
testDebug("Converted to CLIOptions:", options);
|
|
256
254
|
return (0, import_config.configFromCLIOptions)(options);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@one2x/playwright",
|
|
3
|
-
"version": "1.57.0-alpha.
|
|
3
|
+
"version": "1.57.0-alpha.15",
|
|
4
4
|
"description": "A high-level API to automate web browsers",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"license": "Apache-2.0",
|
|
66
66
|
"dependencies": {
|
|
67
67
|
"content-type": "^1.0.5",
|
|
68
|
-
"playwright-core": "npm:@one2x/playwright-core@1.57.0-alpha.
|
|
68
|
+
"playwright-core": "npm:@one2x/playwright-core@1.57.0-alpha.15",
|
|
69
69
|
"raw-body": "^2.5.2"
|
|
70
70
|
},
|
|
71
71
|
"optionalDependencies": {
|