firefox-devtools-mcp 0.2.0
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/LICENSE +21 -0
- package/README.md +126 -0
- package/dist/index.js +15826 -0
- package/dist/snapshot.injected.global.js +1 -0
- package/package.json +102 -0
- package/scripts/_helpers/page-loader.js +121 -0
- package/scripts/demo-server.js +325 -0
- package/scripts/setup-mcp-config.js +260 -0
- package/scripts/test-bidi-devtools.js +380 -0
- package/scripts/test-console.js +148 -0
- package/scripts/test-dialog.js +102 -0
- package/scripts/test-input-tools.js +233 -0
- package/scripts/test-lifecycle-hooks.js +124 -0
- package/scripts/test-screenshot.js +190 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Test script for screenshot functionality (Task 22)
|
|
5
|
+
* Tests: takeScreenshotPage, takeScreenshotByUid
|
|
6
|
+
* Saves screenshots to temp/ directory for visual inspection
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { FirefoxDevTools } from '../dist/index.js';
|
|
10
|
+
import { writeFile, mkdir } from 'node:fs/promises';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import { fileURLToPath } from 'node:url';
|
|
13
|
+
import { dirname } from 'node:path';
|
|
14
|
+
import {
|
|
15
|
+
loadHTML,
|
|
16
|
+
waitShort,
|
|
17
|
+
shouldRunOnlineTests,
|
|
18
|
+
skipOnlineTest,
|
|
19
|
+
} from './_helpers/page-loader.js';
|
|
20
|
+
|
|
21
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
22
|
+
const __dirname = dirname(__filename);
|
|
23
|
+
const TEMP_DIR = join(__dirname, '../temp');
|
|
24
|
+
|
|
25
|
+
async function saveScreenshot(base64Data, filename) {
|
|
26
|
+
// Ensure temp directory exists
|
|
27
|
+
await mkdir(TEMP_DIR, { recursive: true });
|
|
28
|
+
|
|
29
|
+
// Convert base64 to buffer and save
|
|
30
|
+
const buffer = Buffer.from(base64Data, 'base64');
|
|
31
|
+
const filepath = join(TEMP_DIR, filename);
|
|
32
|
+
await writeFile(filepath, buffer);
|
|
33
|
+
|
|
34
|
+
console.log(` ๐พ Saved: ${filepath} (${(buffer.length / 1024).toFixed(2)} KB)`);
|
|
35
|
+
return filepath;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function main() {
|
|
39
|
+
console.log('๐ท Testing Screenshot Functionality...\n');
|
|
40
|
+
|
|
41
|
+
const firefox = new FirefoxDevTools({
|
|
42
|
+
firefoxPath: undefined,
|
|
43
|
+
headless: false,
|
|
44
|
+
startUrl: 'about:blank',
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
console.log('๐ก Connecting to Firefox...');
|
|
49
|
+
await firefox.connect();
|
|
50
|
+
console.log('โ
Connected!\n');
|
|
51
|
+
|
|
52
|
+
// Online tests (optional)
|
|
53
|
+
if (shouldRunOnlineTests()) {
|
|
54
|
+
// Test 1: Screenshot of example.com
|
|
55
|
+
console.log('๐ Test 1: Full page screenshot (example.com)');
|
|
56
|
+
await firefox.navigate('https://example.com');
|
|
57
|
+
await waitShort(2000);
|
|
58
|
+
|
|
59
|
+
const examplePageScreenshot = await firefox.takeScreenshotPage();
|
|
60
|
+
await saveScreenshot(examplePageScreenshot, 'screenshot-example-page.png');
|
|
61
|
+
console.log(` โ
Screenshot captured (${examplePageScreenshot.length} chars base64)\n`);
|
|
62
|
+
|
|
63
|
+
// Test 2: Screenshot of specific element (heading)
|
|
64
|
+
console.log('๐ฏ Test 2: Element screenshot (h1 heading)');
|
|
65
|
+
const snapshot1 = await firefox.takeSnapshot();
|
|
66
|
+
const h1Node = snapshot1.json.root.children?.find((n) => n.tag === 'h1');
|
|
67
|
+
|
|
68
|
+
if (h1Node && h1Node.uid) {
|
|
69
|
+
console.log(` Found: <h1> with UID ${h1Node.uid}`);
|
|
70
|
+
const h1Screenshot = await firefox.takeScreenshotByUid(h1Node.uid);
|
|
71
|
+
await saveScreenshot(h1Screenshot, 'screenshot-example-h1.png');
|
|
72
|
+
console.log(` โ
Element screenshot captured (${h1Screenshot.length} chars base64)\n`);
|
|
73
|
+
} else {
|
|
74
|
+
console.log(' โ ๏ธ No h1 element found\n');
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
skipOnlineTest('Online screenshot tests (example.com)');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Test 3: Custom HTML page with styled elements (OFFLINE)
|
|
81
|
+
console.log('๐จ Test 3: Custom styled page (offline)');
|
|
82
|
+
|
|
83
|
+
await loadHTML(
|
|
84
|
+
firefox,
|
|
85
|
+
`
|
|
86
|
+
<head><title>Screenshot Test</title><style>
|
|
87
|
+
body { font-family: Arial; padding: 40px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); margin: 0; min-height: 100vh; }
|
|
88
|
+
.card { background: white; border-radius: 12px; padding: 30px; box-shadow: 0 20px 60px rgba(0,0,0,0.3); max-width: 600px; margin: 0 auto; }
|
|
89
|
+
h1 { color: #667eea; margin: 0 0 20px 0; font-size: 36px; }
|
|
90
|
+
.button { background: #667eea; color: white; padding: 15px 30px; border: none; border-radius: 8px; font-size: 18px; cursor: pointer; display: inline-block; margin: 10px 5px; box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4); }
|
|
91
|
+
.button:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6); }
|
|
92
|
+
p { color: #555; line-height: 1.6; font-size: 16px; }
|
|
93
|
+
</style></head><body>
|
|
94
|
+
<div class="card">
|
|
95
|
+
<h1 id="title">๐ฏ Screenshot Test Page</h1>
|
|
96
|
+
<p id="description">This is a beautifully styled test page for screenshot functionality. The gradient background and card design showcase visual capture capabilities.</p>
|
|
97
|
+
<button class="button" id="btn1">Primary Action</button>
|
|
98
|
+
<button class="button" id="btn2">Secondary Action</button>
|
|
99
|
+
</div>
|
|
100
|
+
</body>
|
|
101
|
+
`
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
await waitShort(500);
|
|
105
|
+
|
|
106
|
+
const customPageScreenshot = await firefox.takeScreenshotPage();
|
|
107
|
+
await saveScreenshot(customPageScreenshot, 'screenshot-custom-page.png');
|
|
108
|
+
console.log(` โ
Full page screenshot captured\n`);
|
|
109
|
+
|
|
110
|
+
// Test 4: Screenshot of styled elements using UID
|
|
111
|
+
console.log('๐จ Test 4: Individual styled elements (via UID)');
|
|
112
|
+
|
|
113
|
+
const snapshot = await firefox.takeSnapshot();
|
|
114
|
+
|
|
115
|
+
// Find h1 element
|
|
116
|
+
const findElement = (node, tag) => {
|
|
117
|
+
if (node.tag === tag) return node;
|
|
118
|
+
if (node.children) {
|
|
119
|
+
for (const child of node.children) {
|
|
120
|
+
const found = findElement(child, tag);
|
|
121
|
+
if (found) return found;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return null;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const h1 = findElement(snapshot.json.root, 'h1');
|
|
128
|
+
if (h1 && h1.uid) {
|
|
129
|
+
const h1Screenshot = await firefox.takeScreenshotByUid(h1.uid);
|
|
130
|
+
await saveScreenshot(h1Screenshot, 'screenshot-custom-h1.png');
|
|
131
|
+
console.log(` โ
H1 screenshot captured via UID`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Find first button
|
|
135
|
+
const button = findElement(snapshot.json.root, 'button');
|
|
136
|
+
if (button && button.uid) {
|
|
137
|
+
const buttonScreenshot = await firefox.takeScreenshotByUid(button.uid);
|
|
138
|
+
await saveScreenshot(buttonScreenshot, 'screenshot-custom-button.png');
|
|
139
|
+
console.log(` โ
Button screenshot captured via UID\n`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Test 5: Screenshot using direct CSS selectors (fallback method)
|
|
143
|
+
console.log('๐จ Test 5: Individual styled elements (via CSS selectors)');
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
// Get element via evaluate and take screenshot using WebDriver directly
|
|
147
|
+
const driver = firefox.getDriver();
|
|
148
|
+
|
|
149
|
+
// Screenshot title
|
|
150
|
+
const titleEl = await driver.findElement({ css: '#title' });
|
|
151
|
+
await driver.executeScript('arguments[0].scrollIntoView({block: "center"});', titleEl);
|
|
152
|
+
await waitShort(200);
|
|
153
|
+
const titleScreenshot = await titleEl.takeScreenshot();
|
|
154
|
+
await saveScreenshot(titleScreenshot, 'screenshot-custom-title.png');
|
|
155
|
+
console.log(` โ
Title screenshot captured`);
|
|
156
|
+
|
|
157
|
+
// Screenshot second button (avoid conflict with UID test)
|
|
158
|
+
const buttonEl = await driver.findElement({ css: '#btn2' });
|
|
159
|
+
await driver.executeScript('arguments[0].scrollIntoView({block: "center"});', buttonEl);
|
|
160
|
+
await waitShort(200);
|
|
161
|
+
const buttonScreenshot = await buttonEl.takeScreenshot();
|
|
162
|
+
await saveScreenshot(buttonScreenshot, 'screenshot-custom-button2.png');
|
|
163
|
+
console.log(` โ
Button screenshot captured`);
|
|
164
|
+
|
|
165
|
+
// Screenshot card container
|
|
166
|
+
const cardEl = await driver.findElement({ css: '.card' });
|
|
167
|
+
await driver.executeScript('arguments[0].scrollIntoView({block: "center"});', cardEl);
|
|
168
|
+
await waitShort(200);
|
|
169
|
+
const cardScreenshot = await cardEl.takeScreenshot();
|
|
170
|
+
await saveScreenshot(cardScreenshot, 'screenshot-custom-card.png');
|
|
171
|
+
console.log(` โ
Card screenshot captured\n`);
|
|
172
|
+
} catch (error) {
|
|
173
|
+
console.log(` โ ๏ธ Element screenshot failed: ${error.message}\n`);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
console.log('โ
All screenshot tests completed! ๐');
|
|
177
|
+
console.log(`\n๐ Screenshots saved to: ${TEMP_DIR}\n`);
|
|
178
|
+
|
|
179
|
+
} catch (error) {
|
|
180
|
+
console.error('โ Test failed:', error.message);
|
|
181
|
+
if (error.stack) console.error(error.stack);
|
|
182
|
+
process.exit(1);
|
|
183
|
+
} finally {
|
|
184
|
+
console.log('๐งน Closing...');
|
|
185
|
+
await firefox.close();
|
|
186
|
+
console.log('โ
Done');
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
main().catch(console.error);
|