webhoster 0.3.0 → 0.3.1

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/package.json CHANGED
@@ -50,5 +50,5 @@
50
50
  "posttestall": "c8 report"
51
51
  },
52
52
  "type": "module",
53
- "version": "0.3.0"
53
+ "version": "0.3.1"
54
54
  }
@@ -0,0 +1,40 @@
1
+ import http from 'node:http';
2
+ import * as starter from '../templates/starter.js';
3
+
4
+ async function run() {
5
+ const throwingMiddleware = [() => { throw new Error('brew failed'); }];
6
+ const teapotHandler = {
7
+ onError(transaction) {
8
+ transaction.response.status = 418;
9
+ return "I'm a teapot";
10
+ },
11
+ };
12
+
13
+ const listener = await starter.start({ middleware: throwingMiddleware, errorHandlers: [teapotHandler], host: '127.0.0.1', port: 0 });
14
+ try {
15
+ const addr = listener.httpServer.address();
16
+ const port = typeof addr === 'object' ? addr.port : addr;
17
+ const result = await new Promise((resolve, reject) => {
18
+ const req = http.get({ port, path: '/' }, (res) => {
19
+ let data = '';
20
+ res.setEncoding('utf8');
21
+ res.on('data', (c) => { data += c; });
22
+ res.on('end', () => resolve({ status: res.statusCode, body: data }));
23
+ });
24
+ req.on('error', reject);
25
+ });
26
+
27
+ // Print a concise confirmation
28
+ // (CI will show this output in the terminal)
29
+ // eslint-disable-next-line no-console
30
+ console.log('TEAPOT_CHECK_RESULT', JSON.stringify(result));
31
+ } finally {
32
+ await listener.stopHttpServer();
33
+ }
34
+ }
35
+
36
+ run().catch((err) => {
37
+ // eslint-disable-next-line no-console
38
+ console.error('check-teapot failed', err);
39
+ process.exit(1);
40
+ });
@@ -32,7 +32,9 @@ export async function start(options) {
32
32
  // Push by reference to allow post modification
33
33
  HttpHandler.defaultInstance.middleware.push(options.middleware);
34
34
  }
35
- if (!options.errorHandlers) {
35
+ if (options.errorHandlers) {
36
+ HttpHandler.defaultInstance.errorHandlers.push(...options.errorHandlers);
37
+ } else {
36
38
  HttpHandler.defaultInstance.errorHandlers.push(
37
39
  {
38
40
  onError() {
@@ -0,0 +1,47 @@
1
+ import test from 'ava';
2
+ import http from 'node:http';
3
+ import HttpListener from '../../helpers/HttpListener.js';
4
+ import HttpHandler from '../../lib/HttpHandler.js';
5
+ import * as starter from '../../templates/starter.js';
6
+
7
+ test.serial('custom error handler returns 418 I\'m a teapot', async (t) => {
8
+ const handler = HttpHandler.defaultInstance;
9
+ const listener = HttpListener.defaultInstance;
10
+
11
+ const mwLen = handler.middleware.length;
12
+ const ehLen = handler.errorHandlers.length;
13
+
14
+ const throwingMiddleware = [() => { throw new Error('brew failed'); }];
15
+ const teapotHandler = {
16
+ onError(transaction) {
17
+ // set custom status and body
18
+ transaction.response.status = 418;
19
+ return "I'm a teapot";
20
+ },
21
+ };
22
+
23
+ await starter.start({ middleware: throwingMiddleware, errorHandlers: [teapotHandler], host: '127.0.0.1', port: 0 });
24
+
25
+ t.truthy(listener.httpServer, 'server started');
26
+ const addr = listener.httpServer.address();
27
+ t.truthy(addr && addr.port, 'server bound');
28
+
29
+ const result = await new Promise((resolve, reject) => {
30
+ const req = http.get({ port: addr.port, path: '/' }, (res) => {
31
+ let data = '';
32
+ res.setEncoding('utf8');
33
+ res.on('data', (chunk) => { data += chunk; });
34
+ res.on('end', () => resolve({ status: res.statusCode, body: data }));
35
+ });
36
+ req.on('error', reject);
37
+ });
38
+
39
+ t.is(result.status, 418);
40
+ t.true(result.body.includes("teapot"));
41
+
42
+ await listener.stopHttpServer();
43
+
44
+ // restore global handler state
45
+ handler.middleware.splice(mwLen);
46
+ handler.errorHandlers.splice(ehLen);
47
+ });
@@ -82,9 +82,9 @@ test.serial('starter.start respects provided errorHandlers and pushes middleware
82
82
  const lastMw = handler.middleware.at(-1);
83
83
  t.is(lastMw, customMiddleware);
84
84
 
85
- // The implementation does not automatically append provided `errorHandlers`;
86
- // it only avoids adding the default when `options.errorHandlers` is supplied.
87
- t.is(handler.errorHandlers.length, ehLength);
85
+ // Provided errorHandlers are appended to the handler.
86
+ t.is(handler.errorHandlers.length, ehLength + customHandlers.length);
87
+ t.is(handler.errorHandlers.at(-1), customHandlers.at(-1));
88
88
 
89
89
  await listener.stopHttpServer();
90
90