@ricardodeazambuja/browser-mcp-server 1.0.3 → 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.3.0.md +42 -0
- package/CHANGELOG-v1.4.0.md +8 -0
- package/README.md +271 -45
- package/package.json +11 -10
- package/plugins/.gitkeep +0 -0
- package/src/.gitkeep +0 -0
- package/src/browser.js +152 -0
- package/src/cdp.js +58 -0
- package/src/index.js +126 -0
- package/src/tools/.gitkeep +0 -0
- package/src/tools/console.js +139 -0
- package/src/tools/docs.js +1611 -0
- package/src/tools/index.js +60 -0
- package/src/tools/info.js +139 -0
- package/src/tools/interaction.js +126 -0
- package/src/tools/keyboard.js +27 -0
- package/src/tools/media.js +264 -0
- package/src/tools/mouse.js +104 -0
- package/src/tools/navigation.js +72 -0
- package/src/tools/network.js +552 -0
- package/src/tools/pages.js +149 -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 +196 -0
- package/src/utils.js +131 -0
- package/tests/.gitkeep +0 -0
- package/tests/fixtures/.gitkeep +0 -0
- package/tests/fixtures/test-media.html +35 -0
- 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/{test-browser-automation.js → tests/test-browser-automation.js} +44 -5
- package/{test-mcp.js → tests/test-mcp.js} +9 -4
- package/tests/test-media-tools.js +168 -0
- 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
- package/CHANGELOG-v1.0.2.md +0 -126
- package/browser-mcp-server-playwright.js +0 -792
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Media Awareness Test Suite
|
|
5
|
+
* Tests browser_get_media_summary, browser_control_media, browser_get_audio_analysis
|
|
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
|
+
console.error(data.toString().trim());
|
|
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('🌐 Media Awareness 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 media 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: 'test-suite', version: '1.0.0' }
|
|
86
|
+
}),
|
|
87
|
+
verify: () => { }
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: 'Navigate to Local Media Test',
|
|
91
|
+
method: 'tools/call',
|
|
92
|
+
params: () => ({
|
|
93
|
+
name: 'browser_navigate',
|
|
94
|
+
arguments: { url: 'file://' + path.join(__dirname, 'fixtures', 'test-media.html') }
|
|
95
|
+
}),
|
|
96
|
+
verify: () => { }
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'Wait for Audio Element',
|
|
100
|
+
method: 'tools/call',
|
|
101
|
+
params: () => ({
|
|
102
|
+
name: 'browser_wait_for_selector',
|
|
103
|
+
arguments: { selector: 'audio', timeout: 10000 }
|
|
104
|
+
}),
|
|
105
|
+
verify: () => { }
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: 'Get Media Summary',
|
|
109
|
+
method: 'tools/call',
|
|
110
|
+
params: () => ({
|
|
111
|
+
name: 'browser_get_media_summary',
|
|
112
|
+
arguments: {}
|
|
113
|
+
}),
|
|
114
|
+
verify: (res) => {
|
|
115
|
+
const summary = JSON.parse(res.result.content[0].text);
|
|
116
|
+
console.log(` Found ${summary.length} media element(s)`);
|
|
117
|
+
if (!Array.isArray(summary)) throw new Error('Result is not an array');
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: 'Play Media',
|
|
122
|
+
method: 'tools/call',
|
|
123
|
+
params: () => ({
|
|
124
|
+
name: 'browser_control_media',
|
|
125
|
+
arguments: { selector: 'audio', action: 'play' }
|
|
126
|
+
}),
|
|
127
|
+
verify: (res) => {
|
|
128
|
+
const result = JSON.parse(res.result.content[0].text);
|
|
129
|
+
if (result.status !== 'playing') throw new Error('Failed to play');
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: 'Wait for Playback',
|
|
134
|
+
method: 'tools/call',
|
|
135
|
+
params: () => ({
|
|
136
|
+
name: 'browser_wait',
|
|
137
|
+
arguments: { ms: 1000 }
|
|
138
|
+
}),
|
|
139
|
+
verify: () => { }
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
name: 'Analyze Audio',
|
|
143
|
+
method: 'tools/call',
|
|
144
|
+
params: () => ({
|
|
145
|
+
name: 'browser_get_audio_analysis',
|
|
146
|
+
arguments: { durationMs: 500 }
|
|
147
|
+
}),
|
|
148
|
+
verify: (res) => {
|
|
149
|
+
const analysis = JSON.parse(res.result.content[0].text);
|
|
150
|
+
if (typeof analysis.averageVolume !== 'number') throw new Error('Invalid analysis');
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
name: 'Pause Media',
|
|
155
|
+
method: 'tools/call',
|
|
156
|
+
params: () => ({
|
|
157
|
+
name: 'browser_control_media',
|
|
158
|
+
arguments: { selector: 'audio', action: 'pause' }
|
|
159
|
+
}),
|
|
160
|
+
verify: (res) => {
|
|
161
|
+
const result = JSON.parse(res.result.content[0].text);
|
|
162
|
+
if (result.status !== 'paused') throw new Error('Failed to pause');
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
];
|
|
166
|
+
|
|
167
|
+
// Start tests
|
|
168
|
+
setTimeout(() => sendRequest(steps[0].method, steps[0].params()), 500);
|
|
@@ -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);
|