mcp-web-inspector 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -16
- package/dist/toolHandler.js +21 -12
- package/dist/tools/browser/compareElementAlignment.d.ts +11 -0
- package/dist/tools/browser/compareElementAlignment.js +171 -0
- package/dist/tools/browser/inspectDom.js +7 -0
- package/dist/tools.d.ts +9 -27
- package/dist/tools.js +35 -30
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -449,15 +449,6 @@ Detailed visibility diagnostics showing exactly why elements are or aren't visib
|
|
|
449
449
|
- Detecting elements covered by modals or overlays
|
|
450
450
|
- Checking if elements are clipped by parent containers
|
|
451
451
|
|
|
452
|
-
#### `get_position`
|
|
453
|
-
Get precise element coordinates and dimensions (x, y, width, height). Shows position relative to viewport.
|
|
454
|
-
|
|
455
|
-
**Use Cases:**
|
|
456
|
-
- Finding exact click coordinates
|
|
457
|
-
- Checking element layout
|
|
458
|
-
- Calculating distances between elements
|
|
459
|
-
- Debugging overlapping elements
|
|
460
|
-
|
|
461
452
|
#### `compare_positions`
|
|
462
453
|
Compare positions and alignment of two elements. Validates if elements are aligned (top, left, right, bottom) or have matching dimensions (width, height).
|
|
463
454
|
|
|
@@ -703,8 +694,8 @@ Regular CSS selectors, text selectors (`text=Login`), and Playwright selectors w
|
|
|
703
694
|
→ Found 3 matches, 2 are hidden (display:none)
|
|
704
695
|
3. check_visibility({ selector: ".submit-button:nth-child(1)" })
|
|
705
696
|
→ Element is clipped by parent overflow:hidden
|
|
706
|
-
4.
|
|
707
|
-
→
|
|
697
|
+
4. measure_element({ selector: ".submit-button:nth-child(1)" })
|
|
698
|
+
→ @ (1500,300) 100x40px (outside viewport)
|
|
708
699
|
```
|
|
709
700
|
|
|
710
701
|
### Understanding Page Structure
|
|
@@ -774,9 +765,9 @@ These step-by-step recipes show how to chain tools together for common testing a
|
|
|
774
765
|
1. navigate({ url: "https://dashboard.example.com" })
|
|
775
766
|
2. inspect_dom({ selector: "testid:sidebar" })
|
|
776
767
|
→ Understand the structure of the problematic area
|
|
777
|
-
3.
|
|
768
|
+
3. measure_element({ selector: "testid:logo" })
|
|
778
769
|
→ @ (20,10) 150x40px
|
|
779
|
-
4.
|
|
770
|
+
4. measure_element({ selector: "testid:menu" })
|
|
780
771
|
→ @ (20,60) 200x300px
|
|
781
772
|
5. compare_positions({
|
|
782
773
|
selector1: "testid:logo",
|
|
@@ -870,9 +861,9 @@ These step-by-step recipes show how to chain tools together for common testing a
|
|
|
870
861
|
checkAlignment: "height"
|
|
871
862
|
})
|
|
872
863
|
→ ✗ not aligned (difference: 20px)
|
|
873
|
-
5.
|
|
864
|
+
5. measure_element({ selector: ".card:nth-child(1)" })
|
|
874
865
|
→ @ (20,100) 400x300px
|
|
875
|
-
6.
|
|
866
|
+
6. measure_element({ selector: ".card:nth-child(2)" })
|
|
876
867
|
→ @ (440,100) 400x320px ← 20px taller!
|
|
877
868
|
```
|
|
878
869
|
|
|
@@ -926,7 +917,7 @@ These step-by-step recipes show how to chain tools together for common testing a
|
|
|
926
917
|
3. wait_for_element({ selector: "testid:tooltip", state: "visible", timeout: 2000 })
|
|
927
918
|
4. check_visibility({ selector: "testid:tooltip" })
|
|
928
919
|
→ ✓ visible
|
|
929
|
-
5.
|
|
920
|
+
5. measure_element({ selector: "testid:tooltip" })
|
|
930
921
|
→ @ (300,150) 200x50px
|
|
931
922
|
6. get_computed_styles({
|
|
932
923
|
selector: "testid:tooltip",
|
package/dist/toolHandler.js
CHANGED
|
@@ -4,7 +4,6 @@ import { ScreenshotTool, NavigationTool, CloseBrowserTool, ConsoleLogsTool } fro
|
|
|
4
4
|
import { ClickTool, FillTool, SelectTool, HoverTool, EvaluateTool, UploadFileTool } from './tools/browser/interaction.js';
|
|
5
5
|
import { VisibleTextTool, VisibleHtmlTool } from './tools/browser/visiblePage.js';
|
|
6
6
|
import { ElementVisibilityTool } from './tools/browser/elementVisibility.js';
|
|
7
|
-
import { ElementPositionTool } from './tools/browser/elementPosition.js';
|
|
8
7
|
import { InspectDomTool } from './tools/browser/inspectDom.js';
|
|
9
8
|
import { GetTestIdsTool } from './tools/browser/getTestIds.js';
|
|
10
9
|
import { QuerySelectorAllTool } from './tools/browser/querySelectorAll.js';
|
|
@@ -12,7 +11,7 @@ import { FindByTextTool } from './tools/browser/findByText.js';
|
|
|
12
11
|
import { GetComputedStylesTool } from './tools/browser/computedStyles.js';
|
|
13
12
|
import { MeasureElementTool } from './tools/browser/measureElement.js';
|
|
14
13
|
import { ElementExistsTool } from './tools/browser/elementExists.js';
|
|
15
|
-
import {
|
|
14
|
+
import { CompareElementAlignmentTool } from './tools/browser/compareElementAlignment.js';
|
|
16
15
|
import { GoBackTool, GoForwardTool } from './tools/browser/navigation.js';
|
|
17
16
|
import { DragTool, PressKeyTool } from './tools/browser/interaction.js';
|
|
18
17
|
import { WaitForElementTool } from './tools/browser/waitForElement.js';
|
|
@@ -90,7 +89,6 @@ let goForwardTool;
|
|
|
90
89
|
let dragTool;
|
|
91
90
|
let pressKeyTool;
|
|
92
91
|
let elementVisibilityTool;
|
|
93
|
-
let elementPositionTool;
|
|
94
92
|
let inspectDomTool;
|
|
95
93
|
let getTestIdsTool;
|
|
96
94
|
let querySelectorAllTool;
|
|
@@ -98,7 +96,7 @@ let findByTextTool;
|
|
|
98
96
|
let getComputedStylesTool;
|
|
99
97
|
let measureElementTool;
|
|
100
98
|
let elementExistsTool;
|
|
101
|
-
let
|
|
99
|
+
let compareElementAlignmentTool;
|
|
102
100
|
let waitForElementTool;
|
|
103
101
|
let waitForNetworkIdleTool;
|
|
104
102
|
let listNetworkRequestsTool;
|
|
@@ -219,6 +217,21 @@ export async function ensureBrowser(browserSettings) {
|
|
|
219
217
|
// Reset browser and page references
|
|
220
218
|
resetBrowserState();
|
|
221
219
|
}
|
|
220
|
+
// If browser exists and viewport settings changed, resize the viewport
|
|
221
|
+
if (browser && page && !page.isClosed() && browserSettings?.viewport) {
|
|
222
|
+
const { width, height } = browserSettings.viewport;
|
|
223
|
+
// Only resize if width or height are explicitly provided
|
|
224
|
+
if (width !== undefined || height !== undefined) {
|
|
225
|
+
const currentViewport = page.viewportSize();
|
|
226
|
+
const targetWidth = width ?? currentViewport?.width ?? 1280;
|
|
227
|
+
const targetHeight = height ?? currentViewport?.height ?? 720;
|
|
228
|
+
// Check if viewport size actually changed
|
|
229
|
+
if (!currentViewport || currentViewport.width !== targetWidth || currentViewport.height !== targetHeight) {
|
|
230
|
+
console.error(`Resizing viewport to ${targetWidth}x${targetHeight}`);
|
|
231
|
+
await page.setViewportSize({ width: targetWidth, height: targetHeight });
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
222
235
|
// Launch new browser if needed
|
|
223
236
|
if (!browser) {
|
|
224
237
|
const { viewport, userAgent, headless = false, browserType = 'chromium', device } = browserSettings ?? {};
|
|
@@ -483,8 +496,6 @@ function initializeTools(server) {
|
|
|
483
496
|
pressKeyTool = new PressKeyTool(server);
|
|
484
497
|
if (!elementVisibilityTool)
|
|
485
498
|
elementVisibilityTool = new ElementVisibilityTool(server);
|
|
486
|
-
if (!elementPositionTool)
|
|
487
|
-
elementPositionTool = new ElementPositionTool(server);
|
|
488
499
|
if (!inspectDomTool)
|
|
489
500
|
inspectDomTool = new InspectDomTool(server);
|
|
490
501
|
if (!getTestIdsTool)
|
|
@@ -499,8 +510,8 @@ function initializeTools(server) {
|
|
|
499
510
|
measureElementTool = new MeasureElementTool(server);
|
|
500
511
|
if (!elementExistsTool)
|
|
501
512
|
elementExistsTool = new ElementExistsTool(server);
|
|
502
|
-
if (!
|
|
503
|
-
|
|
513
|
+
if (!compareElementAlignmentTool)
|
|
514
|
+
compareElementAlignmentTool = new CompareElementAlignmentTool(server);
|
|
504
515
|
if (!waitForElementTool)
|
|
505
516
|
waitForElementTool = new WaitForElementTool(server);
|
|
506
517
|
if (!waitForNetworkIdleTool)
|
|
@@ -626,8 +637,6 @@ export async function handleToolCall(name, args, server) {
|
|
|
626
637
|
return await pressKeyTool.execute(args, context);
|
|
627
638
|
case "check_visibility":
|
|
628
639
|
return await elementVisibilityTool.execute(args, context);
|
|
629
|
-
case "get_position":
|
|
630
|
-
return await elementPositionTool.execute(args, context);
|
|
631
640
|
case "inspect_dom":
|
|
632
641
|
return await inspectDomTool.execute(args, context);
|
|
633
642
|
case "get_test_ids":
|
|
@@ -642,8 +651,8 @@ export async function handleToolCall(name, args, server) {
|
|
|
642
651
|
return await measureElementTool.execute(args, context);
|
|
643
652
|
case "element_exists":
|
|
644
653
|
return await elementExistsTool.execute(args, context);
|
|
645
|
-
case "
|
|
646
|
-
return await
|
|
654
|
+
case "compare_element_alignment":
|
|
655
|
+
return await compareElementAlignmentTool.execute(args, context);
|
|
647
656
|
case "wait_for_element":
|
|
648
657
|
return await waitForElementTool.execute(args, context);
|
|
649
658
|
case "wait_for_network_idle":
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { BrowserToolBase } from './base.js';
|
|
2
|
+
import { ToolContext, ToolResponse } from '../common/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Tool for comparing alignment of two elements
|
|
5
|
+
*/
|
|
6
|
+
export declare class CompareElementAlignmentTool extends BrowserToolBase {
|
|
7
|
+
/**
|
|
8
|
+
* Execute the compare element alignment tool
|
|
9
|
+
*/
|
|
10
|
+
execute(args: any, context: ToolContext): Promise<ToolResponse>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { BrowserToolBase } from './base.js';
|
|
2
|
+
import { createSuccessResponse, createErrorResponse } from '../common/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Tool for comparing alignment of two elements
|
|
5
|
+
*/
|
|
6
|
+
export class CompareElementAlignmentTool extends BrowserToolBase {
|
|
7
|
+
/**
|
|
8
|
+
* Execute the compare element alignment tool
|
|
9
|
+
*/
|
|
10
|
+
async execute(args, context) {
|
|
11
|
+
return this.safeExecute(context, async (page) => {
|
|
12
|
+
const selector1 = this.normalizeSelector(args.selector1);
|
|
13
|
+
const selector2 = this.normalizeSelector(args.selector2);
|
|
14
|
+
try {
|
|
15
|
+
// Get locators for both elements
|
|
16
|
+
const locator1 = page.locator(selector1);
|
|
17
|
+
const locator2 = page.locator(selector2);
|
|
18
|
+
// Check if both elements exist
|
|
19
|
+
const count1 = await locator1.count();
|
|
20
|
+
const count2 = await locator2.count();
|
|
21
|
+
if (count1 === 0) {
|
|
22
|
+
return createErrorResponse(`First element not found: ${args.selector1}`);
|
|
23
|
+
}
|
|
24
|
+
if (count2 === 0) {
|
|
25
|
+
return createErrorResponse(`Second element not found: ${args.selector2}`);
|
|
26
|
+
}
|
|
27
|
+
// Handle multiple matches by using first() - show warning
|
|
28
|
+
const targetLocator1 = count1 > 1 ? locator1.first() : locator1;
|
|
29
|
+
const targetLocator2 = count2 > 1 ? locator2.first() : locator2;
|
|
30
|
+
let warnings = '';
|
|
31
|
+
if (count1 > 1) {
|
|
32
|
+
warnings += `⚠ Warning: First selector matched ${count1} elements, using first\n`;
|
|
33
|
+
}
|
|
34
|
+
if (count2 > 1) {
|
|
35
|
+
warnings += `⚠ Warning: Second selector matched ${count2} elements, using first\n`;
|
|
36
|
+
}
|
|
37
|
+
if (warnings) {
|
|
38
|
+
warnings += '\n';
|
|
39
|
+
}
|
|
40
|
+
// Get bounding boxes
|
|
41
|
+
const box1 = await targetLocator1.boundingBox();
|
|
42
|
+
const box2 = await targetLocator2.boundingBox();
|
|
43
|
+
// Get element descriptors
|
|
44
|
+
const getDescriptor = async (locator) => {
|
|
45
|
+
return await locator.evaluate((element) => {
|
|
46
|
+
const tagName = element.tagName.toLowerCase();
|
|
47
|
+
const testId = element.getAttribute('data-testid') || element.getAttribute('data-test') || element.getAttribute('data-cy');
|
|
48
|
+
const id = element.id ? `#${element.id}` : '';
|
|
49
|
+
const classes = element.className && typeof element.className === 'string'
|
|
50
|
+
? `.${element.className.split(' ').filter(c => c).join('.')}`
|
|
51
|
+
: '';
|
|
52
|
+
let descriptor = `<${tagName}`;
|
|
53
|
+
if (testId)
|
|
54
|
+
descriptor += ` data-testid="${testId}"`;
|
|
55
|
+
else if (id)
|
|
56
|
+
descriptor += id;
|
|
57
|
+
else if (classes)
|
|
58
|
+
descriptor += classes;
|
|
59
|
+
descriptor += '>';
|
|
60
|
+
return descriptor;
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
const descriptor1 = await getDescriptor(targetLocator1);
|
|
64
|
+
const descriptor2 = await getDescriptor(targetLocator2);
|
|
65
|
+
// Handle hidden elements
|
|
66
|
+
if (!box1) {
|
|
67
|
+
return createErrorResponse(`First element is hidden or has no dimensions: ${descriptor1}`);
|
|
68
|
+
}
|
|
69
|
+
if (!box2) {
|
|
70
|
+
return createErrorResponse(`Second element is hidden or has no dimensions: ${descriptor2}`);
|
|
71
|
+
}
|
|
72
|
+
// Extract short name from descriptor for compact output
|
|
73
|
+
const getShortName = (descriptor, selector) => {
|
|
74
|
+
const testIdMatch = descriptor.match(/data-testid="([^"]+)"/);
|
|
75
|
+
if (testIdMatch)
|
|
76
|
+
return testIdMatch[1];
|
|
77
|
+
const idMatch = descriptor.match(/#([^>]+)/);
|
|
78
|
+
if (idMatch)
|
|
79
|
+
return idMatch[1];
|
|
80
|
+
// Use original selector if available
|
|
81
|
+
return selector;
|
|
82
|
+
};
|
|
83
|
+
const name1 = getShortName(descriptor1, args.selector1);
|
|
84
|
+
const name2 = getShortName(descriptor2, args.selector2);
|
|
85
|
+
// Calculate all alignment values
|
|
86
|
+
const tolerance = 2; // Allow 2px tolerance for rounding
|
|
87
|
+
// Edge positions
|
|
88
|
+
const top1 = Math.round(box1.y);
|
|
89
|
+
const top2 = Math.round(box2.y);
|
|
90
|
+
const topDiff = Math.abs(top1 - top2);
|
|
91
|
+
const topAligned = topDiff <= tolerance;
|
|
92
|
+
const left1 = Math.round(box1.x);
|
|
93
|
+
const left2 = Math.round(box2.x);
|
|
94
|
+
const leftDiff = Math.abs(left1 - left2);
|
|
95
|
+
const leftAligned = leftDiff <= tolerance;
|
|
96
|
+
const right1 = Math.round(box1.x + box1.width);
|
|
97
|
+
const right2 = Math.round(box2.x + box2.width);
|
|
98
|
+
const rightDiff = Math.abs(right1 - right2);
|
|
99
|
+
const rightAligned = rightDiff <= tolerance;
|
|
100
|
+
const bottom1 = Math.round(box1.y + box1.height);
|
|
101
|
+
const bottom2 = Math.round(box2.y + box2.height);
|
|
102
|
+
const bottomDiff = Math.abs(bottom1 - bottom2);
|
|
103
|
+
const bottomAligned = bottomDiff <= tolerance;
|
|
104
|
+
// Center positions
|
|
105
|
+
const centerH1 = Math.round(box1.x + box1.width / 2);
|
|
106
|
+
const centerH2 = Math.round(box2.x + box2.width / 2);
|
|
107
|
+
const centerHDiff = Math.abs(centerH1 - centerH2);
|
|
108
|
+
const centerHAligned = centerHDiff <= tolerance;
|
|
109
|
+
const centerV1 = Math.round(box1.y + box1.height / 2);
|
|
110
|
+
const centerV2 = Math.round(box2.y + box2.height / 2);
|
|
111
|
+
const centerVDiff = Math.abs(centerV1 - centerV2);
|
|
112
|
+
const centerVAligned = centerVDiff <= tolerance;
|
|
113
|
+
// Dimensions
|
|
114
|
+
const width1 = Math.round(box1.width);
|
|
115
|
+
const width2 = Math.round(box2.width);
|
|
116
|
+
const widthDiff = Math.abs(width1 - width2);
|
|
117
|
+
const widthSame = widthDiff <= tolerance;
|
|
118
|
+
const height1 = Math.round(box1.height);
|
|
119
|
+
const height2 = Math.round(box2.height);
|
|
120
|
+
const heightDiff = Math.abs(height1 - height2);
|
|
121
|
+
const heightSame = heightDiff <= tolerance;
|
|
122
|
+
// Format compact output
|
|
123
|
+
const formatAlignment = (aligned, val1, val2, diff, unit = 'px') => {
|
|
124
|
+
const symbol = aligned ? '✓' : '✗';
|
|
125
|
+
const status = aligned ? 'aligned' : 'not aligned';
|
|
126
|
+
if (aligned) {
|
|
127
|
+
return `${symbol} ${status} (both @ ${val1}${unit})`;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
return `${symbol} ${status} (${val1}${unit} vs ${val2}${unit}, diff: ${diff}${unit})`;
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
const formatDimension = (same, val1, val2, diff, unit = 'px') => {
|
|
134
|
+
const symbol = same ? '✓' : '✗';
|
|
135
|
+
const status = same ? 'same' : 'different';
|
|
136
|
+
if (same) {
|
|
137
|
+
return `${symbol} ${status} (${val1}${unit})`;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
return `${symbol} ${status} (${val1}${unit} vs ${val2}${unit}, diff: ${diff}${unit})`;
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
// Build output
|
|
144
|
+
const lines = [
|
|
145
|
+
warnings,
|
|
146
|
+
`Alignment: ${descriptor1} vs ${descriptor2}`,
|
|
147
|
+
` ${name1}: @ (${left1},${top1}) ${width1}×${height1}px`,
|
|
148
|
+
` ${name2}: @ (${left2},${top2}) ${width2}×${height2}px`,
|
|
149
|
+
'',
|
|
150
|
+
'Edges:',
|
|
151
|
+
` Top: ${formatAlignment(topAligned, top1, top2, topDiff)}`,
|
|
152
|
+
` Left: ${formatAlignment(leftAligned, left1, left2, leftDiff)}`,
|
|
153
|
+
` Right: ${formatAlignment(rightAligned, right1, right2, rightDiff)}`,
|
|
154
|
+
` Bottom: ${formatAlignment(bottomAligned, bottom1, bottom2, bottomDiff)}`,
|
|
155
|
+
'',
|
|
156
|
+
'Centers:',
|
|
157
|
+
` Horizontal: ${formatAlignment(centerHAligned, centerH1, centerH2, centerHDiff)}`,
|
|
158
|
+
` Vertical: ${formatAlignment(centerVAligned, centerV1, centerV2, centerVDiff)}`,
|
|
159
|
+
'',
|
|
160
|
+
'Dimensions:',
|
|
161
|
+
` Width: ${formatDimension(widthSame, width1, width2, widthDiff)}`,
|
|
162
|
+
` Height: ${formatDimension(heightSame, height1, height2, heightDiff)}`
|
|
163
|
+
];
|
|
164
|
+
return createSuccessResponse(lines.filter(l => l !== undefined).join('\n'));
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
return createErrorResponse(`Failed to compare element alignment: ${error.message}`);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -391,6 +391,13 @@ export class InspectDomTool extends BrowserToolBase {
|
|
|
391
391
|
lines.push(`${prefix} ${tag}${roleInfo}`);
|
|
392
392
|
// Position
|
|
393
393
|
lines.push(` @ (${child.position.x},${child.position.y}) ${child.position.width}x${child.position.height}px`);
|
|
394
|
+
// Calculate distances from all parent edges
|
|
395
|
+
const fromLeft = child.position.x - target.position.x;
|
|
396
|
+
const fromRight = (target.position.x + target.position.width) - (child.position.x + child.position.width);
|
|
397
|
+
const fromTop = child.position.y - target.position.y;
|
|
398
|
+
const fromBottom = (target.position.y + target.position.height) - (child.position.y + child.position.height);
|
|
399
|
+
// Format edge distances (centering is obvious: equal left/right = horizontal center, equal top/bottom = vertical center)
|
|
400
|
+
lines.push(` from edges: ←${fromLeft}px →${fromRight}px ↑${fromTop}px ↓${fromBottom}px`);
|
|
394
401
|
// Calculate offset from previous sibling
|
|
395
402
|
if (index > 0) {
|
|
396
403
|
const prev = children[index - 1];
|
package/dist/tools.d.ts
CHANGED
|
@@ -48,7 +48,7 @@ export declare function createToolDefinitions(sessionConfig?: SessionConfig): [{
|
|
|
48
48
|
};
|
|
49
49
|
}, {
|
|
50
50
|
readonly name: "screenshot";
|
|
51
|
-
readonly description:
|
|
51
|
+
readonly description: `\u26A0\uFE0F RARELY NEEDED: Screenshots are NOT useful for LLMs to analyze layouts, margins, or alignment issues. Use inspect_dom(), compare_positions(), or measure_element() instead - they provide precise numerical data. Only take screenshots for: (1) sharing with humans for visual confirmation, (2) documenting test results, or (3) verifying colors/images. Screenshots are saved to ${string}. Example: { name: "login-page", fullPage: true } or { name: "submit-btn", selector: "testid:submit" }`;
|
|
52
52
|
readonly inputSchema: {
|
|
53
53
|
readonly type: "object";
|
|
54
54
|
readonly properties: {
|
|
@@ -150,7 +150,7 @@ export declare function createToolDefinitions(sessionConfig?: SessionConfig): [{
|
|
|
150
150
|
};
|
|
151
151
|
}, {
|
|
152
152
|
readonly name: "evaluate";
|
|
153
|
-
readonly description: "Execute JavaScript in the browser console";
|
|
153
|
+
readonly description: "Execute JavaScript in the browser console. ⚠️ AVOID for common tasks - use specialized tools instead: inspect_dom() for page structure, compare_positions() for alignment, measure_element() for spacing, query_selector() for finding elements. Only use evaluate() for custom logic not covered by other tools.";
|
|
154
154
|
readonly inputSchema: {
|
|
155
155
|
readonly type: "object";
|
|
156
156
|
readonly properties: {
|
|
@@ -210,7 +210,7 @@ export declare function createToolDefinitions(sessionConfig?: SessionConfig): [{
|
|
|
210
210
|
};
|
|
211
211
|
}, {
|
|
212
212
|
readonly name: "get_html";
|
|
213
|
-
readonly description: "Get
|
|
213
|
+
readonly description: "Get raw HTML content of the page or specific element. ⚠️ For understanding page structure, use inspect_dom() instead - it's more efficient and filters out noise. Use get_html() only when you need the actual HTML markup (e.g., to check specific attributes or element nesting).";
|
|
214
214
|
readonly inputSchema: {
|
|
215
215
|
readonly type: "object";
|
|
216
216
|
readonly properties: {
|
|
@@ -312,22 +312,9 @@ export declare function createToolDefinitions(sessionConfig?: SessionConfig): [{
|
|
|
312
312
|
};
|
|
313
313
|
readonly required: readonly ["selector"];
|
|
314
314
|
};
|
|
315
|
-
}, {
|
|
316
|
-
readonly name: "get_position";
|
|
317
|
-
readonly description: "Get the position and size of an element. Returns x, y coordinates and width/height in pixels. Useful for finding where to click or checking element layout. Supports testid shortcuts (e.g., 'testid:submit-button').";
|
|
318
|
-
readonly inputSchema: {
|
|
319
|
-
readonly type: "object";
|
|
320
|
-
readonly properties: {
|
|
321
|
-
readonly selector: {
|
|
322
|
-
readonly type: "string";
|
|
323
|
-
readonly description: "CSS selector, text selector, or testid shorthand (e.g., 'testid:login-button', '#submit', 'text=Click here')";
|
|
324
|
-
};
|
|
325
|
-
};
|
|
326
|
-
readonly required: readonly ["selector"];
|
|
327
|
-
};
|
|
328
315
|
}, {
|
|
329
316
|
readonly name: "inspect_dom";
|
|
330
|
-
readonly description: "Progressive DOM inspection
|
|
317
|
+
readonly description: "START HERE FOR LAYOUT DEBUGGING: Progressive DOM inspection that shows parent-child relationships, centering issues, and spacing gaps. Skips wrapper divs and shows only semantic elements (header, nav, main, form, button, elements with test IDs, ARIA roles, etc.).\n\nWORKFLOW: Call without selector for page overview, then drill down by calling with child's selector.\n\nDETECTS: Parent-relative positioning, vertical/horizontal centering, sibling spacing gaps, layout patterns.\n\nOUTPUT FORMAT:\n[0] <button data-testid=\"menu\">\n @ (16,8) 40×40px ← Absolute viewport position (x,y) and size\n from edges: ←16px →1144px ↑8px ↓8px ← Distance from parent edges (↑8px = ↓8px means vertically centered)\n \"Menu\"\n ✓ visible, ⚡ interactive\n\n[1] <div data-testid=\"title\">\n @ (260,2) 131×28px\n from edges: ←244px →244px ↑2px ↓42px ← Equal left/right (244px) = horizontally centered, unequal top/bottom = NOT vertically centered\n gap from [0]: →16px ← Spacing between siblings\n \"Title\"\n ✓ visible, 2 children\n\nSYMBOLS: ✓=visible, ✗=hidden, ⚡=interactive, ←→=horizontal edges, ↑↓=vertical edges\nCENTERING: Equal left/right distances = horizontally centered, equal top/bottom = vertically centered\n\nRELATED TOOLS: For comparing TWO elements' alignment (not parent-child), use compare_element_alignment(). For box model (padding/margin), use measure_element().\n\nMore efficient than get_html() or evaluate(). Supports testid shortcuts.";
|
|
331
318
|
readonly inputSchema: {
|
|
332
319
|
readonly type: "object";
|
|
333
320
|
readonly properties: {
|
|
@@ -423,7 +410,7 @@ export declare function createToolDefinitions(sessionConfig?: SessionConfig): [{
|
|
|
423
410
|
};
|
|
424
411
|
}, {
|
|
425
412
|
readonly name: "get_computed_styles";
|
|
426
|
-
readonly description: "Get computed CSS
|
|
413
|
+
readonly description: "INSPECT CSS PROPERTIES: Get computed CSS values for specific properties (display, position, width, etc.). Use when you need raw CSS values or specific properties not shown by measure_element(). Returns styles grouped by category (Layout, Visibility, Spacing, Typography). For box model visualization (padding/margin), use measure_element() instead.";
|
|
427
414
|
readonly inputSchema: {
|
|
428
415
|
readonly type: "object";
|
|
429
416
|
readonly properties: {
|
|
@@ -440,7 +427,7 @@ export declare function createToolDefinitions(sessionConfig?: SessionConfig): [{
|
|
|
440
427
|
};
|
|
441
428
|
}, {
|
|
442
429
|
readonly name: "measure_element";
|
|
443
|
-
readonly description: "
|
|
430
|
+
readonly description: "DEBUG SPACING ISSUES: See padding, margin, and border measurements in visual box model format. Use when elements have unexpected spacing or size. Returns compact visual representation showing content → padding → border → margin with directional arrows (↑24px for top margin, etc.). For parent-child centering issues, use inspect_dom() first (shows if child is centered in parent). For comparing alignment between two elements, use compare_element_alignment(). More readable than get_computed_styles() for box model debugging.";
|
|
444
431
|
readonly inputSchema: {
|
|
445
432
|
readonly type: "object";
|
|
446
433
|
readonly properties: {
|
|
@@ -465,8 +452,8 @@ export declare function createToolDefinitions(sessionConfig?: SessionConfig): [{
|
|
|
465
452
|
readonly required: readonly ["selector"];
|
|
466
453
|
};
|
|
467
454
|
}, {
|
|
468
|
-
readonly name: "
|
|
469
|
-
readonly description: "
|
|
455
|
+
readonly name: "compare_element_alignment";
|
|
456
|
+
readonly description: "COMPARE TWO ELEMENTS: Get comprehensive alignment and dimension comparison in one call. Shows edge alignment (top, left, right, bottom), center alignment (horizontal, vertical), and dimensions (width, height). Perfect for debugging 'are these headers aligned?' or 'do these panels match?'. Returns all alignment info with ✓/✗ symbols and pixel differences. For parent-child centering, use inspect_dom() instead (automatically shows if children are centered in parent). More efficient than evaluate() with manual getBoundingClientRect() calculations.";
|
|
470
457
|
readonly inputSchema: {
|
|
471
458
|
readonly type: "object";
|
|
472
459
|
readonly properties: {
|
|
@@ -478,13 +465,8 @@ export declare function createToolDefinitions(sessionConfig?: SessionConfig): [{
|
|
|
478
465
|
readonly type: "string";
|
|
479
466
|
readonly description: "CSS selector, text selector, or testid shorthand for the second element (e.g., 'testid:chat-header', '#secondary-header')";
|
|
480
467
|
};
|
|
481
|
-
readonly checkAlignment: {
|
|
482
|
-
readonly type: "string";
|
|
483
|
-
readonly description: "What to check: 'top', 'left', 'right', 'bottom' (edge alignment), or 'width', 'height' (dimension matching)";
|
|
484
|
-
readonly enum: readonly ["top", "left", "right", "bottom", "width", "height"];
|
|
485
|
-
};
|
|
486
468
|
};
|
|
487
|
-
readonly required: readonly ["selector1", "selector2"
|
|
469
|
+
readonly required: readonly ["selector1", "selector2"];
|
|
488
470
|
};
|
|
489
471
|
}, {
|
|
490
472
|
readonly name: "wait_for_element";
|
package/dist/tools.js
CHANGED
|
@@ -31,7 +31,7 @@ export function createToolDefinitions(sessionConfig) {
|
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
name: "screenshot",
|
|
34
|
-
description:
|
|
34
|
+
description: `⚠️ RARELY NEEDED: Screenshots are NOT useful for LLMs to analyze layouts, margins, or alignment issues. Use inspect_dom(), compare_positions(), or measure_element() instead - they provide precise numerical data. Only take screenshots for: (1) sharing with humans for visual confirmation, (2) documenting test results, or (3) verifying colors/images. Screenshots are saved to ${screenshotsDir}. Example: { name: "login-page", fullPage: true } or { name: "submit-btn", selector: "testid:submit" }`,
|
|
35
35
|
inputSchema: {
|
|
36
36
|
type: "object",
|
|
37
37
|
properties: {
|
|
@@ -115,7 +115,7 @@ export function createToolDefinitions(sessionConfig) {
|
|
|
115
115
|
},
|
|
116
116
|
{
|
|
117
117
|
name: "evaluate",
|
|
118
|
-
description: "Execute JavaScript in the browser console",
|
|
118
|
+
description: "Execute JavaScript in the browser console. ⚠️ AVOID for common tasks - use specialized tools instead: inspect_dom() for page structure, compare_positions() for alignment, measure_element() for spacing, query_selector() for finding elements. Only use evaluate() for custom logic not covered by other tools.",
|
|
119
119
|
inputSchema: {
|
|
120
120
|
type: "object",
|
|
121
121
|
properties: {
|
|
@@ -176,7 +176,7 @@ export function createToolDefinitions(sessionConfig) {
|
|
|
176
176
|
},
|
|
177
177
|
{
|
|
178
178
|
name: "get_html",
|
|
179
|
-
description: "Get
|
|
179
|
+
description: "Get raw HTML content of the page or specific element. ⚠️ For understanding page structure, use inspect_dom() instead - it's more efficient and filters out noise. Use get_html() only when you need the actual HTML markup (e.g., to check specific attributes or element nesting).",
|
|
180
180
|
inputSchema: {
|
|
181
181
|
type: "object",
|
|
182
182
|
properties: {
|
|
@@ -248,23 +248,34 @@ export function createToolDefinitions(sessionConfig) {
|
|
|
248
248
|
required: ["selector"],
|
|
249
249
|
},
|
|
250
250
|
},
|
|
251
|
-
{
|
|
252
|
-
name: "get_position",
|
|
253
|
-
description: "Get the position and size of an element. Returns x, y coordinates and width/height in pixels. Useful for finding where to click or checking element layout. Supports testid shortcuts (e.g., 'testid:submit-button').",
|
|
254
|
-
inputSchema: {
|
|
255
|
-
type: "object",
|
|
256
|
-
properties: {
|
|
257
|
-
selector: {
|
|
258
|
-
type: "string",
|
|
259
|
-
description: "CSS selector, text selector, or testid shorthand (e.g., 'testid:login-button', '#submit', 'text=Click here')"
|
|
260
|
-
},
|
|
261
|
-
},
|
|
262
|
-
required: ["selector"],
|
|
263
|
-
},
|
|
264
|
-
},
|
|
265
251
|
{
|
|
266
252
|
name: "inspect_dom",
|
|
267
|
-
description:
|
|
253
|
+
description: `START HERE FOR LAYOUT DEBUGGING: Progressive DOM inspection that shows parent-child relationships, centering issues, and spacing gaps. Skips wrapper divs and shows only semantic elements (header, nav, main, form, button, elements with test IDs, ARIA roles, etc.).
|
|
254
|
+
|
|
255
|
+
WORKFLOW: Call without selector for page overview, then drill down by calling with child's selector.
|
|
256
|
+
|
|
257
|
+
DETECTS: Parent-relative positioning, vertical/horizontal centering, sibling spacing gaps, layout patterns.
|
|
258
|
+
|
|
259
|
+
OUTPUT FORMAT:
|
|
260
|
+
[0] <button data-testid="menu">
|
|
261
|
+
@ (16,8) 40×40px ← Absolute viewport position (x,y) and size
|
|
262
|
+
from edges: ←16px →1144px ↑8px ↓8px ← Distance from parent edges (↑8px = ↓8px means vertically centered)
|
|
263
|
+
"Menu"
|
|
264
|
+
✓ visible, ⚡ interactive
|
|
265
|
+
|
|
266
|
+
[1] <div data-testid="title">
|
|
267
|
+
@ (260,2) 131×28px
|
|
268
|
+
from edges: ←244px →244px ↑2px ↓42px ← Equal left/right (244px) = horizontally centered, unequal top/bottom = NOT vertically centered
|
|
269
|
+
gap from [0]: →16px ← Spacing between siblings
|
|
270
|
+
"Title"
|
|
271
|
+
✓ visible, 2 children
|
|
272
|
+
|
|
273
|
+
SYMBOLS: ✓=visible, ✗=hidden, ⚡=interactive, ←→=horizontal edges, ↑↓=vertical edges
|
|
274
|
+
CENTERING: Equal left/right distances = horizontally centered, equal top/bottom = vertically centered
|
|
275
|
+
|
|
276
|
+
RELATED TOOLS: For comparing TWO elements' alignment (not parent-child), use compare_element_alignment(). For box model (padding/margin), use measure_element().
|
|
277
|
+
|
|
278
|
+
More efficient than get_html() or evaluate(). Supports testid shortcuts.`,
|
|
268
279
|
inputSchema: {
|
|
269
280
|
type: "object",
|
|
270
281
|
properties: {
|
|
@@ -364,7 +375,7 @@ export function createToolDefinitions(sessionConfig) {
|
|
|
364
375
|
},
|
|
365
376
|
{
|
|
366
377
|
name: "get_computed_styles",
|
|
367
|
-
description: "Get computed CSS
|
|
378
|
+
description: "INSPECT CSS PROPERTIES: Get computed CSS values for specific properties (display, position, width, etc.). Use when you need raw CSS values or specific properties not shown by measure_element(). Returns styles grouped by category (Layout, Visibility, Spacing, Typography). For box model visualization (padding/margin), use measure_element() instead.",
|
|
368
379
|
inputSchema: {
|
|
369
380
|
type: "object",
|
|
370
381
|
properties: {
|
|
@@ -382,7 +393,7 @@ export function createToolDefinitions(sessionConfig) {
|
|
|
382
393
|
},
|
|
383
394
|
{
|
|
384
395
|
name: "measure_element",
|
|
385
|
-
description: "
|
|
396
|
+
description: "DEBUG SPACING ISSUES: See padding, margin, and border measurements in visual box model format. Use when elements have unexpected spacing or size. Returns compact visual representation showing content → padding → border → margin with directional arrows (↑24px for top margin, etc.). For parent-child centering issues, use inspect_dom() first (shows if child is centered in parent). For comparing alignment between two elements, use compare_element_alignment(). More readable than get_computed_styles() for box model debugging.",
|
|
386
397
|
inputSchema: {
|
|
387
398
|
type: "object",
|
|
388
399
|
properties: {
|
|
@@ -409,8 +420,8 @@ export function createToolDefinitions(sessionConfig) {
|
|
|
409
420
|
},
|
|
410
421
|
},
|
|
411
422
|
{
|
|
412
|
-
name: "
|
|
413
|
-
description: "
|
|
423
|
+
name: "compare_element_alignment",
|
|
424
|
+
description: "COMPARE TWO ELEMENTS: Get comprehensive alignment and dimension comparison in one call. Shows edge alignment (top, left, right, bottom), center alignment (horizontal, vertical), and dimensions (width, height). Perfect for debugging 'are these headers aligned?' or 'do these panels match?'. Returns all alignment info with ✓/✗ symbols and pixel differences. For parent-child centering, use inspect_dom() instead (automatically shows if children are centered in parent). More efficient than evaluate() with manual getBoundingClientRect() calculations.",
|
|
414
425
|
inputSchema: {
|
|
415
426
|
type: "object",
|
|
416
427
|
properties: {
|
|
@@ -421,14 +432,9 @@ export function createToolDefinitions(sessionConfig) {
|
|
|
421
432
|
selector2: {
|
|
422
433
|
type: "string",
|
|
423
434
|
description: "CSS selector, text selector, or testid shorthand for the second element (e.g., 'testid:chat-header', '#secondary-header')"
|
|
424
|
-
},
|
|
425
|
-
checkAlignment: {
|
|
426
|
-
type: "string",
|
|
427
|
-
description: "What to check: 'top', 'left', 'right', 'bottom' (edge alignment), or 'width', 'height' (dimension matching)",
|
|
428
|
-
enum: ["top", "left", "right", "bottom", "width", "height"]
|
|
429
435
|
}
|
|
430
436
|
},
|
|
431
|
-
required: ["selector1", "selector2"
|
|
437
|
+
required: ["selector1", "selector2"],
|
|
432
438
|
},
|
|
433
439
|
},
|
|
434
440
|
{
|
|
@@ -516,8 +522,7 @@ export const BROWSER_TOOLS = [
|
|
|
516
522
|
"find_by_text",
|
|
517
523
|
// Visibility & Position
|
|
518
524
|
"check_visibility",
|
|
519
|
-
"
|
|
520
|
-
"compare_positions",
|
|
525
|
+
"compare_element_alignment",
|
|
521
526
|
"element_exists",
|
|
522
527
|
"wait_for_element",
|
|
523
528
|
"wait_for_network_idle",
|