@ricardodeazambuja/browser-mcp-server 1.3.0 → 1.4.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/CHANGELOG-v1.4.0.md +8 -0
- package/README.md +87 -6
- package/package.json +3 -2
- package/src/browser.js +2 -0
- package/src/cdp.js +58 -0
- package/src/index.js +2 -2
- package/src/tools/docs.js +798 -0
- package/src/tools/index.js +5 -1
- package/src/tools/network.js +552 -0
- package/src/tools/performance.js +517 -0
- package/src/tools/security.js +470 -0
- package/src/tools/storage.js +467 -0
- package/src/tools/system.js +5 -1
- package/src/utils.js +12 -1
- package/tests/fixtures/test-network.html +48 -0
- package/tests/fixtures/test-performance.html +61 -0
- package/tests/fixtures/test-security.html +33 -0
- package/tests/fixtures/test-storage.html +76 -0
- package/tests/run-all.js +50 -0
- package/tests/test-mcp.js +3 -2
- package/tests/test-network.js +212 -0
- package/tests/test-performance.js +254 -0
- package/tests/test-security.js +203 -0
- package/tests/test-storage.js +192 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Storage Test Page</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<h1>Storage Test Page</h1>
|
|
10
|
+
<p>This page creates IndexedDB and Cache Storage for testing.</p>
|
|
11
|
+
<div id="status"></div>
|
|
12
|
+
|
|
13
|
+
<script>
|
|
14
|
+
async function setupStorage() {
|
|
15
|
+
const status = document.getElementById('status');
|
|
16
|
+
status.innerHTML = 'Setting up storage...<br>';
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
// Create IndexedDB
|
|
20
|
+
const dbRequest = indexedDB.open('testDB', 1);
|
|
21
|
+
|
|
22
|
+
dbRequest.onupgradeneeded = (event) => {
|
|
23
|
+
const db = event.target.result;
|
|
24
|
+
if (!db.objectStoreNames.contains('users')) {
|
|
25
|
+
const objectStore = db.createObjectStore('users', { keyPath: 'id' });
|
|
26
|
+
objectStore.createIndex('name', 'name', { unique: false });
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
dbRequest.onsuccess = async (event) => {
|
|
31
|
+
const db = event.target.result;
|
|
32
|
+
const transaction = db.transaction(['users'], 'readwrite');
|
|
33
|
+
const objectStore = transaction.objectStore('users');
|
|
34
|
+
|
|
35
|
+
// Add some data
|
|
36
|
+
objectStore.add({ id: 1, name: 'Alice', email: 'alice@example.com' });
|
|
37
|
+
objectStore.add({ id: 2, name: 'Bob', email: 'bob@example.com' });
|
|
38
|
+
|
|
39
|
+
status.innerHTML += '✓ IndexedDB created and populated<br>';
|
|
40
|
+
|
|
41
|
+
// Create Cache Storage
|
|
42
|
+
if ('caches' in window) {
|
|
43
|
+
const cache = await caches.open('test-cache-v1');
|
|
44
|
+
await cache.put('/test', new Response('Test data'));
|
|
45
|
+
status.innerHTML += '✓ Cache Storage created<br>';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Register Service Worker (if supported)
|
|
49
|
+
if ('serviceWorker' in navigator) {
|
|
50
|
+
try {
|
|
51
|
+
// Note: Service worker registration requires HTTPS or localhost
|
|
52
|
+
status.innerHTML += 'Service Worker registration skipped (requires HTTPS)<br>';
|
|
53
|
+
} catch (e) {
|
|
54
|
+
status.innerHTML += `Service Worker: ${e.message}<br>`;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
status.innerHTML += 'Storage setup complete!';
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
dbRequest.onerror = (event) => {
|
|
62
|
+
status.innerHTML += `✗ IndexedDB error: ${event.target.error}<br>`;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
} catch (error) {
|
|
66
|
+
status.innerHTML += `Error: ${error.message}`;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Auto-run after page load
|
|
71
|
+
window.addEventListener('load', () => {
|
|
72
|
+
setTimeout(setupStorage, 500);
|
|
73
|
+
});
|
|
74
|
+
</script>
|
|
75
|
+
</body>
|
|
76
|
+
</html>
|
package/tests/run-all.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Main Test Runner
|
|
5
|
+
* Runs all test files in the tests directory
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { spawnSync } = require('child_process');
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
|
|
12
|
+
const testsDir = __dirname;
|
|
13
|
+
const testFiles = fs.readdirSync(testsDir)
|
|
14
|
+
.filter(f => f.startsWith('test-') && f.endsWith('.js'))
|
|
15
|
+
.sort();
|
|
16
|
+
|
|
17
|
+
console.log('🚀 Running all Browser MCP Server tests...\n');
|
|
18
|
+
|
|
19
|
+
let passed = 0;
|
|
20
|
+
let failed = 0;
|
|
21
|
+
|
|
22
|
+
testFiles.forEach(file => {
|
|
23
|
+
console.log(`\n------------------------------------------------------------`);
|
|
24
|
+
console.log(`📄 Testing: ${file}`);
|
|
25
|
+
console.log(`------------------------------------------------------------\n`);
|
|
26
|
+
|
|
27
|
+
const result = spawnSync('node', [path.join(testsDir, file)], {
|
|
28
|
+
stdio: 'inherit'
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
if (result.status === 0) {
|
|
32
|
+
passed++;
|
|
33
|
+
} else {
|
|
34
|
+
failed++;
|
|
35
|
+
console.error(`\n❌ ${file} failed with exit code ${result.status}`);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
console.log(`\n\n${'='.repeat(60)}`);
|
|
40
|
+
console.log(`📊 Final Test Summary:`);
|
|
41
|
+
console.log(` ✅ Passed: ${passed}`);
|
|
42
|
+
console.log(` ❌ Failed: ${failed}`);
|
|
43
|
+
console.log(`${'='.repeat(60)}\n`);
|
|
44
|
+
|
|
45
|
+
if (failed > 0) {
|
|
46
|
+
process.exit(1);
|
|
47
|
+
} else {
|
|
48
|
+
console.log('🎉 All test suites passed successfully!\n');
|
|
49
|
+
process.exit(0);
|
|
50
|
+
}
|
package/tests/test-mcp.js
CHANGED
|
@@ -51,6 +51,7 @@ async function runTests() {
|
|
|
51
51
|
|
|
52
52
|
const responses = new Map();
|
|
53
53
|
let testsCompleted = 0;
|
|
54
|
+
let toolCount = 0;
|
|
54
55
|
const totalTests = 3;
|
|
55
56
|
|
|
56
57
|
rl.on('line', (line) => {
|
|
@@ -75,7 +76,7 @@ async function runTests() {
|
|
|
75
76
|
|
|
76
77
|
} else if (response.id === 2) {
|
|
77
78
|
// Tools list response
|
|
78
|
-
|
|
79
|
+
toolCount = response.result.tools.length;
|
|
79
80
|
console.log(` ✅ Received ${toolCount} tools:`);
|
|
80
81
|
response.result.tools.forEach(tool => {
|
|
81
82
|
console.log(` - ${tool.name}`);
|
|
@@ -102,7 +103,7 @@ async function runTests() {
|
|
|
102
103
|
console.log(`\n✅ All tests passed! (${testsCompleted}/${totalTests})`);
|
|
103
104
|
console.log('\n📊 Test Summary:');
|
|
104
105
|
console.log(' ✅ MCP Protocol initialization');
|
|
105
|
-
console.log(
|
|
106
|
+
console.log(` ✅ Tools listing (${toolCount} tools)`);
|
|
106
107
|
|
|
107
108
|
|
|
108
109
|
console.log(' ✅ Browser automation (health check)');
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Network Tools Test Suite
|
|
5
|
+
* Tests network monitoring, HAR export, and request blocking
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { spawn } = require('child_process');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const readline = require('readline');
|
|
11
|
+
|
|
12
|
+
const serverPath = path.join(__dirname, '..', 'src', 'index.js');
|
|
13
|
+
const proc = spawn('node', [serverPath], { stdio: ['pipe', 'pipe', 'pipe'] });
|
|
14
|
+
|
|
15
|
+
proc.stderr.on('data', (data) => {
|
|
16
|
+
// Suppress stderr for cleaner test output
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
proc.on('error', (err) => {
|
|
20
|
+
console.error('Server error:', err);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const rl = readline.createInterface({ input: proc.stdout, terminal: false });
|
|
25
|
+
|
|
26
|
+
let messageId = 1;
|
|
27
|
+
let testStep = 0;
|
|
28
|
+
|
|
29
|
+
function sendRequest(method, params) {
|
|
30
|
+
const request = { jsonrpc: '2.0', id: messageId++, method, params };
|
|
31
|
+
proc.stdin.write(JSON.stringify(request) + '\n');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
console.log('🌐 Network Tools Test Suite\n');
|
|
35
|
+
|
|
36
|
+
rl.on('line', (line) => {
|
|
37
|
+
try {
|
|
38
|
+
const response = JSON.parse(line);
|
|
39
|
+
if (response.method === 'notifications/resources/list_changed') return;
|
|
40
|
+
if (response.error) {
|
|
41
|
+
console.error('❌ Error:', response.error.message);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
if (response.result && response.id) {
|
|
45
|
+
handleResponse(response);
|
|
46
|
+
}
|
|
47
|
+
} catch (e) {
|
|
48
|
+
// Ignore non-JSON lines
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
function handleResponse(response) {
|
|
53
|
+
const currentTest = steps[testStep];
|
|
54
|
+
if (!currentTest) return;
|
|
55
|
+
|
|
56
|
+
console.log(`➡️ ${currentTest.name}`);
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
currentTest.verify(response);
|
|
60
|
+
console.log(` ✅ Passed\n`);
|
|
61
|
+
} catch (err) {
|
|
62
|
+
console.error(` ❌ Failed: ${err.message}`);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
testStep++;
|
|
67
|
+
if (testStep < steps.length) {
|
|
68
|
+
setTimeout(() => {
|
|
69
|
+
sendRequest(steps[testStep].method, steps[testStep].params());
|
|
70
|
+
}, 500);
|
|
71
|
+
} else {
|
|
72
|
+
console.log('🎉 All network tests passed!');
|
|
73
|
+
proc.kill();
|
|
74
|
+
process.exit(0);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const steps = [
|
|
79
|
+
{
|
|
80
|
+
name: 'Initialize',
|
|
81
|
+
method: 'initialize',
|
|
82
|
+
params: () => ({
|
|
83
|
+
protocolVersion: '2024-11-05',
|
|
84
|
+
capabilities: {},
|
|
85
|
+
clientInfo: { name: 'network-test', version: '1.0.0' }
|
|
86
|
+
}),
|
|
87
|
+
verify: () => { }
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: 'Start Network Monitoring',
|
|
91
|
+
method: 'tools/call',
|
|
92
|
+
params: () => ({
|
|
93
|
+
name: 'browser_net_start_monitoring',
|
|
94
|
+
arguments: {}
|
|
95
|
+
}),
|
|
96
|
+
verify: (res) => {
|
|
97
|
+
const text = res.result.content[0].text;
|
|
98
|
+
// Accept success, already active, or CDP error
|
|
99
|
+
if (!text.includes('monitoring started') && !text.includes('already active') && !text.includes('CDP Error')) {
|
|
100
|
+
throw new Error('Unexpected response: ' + text.substring(0, 100));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: 'Navigate to Network Test Page',
|
|
106
|
+
method: 'tools/call',
|
|
107
|
+
params: () => ({
|
|
108
|
+
name: 'browser_navigate',
|
|
109
|
+
arguments: { url: 'file://' + path.join(__dirname, 'fixtures', 'test-network.html') }
|
|
110
|
+
}),
|
|
111
|
+
verify: () => { }
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: 'Wait for Network Requests',
|
|
115
|
+
method: 'tools/call',
|
|
116
|
+
params: () => ({
|
|
117
|
+
name: 'browser_wait',
|
|
118
|
+
arguments: { ms: 3000 }
|
|
119
|
+
}),
|
|
120
|
+
verify: () => { }
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: 'Get Network Requests',
|
|
124
|
+
method: 'tools/call',
|
|
125
|
+
params: () => ({
|
|
126
|
+
name: 'browser_net_get_requests',
|
|
127
|
+
arguments: {}
|
|
128
|
+
}),
|
|
129
|
+
verify: (res) => {
|
|
130
|
+
const text = res.result.content[0].text;
|
|
131
|
+
// Accept success, not active, or CDP error
|
|
132
|
+
if (!text.includes('totalCaptured') && !text.includes('not active') && !text.includes('CDP Error')) {
|
|
133
|
+
throw new Error('Unexpected response: ' + text.substring(0, 100));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: 'Export HAR',
|
|
139
|
+
method: 'tools/call',
|
|
140
|
+
params: () => ({
|
|
141
|
+
name: 'browser_net_export_har',
|
|
142
|
+
arguments: {}
|
|
143
|
+
}),
|
|
144
|
+
verify: (res) => {
|
|
145
|
+
const text = res.result.content[0].text;
|
|
146
|
+
// Accept HAR export, not active warning, or error
|
|
147
|
+
if (!text.includes('HAR') && !text.includes('No network data') && !text.includes('Error')) {
|
|
148
|
+
throw new Error('Unexpected response: ' + text.substring(0, 100));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
name: 'Stop Network Monitoring',
|
|
154
|
+
method: 'tools/call',
|
|
155
|
+
params: () => ({
|
|
156
|
+
name: 'browser_net_stop_monitoring',
|
|
157
|
+
arguments: {}
|
|
158
|
+
}),
|
|
159
|
+
verify: (res) => {
|
|
160
|
+
const text = res.result.content[0].text;
|
|
161
|
+
// Accept stopped message, not active, or error
|
|
162
|
+
if (!text.includes('stopped') && !text.includes('not active') && !text.includes('Error')) {
|
|
163
|
+
throw new Error('Unexpected response: ' + text.substring(0, 100));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
name: 'Set Request Blocking',
|
|
169
|
+
method: 'tools/call',
|
|
170
|
+
params: () => ({
|
|
171
|
+
name: 'browser_net_set_request_blocking',
|
|
172
|
+
arguments: { patterns: ['*.jpg', '*.png'] }
|
|
173
|
+
}),
|
|
174
|
+
verify: (res) => {
|
|
175
|
+
const text = res.result.content[0].text;
|
|
176
|
+
// Accept success or error
|
|
177
|
+
if (!text.includes('blocking enabled') && !text.includes('Error')) {
|
|
178
|
+
throw new Error('Unexpected response: ' + text.substring(0, 100));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
name: 'Emulate Network Conditions',
|
|
184
|
+
method: 'tools/call',
|
|
185
|
+
params: () => ({
|
|
186
|
+
name: 'browser_net_emulate_conditions',
|
|
187
|
+
arguments: {
|
|
188
|
+
offline: false,
|
|
189
|
+
latency: 100,
|
|
190
|
+
downloadThroughput: 1000000,
|
|
191
|
+
uploadThroughput: 500000
|
|
192
|
+
}
|
|
193
|
+
}),
|
|
194
|
+
verify: (res) => {
|
|
195
|
+
const text = res.result.content[0].text;
|
|
196
|
+
// Accept success or error
|
|
197
|
+
if (!text.includes('conditions applied') && !text.includes('Error')) {
|
|
198
|
+
throw new Error('Unexpected response: ' + text.substring(0, 100));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
];
|
|
203
|
+
|
|
204
|
+
// Start tests
|
|
205
|
+
setTimeout(() => sendRequest(steps[0].method, steps[0].params()), 500);
|
|
206
|
+
|
|
207
|
+
// Timeout after 60 seconds
|
|
208
|
+
setTimeout(() => {
|
|
209
|
+
console.error('\n❌ Test timeout');
|
|
210
|
+
proc.kill();
|
|
211
|
+
process.exit(1);
|
|
212
|
+
}, 60000);
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Performance Tools Test Suite
|
|
5
|
+
* Tests CPU profiling, heap snapshots, metrics, and code coverage
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { spawn } = require('child_process');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const readline = require('readline');
|
|
11
|
+
|
|
12
|
+
const serverPath = path.join(__dirname, '..', 'src', 'index.js');
|
|
13
|
+
const proc = spawn('node', [serverPath], { stdio: ['pipe', 'pipe', 'pipe'] });
|
|
14
|
+
|
|
15
|
+
proc.stderr.on('data', (data) => {
|
|
16
|
+
// Suppress stderr for cleaner test output
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
proc.on('error', (err) => {
|
|
20
|
+
console.error('Server error:', err);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const rl = readline.createInterface({ input: proc.stdout, terminal: false });
|
|
25
|
+
|
|
26
|
+
let messageId = 1;
|
|
27
|
+
let testStep = 0;
|
|
28
|
+
|
|
29
|
+
function sendRequest(method, params) {
|
|
30
|
+
const request = { jsonrpc: '2.0', id: messageId++, method, params };
|
|
31
|
+
proc.stdin.write(JSON.stringify(request) + '\n');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
console.log('🔬 Performance Tools Test Suite\n');
|
|
35
|
+
|
|
36
|
+
rl.on('line', (line) => {
|
|
37
|
+
try {
|
|
38
|
+
const response = JSON.parse(line);
|
|
39
|
+
if (response.method === 'notifications/resources/list_changed') return;
|
|
40
|
+
if (response.error) {
|
|
41
|
+
console.error('❌ Error:', response.error.message);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
if (response.result && response.id) {
|
|
45
|
+
handleResponse(response);
|
|
46
|
+
}
|
|
47
|
+
} catch (e) {
|
|
48
|
+
// Ignore non-JSON lines
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
function handleResponse(response) {
|
|
53
|
+
const currentTest = steps[testStep];
|
|
54
|
+
if (!currentTest) return;
|
|
55
|
+
|
|
56
|
+
console.log(`➡️ ${currentTest.name}`);
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
currentTest.verify(response);
|
|
60
|
+
console.log(` ✅ Passed\n`);
|
|
61
|
+
} catch (err) {
|
|
62
|
+
console.error(` ❌ Failed: ${err.message}`);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
testStep++;
|
|
67
|
+
if (testStep < steps.length) {
|
|
68
|
+
setTimeout(() => {
|
|
69
|
+
sendRequest(steps[testStep].method, steps[testStep].params());
|
|
70
|
+
}, 500);
|
|
71
|
+
} else {
|
|
72
|
+
console.log('🎉 All performance tests passed!');
|
|
73
|
+
proc.kill();
|
|
74
|
+
process.exit(0);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const steps = [
|
|
79
|
+
{
|
|
80
|
+
name: 'Initialize',
|
|
81
|
+
method: 'initialize',
|
|
82
|
+
params: () => ({
|
|
83
|
+
protocolVersion: '2024-11-05',
|
|
84
|
+
capabilities: {},
|
|
85
|
+
clientInfo: { name: 'performance-test', version: '1.0.0' }
|
|
86
|
+
}),
|
|
87
|
+
verify: () => { }
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: 'Navigate to Performance Test Page',
|
|
91
|
+
method: 'tools/call',
|
|
92
|
+
params: () => ({
|
|
93
|
+
name: 'browser_navigate',
|
|
94
|
+
arguments: { url: 'file://' + path.join(__dirname, 'fixtures', 'test-performance.html') }
|
|
95
|
+
}),
|
|
96
|
+
verify: () => { }
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'Wait for Page Load',
|
|
100
|
+
method: 'tools/call',
|
|
101
|
+
params: () => ({
|
|
102
|
+
name: 'browser_wait',
|
|
103
|
+
arguments: { ms: 1000 }
|
|
104
|
+
}),
|
|
105
|
+
verify: () => { }
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: 'Start CPU Profiling',
|
|
109
|
+
method: 'tools/call',
|
|
110
|
+
params: () => ({
|
|
111
|
+
name: 'browser_perf_start_profile',
|
|
112
|
+
arguments: {}
|
|
113
|
+
}),
|
|
114
|
+
verify: (res) => {
|
|
115
|
+
const text = res.result.content[0].text;
|
|
116
|
+
if (res.result.isError) {
|
|
117
|
+
throw new Error('CPU profiling failed: ' + text);
|
|
118
|
+
}
|
|
119
|
+
if (!text.includes('profiling started') && !text.includes('already active')) {
|
|
120
|
+
throw new Error('Unexpected response: ' + text.substring(0, 100));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: 'Wait for Execution',
|
|
126
|
+
method: 'tools/call',
|
|
127
|
+
params: () => ({
|
|
128
|
+
name: 'browser_wait',
|
|
129
|
+
arguments: { ms: 2000 }
|
|
130
|
+
}),
|
|
131
|
+
verify: () => { }
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
name: 'Stop CPU Profiling',
|
|
135
|
+
method: 'tools/call',
|
|
136
|
+
params: () => ({
|
|
137
|
+
name: 'browser_perf_stop_profile',
|
|
138
|
+
arguments: {}
|
|
139
|
+
}),
|
|
140
|
+
verify: (res) => {
|
|
141
|
+
const text = res.result.content[0].text;
|
|
142
|
+
if (res.result.isError) {
|
|
143
|
+
throw new Error('Stop CPU profiling failed: ' + text);
|
|
144
|
+
}
|
|
145
|
+
if (!text.includes('totalNodes') && !text.includes('not active')) {
|
|
146
|
+
throw new Error('Unexpected response: ' + text.substring(0, 100));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
name: 'Get Heap Usage',
|
|
152
|
+
method: 'tools/call',
|
|
153
|
+
params: () => ({
|
|
154
|
+
name: 'browser_perf_get_heap_usage',
|
|
155
|
+
arguments: {}
|
|
156
|
+
}),
|
|
157
|
+
verify: (res) => {
|
|
158
|
+
const text = res.result.content[0].text;
|
|
159
|
+
if (res.result.isError) {
|
|
160
|
+
throw new Error('Get heap usage failed: ' + text);
|
|
161
|
+
}
|
|
162
|
+
if (!text.includes('usedSize')) {
|
|
163
|
+
throw new Error('Unexpected response: ' + text.substring(0, 100));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
name: 'Get Runtime Metrics',
|
|
169
|
+
method: 'tools/call',
|
|
170
|
+
params: () => ({
|
|
171
|
+
name: 'browser_perf_get_metrics',
|
|
172
|
+
arguments: {}
|
|
173
|
+
}),
|
|
174
|
+
verify: (res) => {
|
|
175
|
+
const text = res.result.content[0].text;
|
|
176
|
+
if (res.result.isError) {
|
|
177
|
+
throw new Error('Get runtime metrics failed: ' + text);
|
|
178
|
+
}
|
|
179
|
+
if (!text.includes('Nodes') && !text.includes('JSHeap')) {
|
|
180
|
+
throw new Error('Unexpected response: ' + text.substring(0, 100));
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: 'Get Performance Metrics',
|
|
186
|
+
method: 'tools/call',
|
|
187
|
+
params: () => ({
|
|
188
|
+
name: 'browser_perf_get_performance_metrics',
|
|
189
|
+
arguments: {}
|
|
190
|
+
}),
|
|
191
|
+
verify: (res) => {
|
|
192
|
+
const text = res.result.content[0].text;
|
|
193
|
+
if (res.result.isError) {
|
|
194
|
+
throw new Error('Get performance metrics failed: ' + text);
|
|
195
|
+
}
|
|
196
|
+
if (!text.includes('navigation')) {
|
|
197
|
+
throw new Error('Unexpected response: ' + text.substring(0, 100));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
name: 'Start Code Coverage',
|
|
203
|
+
method: 'tools/call',
|
|
204
|
+
params: () => ({
|
|
205
|
+
name: 'browser_perf_start_coverage',
|
|
206
|
+
arguments: {}
|
|
207
|
+
}),
|
|
208
|
+
verify: (res) => {
|
|
209
|
+
const text = res.result.content[0].text;
|
|
210
|
+
if (res.result.isError) {
|
|
211
|
+
throw new Error('Start code coverage failed: ' + text);
|
|
212
|
+
}
|
|
213
|
+
if (!text.includes('coverage started') && !text.includes('already active')) {
|
|
214
|
+
throw new Error('Unexpected response: ' + text.substring(0, 100));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
name: 'Wait for Coverage Collection',
|
|
220
|
+
method: 'tools/call',
|
|
221
|
+
params: () => ({
|
|
222
|
+
name: 'browser_wait',
|
|
223
|
+
arguments: { ms: 1000 }
|
|
224
|
+
}),
|
|
225
|
+
verify: () => { }
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
name: 'Stop Code Coverage',
|
|
229
|
+
method: 'tools/call',
|
|
230
|
+
params: () => ({
|
|
231
|
+
name: 'browser_perf_stop_coverage',
|
|
232
|
+
arguments: {}
|
|
233
|
+
}),
|
|
234
|
+
verify: (res) => {
|
|
235
|
+
const text = res.result.content[0].text;
|
|
236
|
+
if (res.result.isError) {
|
|
237
|
+
throw new Error('Stop code coverage failed: ' + text);
|
|
238
|
+
}
|
|
239
|
+
if (!text.includes('javascript') && !text.includes('not active')) {
|
|
240
|
+
throw new Error('Unexpected response: ' + text.substring(0, 100));
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
];
|
|
245
|
+
|
|
246
|
+
// Start tests
|
|
247
|
+
setTimeout(() => sendRequest(steps[0].method, steps[0].params()), 500);
|
|
248
|
+
|
|
249
|
+
// Timeout after 60 seconds
|
|
250
|
+
setTimeout(() => {
|
|
251
|
+
console.error('\n❌ Test timeout');
|
|
252
|
+
proc.kill();
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}, 60000);
|