mcpbrowser 0.2.18 โ 0.2.21
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/.github/workflows/test.yml +33 -0
- package/README.md +1 -1
- package/extension/package.json +1 -1
- package/extension/src/extension.js +1 -1
- package/package.json +4 -2
- package/server.json +1 -1
- package/src/mcp-browser.js +185 -68
- package/test-mcp.js +63 -0
- package/tests/domain-tab-pooling.test.js +329 -0
- package/tests/integration.test.js +158 -0
- package/tests/mcp-server.test.js +154 -0
- package/tests/prepare-html.test.js +307 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import assert from 'assert';
|
|
2
|
+
import { prepareHtml } from '../src/mcp-browser.js';
|
|
3
|
+
|
|
4
|
+
console.log('๐งช Testing prepareHtml function\n');
|
|
5
|
+
|
|
6
|
+
let testsPassed = 0;
|
|
7
|
+
let testsFailed = 0;
|
|
8
|
+
|
|
9
|
+
function test(description, fn) {
|
|
10
|
+
try {
|
|
11
|
+
fn();
|
|
12
|
+
console.log(`โ
${description}`);
|
|
13
|
+
testsPassed++;
|
|
14
|
+
} catch (err) {
|
|
15
|
+
console.log(`โ ${description}`);
|
|
16
|
+
console.log(` Error: ${err.message}`);
|
|
17
|
+
testsFailed++;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Test 1: Remove HTML comments
|
|
22
|
+
test('Should remove HTML comments', () => {
|
|
23
|
+
const html = '<div>Content<!-- This is a comment --></div>';
|
|
24
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
25
|
+
assert(!result.includes('<!--'), 'Should not contain comment start');
|
|
26
|
+
assert(!result.includes('-->'), 'Should not contain comment end');
|
|
27
|
+
assert(result.includes('Content'), 'Should preserve content');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Test 2: Remove script tags
|
|
31
|
+
test('Should remove script tags and their content', () => {
|
|
32
|
+
const html = '<div>Keep this</div><script>alert("remove");</script><div>And this</div>';
|
|
33
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
34
|
+
assert(!result.includes('<script'), 'Should not contain script tag');
|
|
35
|
+
assert(!result.includes('alert'), 'Should not contain script content');
|
|
36
|
+
assert(result.includes('Keep this'), 'Should preserve content');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Test 3: Remove style tags
|
|
40
|
+
test('Should remove style tags and their content', () => {
|
|
41
|
+
const html = '<div>Content</div><style>.class { color: red; }</style>';
|
|
42
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
43
|
+
assert(!result.includes('<style'), 'Should not contain style tag');
|
|
44
|
+
assert(!result.includes('color: red'), 'Should not contain style content');
|
|
45
|
+
assert(result.includes('Content'), 'Should preserve content');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Test 4: Remove meta tags
|
|
49
|
+
test('Should remove meta tags', () => {
|
|
50
|
+
const html = '<head><meta charset="utf-8"><meta name="viewport" content="width=device-width"></head><body>Content</body>';
|
|
51
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
52
|
+
assert(!result.includes('<meta'), 'Should not contain meta tags');
|
|
53
|
+
assert(result.includes('Content'), 'Should preserve content');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Test 5: Convert relative URLs in href
|
|
57
|
+
test('Should convert relative href URLs to absolute', () => {
|
|
58
|
+
const html = '<a href="/docs/page">Link</a>';
|
|
59
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
60
|
+
assert(result.includes('href="https://example.com/docs/page"'), 'Should convert relative href to absolute');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Test 6: Keep absolute URLs in href unchanged
|
|
64
|
+
test('Should keep absolute href URLs unchanged', () => {
|
|
65
|
+
const html = '<a href="https://other.com/page">Link</a>';
|
|
66
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
67
|
+
assert(result.includes('href="https://other.com/page"'), 'Should keep absolute href unchanged');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Test 7: Convert relative URLs in src
|
|
71
|
+
test('Should convert relative src URLs to absolute', () => {
|
|
72
|
+
const html = '<img src="/images/logo.png">';
|
|
73
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
74
|
+
assert(result.includes('src="https://example.com/images/logo.png"'), 'Should convert relative src to absolute');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Test 8: Keep absolute URLs in src unchanged
|
|
78
|
+
test('Should keep absolute src URLs unchanged', () => {
|
|
79
|
+
const html = '<img src="https://cdn.example.com/logo.png">';
|
|
80
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
81
|
+
assert(result.includes('src="https://cdn.example.com/logo.png"'), 'Should keep absolute src unchanged');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Test 9: Handle anchor links (should not modify)
|
|
85
|
+
test('Should not modify anchor links', () => {
|
|
86
|
+
const html = '<a href="#section">Jump</a>';
|
|
87
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
88
|
+
assert(result.includes('href="#section"'), 'Should keep anchor links unchanged');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Test 10: Handle mailto and tel links (should not modify)
|
|
92
|
+
test('Should not modify mailto and tel links', () => {
|
|
93
|
+
const html = '<a href="mailto:test@example.com">Email</a><a href="tel:+1234567890">Call</a>';
|
|
94
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
95
|
+
assert(result.includes('href="mailto:test@example.com"'), 'Should keep mailto unchanged');
|
|
96
|
+
assert(result.includes('href="tel:+1234567890"'), 'Should keep tel unchanged');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Test 11: Handle data URIs in src (should not modify)
|
|
100
|
+
test('Should not modify data URIs', () => {
|
|
101
|
+
const html = '<img src="data:image/png;base64,iVBORw0KGg==">';
|
|
102
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
103
|
+
assert(result.includes('src="data:image/png;base64,iVBORw0KGg=="'), 'Should keep data URI unchanged');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Test 12: Handle protocol-relative URLs (should not modify)
|
|
107
|
+
test('Should not modify protocol-relative URLs', () => {
|
|
108
|
+
const html = '<img src="//cdn.example.com/image.png">';
|
|
109
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
110
|
+
assert(result.includes('src="//cdn.example.com/image.png"'), 'Should keep protocol-relative URL unchanged');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Test 13: Handle empty or null HTML
|
|
114
|
+
test('Should handle empty HTML', () => {
|
|
115
|
+
const result = prepareHtml('', 'https://example.com');
|
|
116
|
+
assert.strictEqual(result, '', 'Should return empty string');
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test('Should handle null HTML', () => {
|
|
120
|
+
const result = prepareHtml(null, 'https://example.com');
|
|
121
|
+
assert.strictEqual(result, '', 'Should return empty string for null');
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Test 14: Complex real-world example
|
|
125
|
+
test('Should handle complex HTML with multiple elements', () => {
|
|
126
|
+
const html = `
|
|
127
|
+
<!DOCTYPE html>
|
|
128
|
+
<html>
|
|
129
|
+
<head>
|
|
130
|
+
<meta charset="utf-8">
|
|
131
|
+
<title>Test Page</title>
|
|
132
|
+
<style>.test { color: blue; }</style>
|
|
133
|
+
<script>console.log("test");</script>
|
|
134
|
+
</head>
|
|
135
|
+
<body>
|
|
136
|
+
<!-- Main content -->
|
|
137
|
+
<div>
|
|
138
|
+
<a href="/page1">Page 1</a>
|
|
139
|
+
<a href="https://external.com">External</a>
|
|
140
|
+
<img src="/images/pic.jpg">
|
|
141
|
+
<script>alert("inline");</script>
|
|
142
|
+
</div>
|
|
143
|
+
</body>
|
|
144
|
+
</html>
|
|
145
|
+
`;
|
|
146
|
+
const result = prepareHtml(html, 'https://example.com/test/');
|
|
147
|
+
|
|
148
|
+
// Should not contain removed elements
|
|
149
|
+
assert(!result.includes('<meta'), 'Should remove meta');
|
|
150
|
+
assert(!result.includes('<style'), 'Should remove style');
|
|
151
|
+
assert(!result.includes('<script'), 'Should remove script');
|
|
152
|
+
assert(!result.includes('<!--'), 'Should remove comments');
|
|
153
|
+
|
|
154
|
+
// Should convert relative URLs
|
|
155
|
+
assert(result.includes('href="https://example.com/page1"'), 'Should convert relative href');
|
|
156
|
+
assert(result.includes('src="https://example.com/images/pic.jpg"'), 'Should convert relative src');
|
|
157
|
+
|
|
158
|
+
// Should keep absolute URLs
|
|
159
|
+
assert(result.includes('href="https://external.com"'), 'Should keep absolute href');
|
|
160
|
+
|
|
161
|
+
// Should preserve content
|
|
162
|
+
assert(result.includes('Page 1'), 'Should preserve content');
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// Test 15: Verify script with attributes is removed
|
|
166
|
+
test('Should remove script tags with various attributes', () => {
|
|
167
|
+
const html = '<script type="text/javascript" async defer src="/app.js">console.log("test");</script>';
|
|
168
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
169
|
+
assert(!result.includes('<script'), 'Should remove script with attributes');
|
|
170
|
+
assert(!result.includes('app.js'), 'Should remove script content');
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Test 16: Remove inline style attributes
|
|
174
|
+
test('Should remove inline style attributes', () => {
|
|
175
|
+
const html = '<div style="color: red; font-size: 14px;">Content</div>';
|
|
176
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
177
|
+
assert(!result.includes('style='), 'Should remove style attribute');
|
|
178
|
+
assert(result.includes('Content'), 'Should preserve content');
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// Test 17: Remove class attributes
|
|
182
|
+
test('Should remove class attributes', () => {
|
|
183
|
+
const html = '<div class="container main-content">Text</div>';
|
|
184
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
185
|
+
assert(!result.includes('class='), 'Should remove class attribute');
|
|
186
|
+
assert(result.includes('Text'), 'Should preserve content');
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// Test 18: Remove id attributes
|
|
190
|
+
test('Should remove id attributes', () => {
|
|
191
|
+
const html = '<div id="main-section">Content</div>';
|
|
192
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
193
|
+
assert(!result.includes('id='), 'Should remove id attribute');
|
|
194
|
+
assert(result.includes('Content'), 'Should preserve content');
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Test 19: Remove data-* attributes
|
|
198
|
+
test('Should remove data-* attributes', () => {
|
|
199
|
+
const html = '<div data-id="123" data-value="test">Content</div>';
|
|
200
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
201
|
+
assert(!result.includes('data-'), 'Should remove data attributes');
|
|
202
|
+
assert(result.includes('Content'), 'Should preserve content');
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// Test 20: Remove event handler attributes
|
|
206
|
+
test('Should remove event handler attributes', () => {
|
|
207
|
+
const html = '<button onclick="handleClick()" onmouseover="hover()">Click</button>';
|
|
208
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
209
|
+
assert(!result.includes('onclick='), 'Should remove onclick');
|
|
210
|
+
assert(!result.includes('onmouseover='), 'Should remove onmouseover');
|
|
211
|
+
assert(result.includes('Click'), 'Should preserve content');
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// Test 21: Remove SVG tags
|
|
215
|
+
test('Should remove SVG tags and content', () => {
|
|
216
|
+
const html = '<div>Text</div><svg width="100" height="100"><circle cx="50" cy="50" r="40"/></svg>';
|
|
217
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
218
|
+
assert(!result.includes('<svg'), 'Should remove svg tag');
|
|
219
|
+
assert(!result.includes('circle'), 'Should remove svg content');
|
|
220
|
+
assert(result.includes('Text'), 'Should preserve content');
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
// Test 22: Remove noscript tags
|
|
224
|
+
test('Should remove noscript tags and content', () => {
|
|
225
|
+
const html = '<div>Content</div><noscript>JavaScript is disabled</noscript>';
|
|
226
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
227
|
+
assert(!result.includes('<noscript'), 'Should remove noscript tag');
|
|
228
|
+
assert(!result.includes('JavaScript is disabled'), 'Should remove noscript content');
|
|
229
|
+
assert(result.includes('Content'), 'Should preserve content');
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// Test 23: Remove link tags
|
|
233
|
+
test('Should remove link tags', () => {
|
|
234
|
+
const html = '<head><link rel="stylesheet" href="/style.css"><link rel="preload" as="script"></head>';
|
|
235
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
236
|
+
assert(!result.includes('<link'), 'Should remove link tags');
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// Test 24: Remove role attributes
|
|
240
|
+
test('Should remove role attributes', () => {
|
|
241
|
+
const html = '<nav role="navigation">Menu</nav>';
|
|
242
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
243
|
+
assert(!result.includes('role='), 'Should remove role attribute');
|
|
244
|
+
assert(result.includes('Menu'), 'Should preserve content');
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
// Test 25: Remove aria-* attributes
|
|
248
|
+
test('Should remove aria-* attributes', () => {
|
|
249
|
+
const html = '<button aria-label="Close" aria-pressed="false">X</button>';
|
|
250
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
251
|
+
assert(!result.includes('aria-'), 'Should remove aria attributes');
|
|
252
|
+
assert(result.includes('X'), 'Should preserve content');
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// Test 26: Collapse whitespace
|
|
256
|
+
test('Should collapse multiple whitespace into single space', () => {
|
|
257
|
+
const html = '<div>Line 1\n\n\n Line 2\t\t\tLine 3</div>';
|
|
258
|
+
const result = prepareHtml(html, 'https://example.com');
|
|
259
|
+
assert(!result.includes('\n\n'), 'Should remove multiple newlines');
|
|
260
|
+
assert(!result.includes(' '), 'Should remove multiple spaces');
|
|
261
|
+
assert(result.includes('Line 1'), 'Should preserve content');
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// Test 27: Comprehensive test with all removals
|
|
265
|
+
test('Should handle HTML with all types of removals', () => {
|
|
266
|
+
const html = `
|
|
267
|
+
<div class="container" id="main" style="color: blue;" data-test="value" onclick="alert()">
|
|
268
|
+
<svg width="100"><circle/></svg>
|
|
269
|
+
<script>console.log("test");</script>
|
|
270
|
+
<style>.test { color: red; }</style>
|
|
271
|
+
<noscript>Enable JS</noscript>
|
|
272
|
+
<link rel="stylesheet" href="/style.css">
|
|
273
|
+
<div role="main" aria-label="content">
|
|
274
|
+
<a href="/page">Link</a>
|
|
275
|
+
<p>Text content</p>
|
|
276
|
+
</div>
|
|
277
|
+
</div>
|
|
278
|
+
`;
|
|
279
|
+
const result = prepareHtml(html, 'https://example.com/test/');
|
|
280
|
+
|
|
281
|
+
// Should remove all code attributes
|
|
282
|
+
assert(!result.includes('class='), 'Should remove class');
|
|
283
|
+
assert(!result.includes('id='), 'Should remove id');
|
|
284
|
+
assert(!result.includes('style='), 'Should remove style');
|
|
285
|
+
assert(!result.includes('data-'), 'Should remove data attributes');
|
|
286
|
+
assert(!result.includes('onclick='), 'Should remove onclick');
|
|
287
|
+
assert(!result.includes('role='), 'Should remove role');
|
|
288
|
+
assert(!result.includes('aria-'), 'Should remove aria');
|
|
289
|
+
|
|
290
|
+
// Should remove non-content elements
|
|
291
|
+
assert(!result.includes('<svg'), 'Should remove svg');
|
|
292
|
+
assert(!result.includes('<script'), 'Should remove script');
|
|
293
|
+
assert(!result.includes('<style'), 'Should remove style');
|
|
294
|
+
assert(!result.includes('<noscript'), 'Should remove noscript');
|
|
295
|
+
assert(!result.includes('<link'), 'Should remove link');
|
|
296
|
+
|
|
297
|
+
// Should preserve content and convert URLs
|
|
298
|
+
assert(result.includes('href="https://example.com/page"'), 'Should convert relative URL');
|
|
299
|
+
assert(result.includes('Text content'), 'Should preserve text');
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
console.log('\n==================================================');
|
|
303
|
+
console.log(`โ
Tests Passed: ${testsPassed}`);
|
|
304
|
+
console.log(`โ Tests Failed: ${testsFailed}`);
|
|
305
|
+
console.log('==================================================\n');
|
|
306
|
+
|
|
307
|
+
process.exit(testsFailed > 0 ? 1 : 0);
|