jsgui3-server 0.0.138 → 0.0.140
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/AGENTS.md +87 -0
- package/README.md +12 -0
- package/docs/GUIDE_TO_AGENTIC_WORKFLOWS_BY_GROK.md +19 -0
- package/docs/advanced-usage-examples.md +1360 -0
- package/docs/agent-development-guide.md +386 -0
- package/docs/api-reference.md +916 -0
- package/docs/broken-functionality-tracker.md +285 -0
- package/docs/bundling-system-deep-dive.md +525 -0
- package/docs/cli-reference.md +393 -0
- package/docs/comprehensive-documentation.md +1403 -0
- package/docs/configuration-reference.md +808 -0
- package/docs/controls-development.md +859 -0
- package/docs/documentation-review/CURRENT_REVIEW.md +95 -0
- package/docs/function-publishers-json-apis.md +847 -0
- package/docs/getting-started-with-json.md +518 -0
- package/docs/minification-compression-sourcemaps-status.md +482 -0
- package/docs/minification-compression-sourcemaps-test-results.md +205 -0
- package/docs/publishers-guide.md +313 -0
- package/docs/resources-guide.md +615 -0
- package/docs/serve-helpers.md +406 -0
- package/docs/simple-server-api-design.md +13 -0
- package/docs/system-architecture.md +275 -0
- package/docs/troubleshooting.md +698 -0
- package/examples/json/README.md +115 -0
- package/examples/json/basic-api/README.md +345 -0
- package/examples/json/basic-api/server.js +199 -0
- package/examples/json/simple-api/README.md +125 -0
- package/examples/json/simple-api/diagnostic-report.json +73 -0
- package/examples/json/simple-api/diagnostic-test.js +433 -0
- package/examples/json/simple-api/server-debug.md +58 -0
- package/examples/json/simple-api/server.js +91 -0
- package/examples/json/simple-api/test.js +215 -0
- package/http/responders/static/Static_Route_HTTP_Responder.js +1 -2
- package/package.json +19 -8
- package/publishers/helpers/assigners/static-compressed-response-buffers/Single_Control_Webpage_Server_Static_Compressed_Response_Buffers_Assigner.js +65 -12
- package/publishers/helpers/preparers/static/bundle/Static_Routes_Responses_Webpage_Bundle_Preparer.js +6 -1
- package/publishers/http-function-publisher.js +59 -38
- package/publishers/http-webpage-publisher.js +48 -1
- package/resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild.js +38 -146
- package/resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild.js +54 -5
- package/resources/processors/bundlers/js/esbuild/Core_JS_Single_File_Minifying_Bundler_Using_ESBuild.js +36 -4
- package/serve-factory.js +36 -9
- package/server.js +10 -4
- package/test-report.json +0 -0
- package/tests/README.md +250 -0
- package/tests/assigners.test.js +316 -0
- package/tests/bundlers.test.js +329 -0
- package/tests/configuration-validation.test.js +530 -0
- package/tests/content-analysis.test.js +641 -0
- package/tests/end-to-end.test.js +496 -0
- package/tests/error-handling.test.js +746 -0
- package/tests/performance.test.js +653 -0
- package/tests/publishers.test.js +395 -0
- package/tests/temp_invalid.js +7 -0
- package/tests/temp_invalid_utf8.js +1 -0
- package/tests/temp_malformed.js +10 -0
- package/tests/test-runner.js +261 -0
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
const assert = require('assert');
|
|
2
|
+
const { describe, it, before, after } = require('mocha');
|
|
3
|
+
const http = require('http');
|
|
4
|
+
const fs = require('fs').promises;
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
// Import server and related classes
|
|
8
|
+
const Server = require('../module');
|
|
9
|
+
|
|
10
|
+
describe('End-to-End Integration Tests', function() {
|
|
11
|
+
this.timeout(30000); // Allow more time for server startup and requests
|
|
12
|
+
|
|
13
|
+
let server;
|
|
14
|
+
let serverPort = 3001; // Use a different port for testing
|
|
15
|
+
let testControl;
|
|
16
|
+
|
|
17
|
+
before(async function() {
|
|
18
|
+
// Create a test control class
|
|
19
|
+
testControl = class TestControl {
|
|
20
|
+
constructor(spec) {
|
|
21
|
+
this.context = spec.context;
|
|
22
|
+
this.head = {
|
|
23
|
+
add: function(element) {
|
|
24
|
+
// Mock add method
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
this.body = {
|
|
28
|
+
add: function(element) {
|
|
29
|
+
// Mock add method
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
active() {
|
|
35
|
+
// Mock activation
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
all_html_render() {
|
|
39
|
+
return Promise.resolve(`<!DOCTYPE html>
|
|
40
|
+
<html>
|
|
41
|
+
<head>
|
|
42
|
+
<title>Test Page</title>
|
|
43
|
+
<script src="/js/js.js"></script>
|
|
44
|
+
</head>
|
|
45
|
+
<body>
|
|
46
|
+
<div id="test-control">
|
|
47
|
+
<h1>Test Control</h1>
|
|
48
|
+
<p>This is a test control with embedded CSS and JS.</p>
|
|
49
|
+
<button onclick="testFunction()">Test Button</button>
|
|
50
|
+
</div>
|
|
51
|
+
</body>
|
|
52
|
+
</html>`);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// Add CSS and JS to the control class
|
|
57
|
+
testControl.css = `
|
|
58
|
+
.test-control {
|
|
59
|
+
background-color: #f0f0f0;
|
|
60
|
+
padding: 20px;
|
|
61
|
+
border: 1px solid #ccc;
|
|
62
|
+
font-family: Arial, sans-serif;
|
|
63
|
+
}
|
|
64
|
+
.test-control h1 {
|
|
65
|
+
color: #333;
|
|
66
|
+
margin-bottom: 10px;
|
|
67
|
+
}
|
|
68
|
+
.test-control p {
|
|
69
|
+
color: #666;
|
|
70
|
+
line-height: 1.5;
|
|
71
|
+
}
|
|
72
|
+
`;
|
|
73
|
+
|
|
74
|
+
testControl.js = `
|
|
75
|
+
// Test JavaScript with CSS embedding
|
|
76
|
+
const css = \`${testControl.css}\`;
|
|
77
|
+
|
|
78
|
+
// Add CSS to document
|
|
79
|
+
const style = document.createElement('style');
|
|
80
|
+
style.textContent = css;
|
|
81
|
+
document.head.appendChild(style);
|
|
82
|
+
|
|
83
|
+
// Test function
|
|
84
|
+
function testFunction() {
|
|
85
|
+
console.log('Test function called');
|
|
86
|
+
alert('Test function executed successfully!');
|
|
87
|
+
return 'test result';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Initialize when DOM is ready
|
|
91
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
92
|
+
console.log('Test control initialized');
|
|
93
|
+
const testDiv = document.getElementById('test-control');
|
|
94
|
+
if (testDiv) {
|
|
95
|
+
testDiv.style.borderColor = '#007bff';
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Export for testing
|
|
100
|
+
window.TestControl = { testFunction };
|
|
101
|
+
`;
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
after(async function() {
|
|
105
|
+
// Clean up server
|
|
106
|
+
if (server) {
|
|
107
|
+
await server.stop();
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('Full Server Integration with Minification and Compression', function() {
|
|
112
|
+
it('should serve webpage with minified and compressed JavaScript', async function() {
|
|
113
|
+
// Start server with minification and compression enabled
|
|
114
|
+
server = new Server();
|
|
115
|
+
await server.serve({
|
|
116
|
+
ctrl: testControl,
|
|
117
|
+
port: serverPort,
|
|
118
|
+
debug: false, // Enable minification
|
|
119
|
+
bundler: {
|
|
120
|
+
minify: {
|
|
121
|
+
enabled: true,
|
|
122
|
+
level: 'normal'
|
|
123
|
+
},
|
|
124
|
+
compression: {
|
|
125
|
+
enabled: true,
|
|
126
|
+
algorithms: ['gzip', 'br']
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Wait for server to be ready
|
|
132
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
133
|
+
|
|
134
|
+
// Test gzip compressed JavaScript
|
|
135
|
+
const jsResponse = await makeRequest(`http://localhost:${serverPort}/js/js.js`, {
|
|
136
|
+
'Accept-Encoding': 'gzip'
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
assert.strictEqual(jsResponse.statusCode, 200);
|
|
140
|
+
assert.strictEqual(jsResponse.headers['content-encoding'], 'gzip');
|
|
141
|
+
assert(jsResponse.headers['content-type'].includes('javascript'));
|
|
142
|
+
|
|
143
|
+
// Verify the response is actually compressed (should be smaller than original)
|
|
144
|
+
const originalSize = Buffer.from(testControl.js, 'utf8').length;
|
|
145
|
+
const compressedSize = jsResponse.body.length;
|
|
146
|
+
assert(compressedSize < originalSize, 'JavaScript should be compressed');
|
|
147
|
+
|
|
148
|
+
// Test brotli compressed JavaScript
|
|
149
|
+
const brJsResponse = await makeRequest(`http://localhost:${serverPort}/js/js.js`, {
|
|
150
|
+
'Accept-Encoding': 'br'
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
assert.strictEqual(brJsResponse.statusCode, 200);
|
|
154
|
+
assert.strictEqual(brJsResponse.headers['content-encoding'], 'br');
|
|
155
|
+
|
|
156
|
+
// Brotli should generally be smaller than gzip for text
|
|
157
|
+
assert(brJsResponse.body.length <= jsResponse.body.length,
|
|
158
|
+
'Brotli should be at least as good as gzip');
|
|
159
|
+
|
|
160
|
+
// Stop server
|
|
161
|
+
await server.stop();
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('should serve webpage with sourcemaps in debug mode', async function() {
|
|
165
|
+
// Start server in debug mode
|
|
166
|
+
server = new Server();
|
|
167
|
+
await server.serve({
|
|
168
|
+
ctrl: testControl,
|
|
169
|
+
port: serverPort,
|
|
170
|
+
debug: true, // Enable sourcemaps
|
|
171
|
+
bundler: {
|
|
172
|
+
sourcemaps: {
|
|
173
|
+
enabled: true,
|
|
174
|
+
format: 'inline'
|
|
175
|
+
},
|
|
176
|
+
compression: {
|
|
177
|
+
enabled: true,
|
|
178
|
+
algorithms: ['gzip']
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Wait for server to be ready
|
|
184
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
185
|
+
|
|
186
|
+
// Test JavaScript with sourcemaps
|
|
187
|
+
const jsResponse = await makeRequest(`http://localhost:${serverPort}/js/js.js`, {
|
|
188
|
+
'Accept-Encoding': 'gzip'
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
assert.strictEqual(jsResponse.statusCode, 200);
|
|
192
|
+
assert.strictEqual(jsResponse.headers['content-encoding'], 'gzip');
|
|
193
|
+
|
|
194
|
+
// Decompress to check for sourcemap
|
|
195
|
+
const zlib = require('zlib');
|
|
196
|
+
const decompressed = zlib.gunzipSync(jsResponse.body).toString();
|
|
197
|
+
assert(decompressed.includes('//# sourceMappingURL='), 'Debug mode should include inline sourcemaps');
|
|
198
|
+
|
|
199
|
+
// Stop server
|
|
200
|
+
await server.stop();
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it('should serve compressed CSS', async function() {
|
|
204
|
+
// Start server with compression
|
|
205
|
+
server = new Server();
|
|
206
|
+
await server.serve({
|
|
207
|
+
ctrl: testControl,
|
|
208
|
+
port: serverPort,
|
|
209
|
+
debug: false,
|
|
210
|
+
bundler: {
|
|
211
|
+
compression: {
|
|
212
|
+
enabled: true,
|
|
213
|
+
algorithms: ['gzip', 'br']
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// Wait for server to be ready
|
|
219
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
220
|
+
|
|
221
|
+
// Test gzip compressed CSS
|
|
222
|
+
const cssResponse = await makeRequest(`http://localhost:${serverPort}/css/css.css`, {
|
|
223
|
+
'Accept-Encoding': 'gzip'
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
assert.strictEqual(cssResponse.statusCode, 200);
|
|
227
|
+
assert.strictEqual(cssResponse.headers['content-encoding'], 'gzip');
|
|
228
|
+
assert(cssResponse.headers['content-type'].includes('css'));
|
|
229
|
+
|
|
230
|
+
// Verify CSS content is compressed
|
|
231
|
+
const originalCssSize = Buffer.from(testControl.css, 'utf8').length;
|
|
232
|
+
const compressedCssSize = cssResponse.body.length;
|
|
233
|
+
assert(compressedCssSize < originalCssSize, 'CSS should be compressed');
|
|
234
|
+
|
|
235
|
+
// Stop server
|
|
236
|
+
await server.stop();
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it('should serve HTML without compression when below threshold', async function() {
|
|
240
|
+
// Start server with high compression threshold
|
|
241
|
+
server = new Server();
|
|
242
|
+
await server.serve({
|
|
243
|
+
ctrl: testControl,
|
|
244
|
+
port: serverPort,
|
|
245
|
+
debug: false,
|
|
246
|
+
bundler: {
|
|
247
|
+
compression: {
|
|
248
|
+
enabled: true,
|
|
249
|
+
threshold: 10000 // Very high threshold
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// Wait for server to be ready
|
|
255
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
256
|
+
|
|
257
|
+
// Test HTML (should not be compressed due to threshold)
|
|
258
|
+
const htmlResponse = await makeRequest(`http://localhost:${serverPort}/`, {
|
|
259
|
+
'Accept-Encoding': 'gzip'
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
assert.strictEqual(htmlResponse.statusCode, 200);
|
|
263
|
+
assert(!htmlResponse.headers['content-encoding'], 'HTML should not be compressed due to threshold');
|
|
264
|
+
assert(htmlResponse.headers['content-type'].includes('html'));
|
|
265
|
+
|
|
266
|
+
// Stop server
|
|
267
|
+
await server.stop();
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('should handle different minification levels', async function() {
|
|
271
|
+
const minificationLevels = ['conservative', 'normal', 'aggressive'];
|
|
272
|
+
|
|
273
|
+
for (const level of minificationLevels) {
|
|
274
|
+
// Start server with specific minification level
|
|
275
|
+
server = new Server();
|
|
276
|
+
await server.serve({
|
|
277
|
+
ctrl: testControl,
|
|
278
|
+
port: serverPort,
|
|
279
|
+
debug: false,
|
|
280
|
+
bundler: {
|
|
281
|
+
minify: {
|
|
282
|
+
enabled: true,
|
|
283
|
+
level: level
|
|
284
|
+
},
|
|
285
|
+
compression: {
|
|
286
|
+
enabled: false // Disable compression for size comparison
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
// Wait for server to be ready
|
|
292
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
293
|
+
|
|
294
|
+
// Test JavaScript
|
|
295
|
+
const jsResponse = await makeRequest(`http://localhost:${serverPort}/js/js.js`);
|
|
296
|
+
|
|
297
|
+
assert.strictEqual(jsResponse.statusCode, 200);
|
|
298
|
+
assert(!jsResponse.headers['content-encoding'], 'Should not be compressed');
|
|
299
|
+
|
|
300
|
+
// Verify minification occurred (should be smaller than original)
|
|
301
|
+
const originalSize = Buffer.from(testControl.js, 'utf8').length;
|
|
302
|
+
const minifiedSize = jsResponse.body.length;
|
|
303
|
+
assert(minifiedSize < originalSize, `JavaScript should be minified with ${level} level`);
|
|
304
|
+
|
|
305
|
+
// Stop server
|
|
306
|
+
await server.stop();
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it('should serve identical content with identity encoding when compression disabled', async function() {
|
|
311
|
+
// Start server with compression disabled
|
|
312
|
+
server = new Server();
|
|
313
|
+
await server.serve({
|
|
314
|
+
ctrl: testControl,
|
|
315
|
+
port: serverPort,
|
|
316
|
+
debug: false,
|
|
317
|
+
bundler: {
|
|
318
|
+
compression: {
|
|
319
|
+
enabled: false
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
// Wait for server to be ready
|
|
325
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
326
|
+
|
|
327
|
+
// Test with gzip request but compression disabled
|
|
328
|
+
const jsResponse = await makeRequest(`http://localhost:${serverPort}/js/js.js`, {
|
|
329
|
+
'Accept-Encoding': 'gzip'
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
assert.strictEqual(jsResponse.statusCode, 200);
|
|
333
|
+
assert(!jsResponse.headers['content-encoding'], 'Should not have content-encoding when compression disabled');
|
|
334
|
+
|
|
335
|
+
// Stop server
|
|
336
|
+
await server.stop();
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it('should handle multiple concurrent requests', async function() {
|
|
340
|
+
// Start server
|
|
341
|
+
server = new Server();
|
|
342
|
+
await server.serve({
|
|
343
|
+
ctrl: testControl,
|
|
344
|
+
port: serverPort,
|
|
345
|
+
debug: false,
|
|
346
|
+
bundler: {
|
|
347
|
+
compression: {
|
|
348
|
+
enabled: true,
|
|
349
|
+
algorithms: ['gzip']
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
// Wait for server to be ready
|
|
355
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
356
|
+
|
|
357
|
+
// Make multiple concurrent requests
|
|
358
|
+
const requests = [];
|
|
359
|
+
for (let i = 0; i < 5; i++) {
|
|
360
|
+
requests.push(makeRequest(`http://localhost:${serverPort}/js/js.js`, {
|
|
361
|
+
'Accept-Encoding': 'gzip'
|
|
362
|
+
}));
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const responses = await Promise.all(requests);
|
|
366
|
+
|
|
367
|
+
// All requests should succeed
|
|
368
|
+
responses.forEach(response => {
|
|
369
|
+
assert.strictEqual(response.statusCode, 200);
|
|
370
|
+
assert.strictEqual(response.headers['content-encoding'], 'gzip');
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
// Stop server
|
|
374
|
+
await server.stop();
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
it('should serve correct content types', async function() {
|
|
378
|
+
// Start server
|
|
379
|
+
server = new Server();
|
|
380
|
+
await server.serve({
|
|
381
|
+
ctrl: testControl,
|
|
382
|
+
port: serverPort,
|
|
383
|
+
debug: false
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
// Wait for server to be ready
|
|
387
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
388
|
+
|
|
389
|
+
// Test different content types
|
|
390
|
+
const tests = [
|
|
391
|
+
{ path: '/', expectedType: 'html' },
|
|
392
|
+
{ path: '/js/js.js', expectedType: 'javascript' },
|
|
393
|
+
{ path: '/css/css.css', expectedType: 'css' }
|
|
394
|
+
];
|
|
395
|
+
|
|
396
|
+
for (const test of tests) {
|
|
397
|
+
const response = await makeRequest(`http://localhost:${serverPort}${test.path}`);
|
|
398
|
+
assert.strictEqual(response.statusCode, 200);
|
|
399
|
+
assert(response.headers['content-type'].includes(test.expectedType),
|
|
400
|
+
`Should serve correct content type for ${test.path}`);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Stop server
|
|
404
|
+
await server.stop();
|
|
405
|
+
});
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
describe('Error Handling in End-to-End Scenarios', function() {
|
|
409
|
+
it('should handle invalid configuration gracefully', async function() {
|
|
410
|
+
// Try to start server with invalid configuration
|
|
411
|
+
server = new Server();
|
|
412
|
+
|
|
413
|
+
try {
|
|
414
|
+
await server.serve({
|
|
415
|
+
ctrl: testControl,
|
|
416
|
+
port: serverPort,
|
|
417
|
+
bundler: {
|
|
418
|
+
compression: {
|
|
419
|
+
enabled: 'invalid' // Invalid boolean
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
assert.fail('Should have thrown error for invalid configuration');
|
|
424
|
+
} catch (error) {
|
|
425
|
+
assert(error, 'Should throw error for invalid configuration');
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
it('should handle server port conflicts', async function() {
|
|
430
|
+
// Start first server
|
|
431
|
+
const server1 = new Server();
|
|
432
|
+
await server1.serve({
|
|
433
|
+
ctrl: testControl,
|
|
434
|
+
port: serverPort,
|
|
435
|
+
debug: false
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
// Try to start second server on same port
|
|
439
|
+
const server2 = new Server();
|
|
440
|
+
try {
|
|
441
|
+
await server2.serve({
|
|
442
|
+
ctrl: testControl,
|
|
443
|
+
port: serverPort, // Same port
|
|
444
|
+
debug: false
|
|
445
|
+
});
|
|
446
|
+
assert.fail('Should have failed to start server on occupied port');
|
|
447
|
+
} catch (error) {
|
|
448
|
+
assert(error, 'Should throw error for port conflict');
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Clean up
|
|
452
|
+
await server1.stop();
|
|
453
|
+
});
|
|
454
|
+
});
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
// Helper function to make HTTP requests
|
|
458
|
+
function makeRequest(url, headers = {}) {
|
|
459
|
+
return new Promise((resolve, reject) => {
|
|
460
|
+
const parsedUrl = new URL(url);
|
|
461
|
+
const options = {
|
|
462
|
+
hostname: parsedUrl.hostname,
|
|
463
|
+
port: parsedUrl.port,
|
|
464
|
+
path: parsedUrl.pathname,
|
|
465
|
+
method: 'GET',
|
|
466
|
+
headers: {
|
|
467
|
+
'User-Agent': 'JSGUI3-Test/1.0',
|
|
468
|
+
...headers
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
const req = http.request(options, (res) => {
|
|
473
|
+
let body = Buffer.alloc(0);
|
|
474
|
+
|
|
475
|
+
res.on('data', (chunk) => {
|
|
476
|
+
body = Buffer.concat([body, chunk]);
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
res.on('end', () => {
|
|
480
|
+
resolve({
|
|
481
|
+
statusCode: res.statusCode,
|
|
482
|
+
headers: res.headers,
|
|
483
|
+
body: body
|
|
484
|
+
});
|
|
485
|
+
});
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
req.on('error', reject);
|
|
489
|
+
req.setTimeout(5000, () => {
|
|
490
|
+
req.destroy();
|
|
491
|
+
reject(new Error('Request timeout'));
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
req.end();
|
|
495
|
+
});
|
|
496
|
+
}
|