kempo-server 1.6.1 → 1.6.3

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.
@@ -3,72 +3,72 @@ import createResponseWrapper from '../src/responseWrapper.js';
3
3
 
4
4
  export default {
5
5
  'status and set/get headers and type': async ({pass, fail}) => {
6
- try {
7
- const res = createMockRes();
8
- const w = createResponseWrapper(res);
9
- w.status(201).set('X-Test', '1').type('json');
10
- if(res.statusCode !== 201) return fail('status');
11
- if(res.getHeader('X-Test') !== '1') return fail('set/get');
12
- if(res.getHeader('Content-Type') !== 'application/json') return fail('type');
13
- pass('status+headers+type');
14
- } catch(e){ fail(e.message); }
6
+ const res = createMockRes();
7
+ const w = createResponseWrapper(res);
8
+ w.status(201).set('X-Test', '1').type('json');
9
+
10
+ if(res.statusCode !== 201) return fail('status');
11
+ if(res.getHeader('X-Test') !== '1') return fail('set/get');
12
+ if(res.getHeader('Content-Type') !== 'application/json') return fail('type');
13
+
14
+ pass('status+headers+type');
15
15
  },
16
16
  'json sends and prevents further changes': async ({pass, fail}) => {
17
- try {
18
- const res = createMockRes();
19
- const w = createResponseWrapper(res);
20
- w.json({a: 1});
21
- if(!res.isEnded()) return fail('ended');
22
- try { w.set('X', 'y'); fail('should not set after send'); } catch(_){ /* ok */ }
23
- pass('json');
24
- } catch(e){ fail(e.message); }
17
+ const res = createMockRes();
18
+ const w = createResponseWrapper(res);
19
+ w.json({a: 1});
20
+
21
+ if(!res.isEnded()) return fail('ended');
22
+
23
+ try { w.set('X', 'y'); fail('should not set after send'); } catch(_){ /* ok */ }
24
+
25
+ pass('json');
25
26
  },
26
27
  'send handles string, object, buffer and null': async ({pass, fail}) => {
27
- try {
28
- const res1 = createMockRes();
29
- createResponseWrapper(res1).send('hello');
30
- // Content-Type defaults to text/html for string when not set
31
- if(res1.getHeader('Content-Type') !== 'text/html') return fail('string content-type');
32
- if(res1.getBody().toString() !== 'hello') return fail('string body');
28
+ const res1 = createMockRes();
29
+ createResponseWrapper(res1).send('hello');
30
+ // Content-Type defaults to text/html for string when not set
31
+ if(res1.getHeader('Content-Type') !== 'text/html') return fail('string content-type');
32
+ if(res1.getBody().toString() !== 'hello') return fail('string body');
33
33
 
34
- const res2 = createMockRes();
35
- createResponseWrapper(res2).send({a:1});
36
- if(res2.getHeader('Content-Type') !== 'application/json') return fail('object content-type');
34
+ const res2 = createMockRes();
35
+ createResponseWrapper(res2).send({a:1});
36
+ if(res2.getHeader('Content-Type') !== 'application/json') return fail('object content-type');
37
37
 
38
- const res3 = createMockRes();
39
- const buf = Buffer.from('abc');
40
- createResponseWrapper(res3).send(buf);
41
- const body3 = res3.getBody().toString();
42
- if(!body3.includes('"data"')) return fail('buffer equal');
38
+ const res3 = createMockRes();
39
+ const buf = Buffer.from('abc');
40
+ createResponseWrapper(res3).send(buf);
41
+ const body3 = res3.getBody().toString();
42
+ if(!body3.includes('"data"')) return fail('buffer equal');
43
43
 
44
- const res4 = createMockRes();
45
- createResponseWrapper(res4).send(null);
46
- if(!res4.isEnded()) return fail('null ended');
47
- pass('send variants');
48
- } catch(e){ fail(e.message); }
44
+ const res4 = createMockRes();
45
+ createResponseWrapper(res4).send(null);
46
+ if(!res4.isEnded()) return fail('null ended');
47
+
48
+ pass('send variants');
49
49
  },
50
50
  'html and text helpers': async ({pass, fail}) => {
51
- try {
52
- const r1 = createMockRes();
53
- createResponseWrapper(r1).html('<h1>Ok</h1>');
54
- if(r1.getHeader('Content-Type') !== 'text/html') return fail('html type');
51
+ const r1 = createMockRes();
52
+ createResponseWrapper(r1).html('<h1>Ok</h1>');
53
+ if(r1.getHeader('Content-Type') !== 'text/html') return fail('html type');
55
54
 
56
- const r2 = createMockRes();
57
- createResponseWrapper(r2).text('plain');
58
- if(r2.getHeader('Content-Type') !== 'text/plain') return fail('text type');
59
- pass('helpers');
60
- } catch(e){ fail(e.message); }
55
+ const r2 = createMockRes();
56
+ createResponseWrapper(r2).text('plain');
57
+ if(r2.getHeader('Content-Type') !== 'text/plain') return fail('text type');
58
+
59
+ pass('helpers');
61
60
  },
62
61
  'redirect and cookies': async ({pass, fail}) => {
63
- try {
64
- const r = createMockRes();
65
- const w = createResponseWrapper(r);
66
- w.cookie('a', 'b', {httpOnly: true, path: '/'});
67
- const cookies = parseCookies(r.getHeader('Set-Cookie'));
68
- if(!(cookies.length === 1 && cookies[0].includes('a=b'))) return fail('cookie added');
69
- w.redirect('/next', 301);
70
- if(!(r.statusCode === 301 && r.getHeader('Location') === '/next')) return fail('redirect');
71
- pass('redirect+cookie');
72
- } catch(e){ fail(e.message); }
62
+ const r = createMockRes();
63
+ const w = createResponseWrapper(r);
64
+ w.cookie('a', 'b', {httpOnly: true, path: '/'});
65
+ const cookies = parseCookies(r.getHeader('Set-Cookie'));
66
+
67
+ if(!(cookies.length === 1 && cookies[0].includes('a=b'))) return fail('cookie added');
68
+
69
+ w.redirect('/next', 301);
70
+ if(!(r.statusCode === 301 && r.getHeader('Location') === '/next')) return fail('redirect');
71
+
72
+ pass('redirect+cookie');
73
73
  }
74
74
  };
@@ -4,43 +4,55 @@ import router from '../src/router.js';
4
4
 
5
5
  export default {
6
6
  'built-in middleware can be configured on router': async ({pass, fail}) => {
7
- try {
8
- await withTempDir(async (dir) => {
9
- await write(dir, '.config.json', JSON.stringify({
10
- middleware: {
11
- cors: {enabled: true, origin: '*', methods: ['GET'], headers: ['X']},
12
- compression: {enabled: true, threshold: 1},
13
- rateLimit: {enabled: true, maxRequests: 1, windowMs: 1000, message: 'Too many'},
14
- security: {enabled: true, headers: {'X-Test':'1'}},
15
- logging: {enabled: true, includeUserAgent: false, includeResponseTime: true}
16
- }
17
- }));
18
- await write(dir, 'index.html', 'hello world');
19
- const prev = process.cwd();
20
- process.chdir(dir);
21
- const flags = {root: '.', logging: 0, scan: false};
22
- const handler = await router(flags, () => {});
23
- const server = http.createServer(handler);
24
- const port = randomPort();
25
- await new Promise(r => server.listen(port, r));
26
- await new Promise(r => setTimeout(r, 50));
27
- try {
28
- const {get} = await import('http');
29
- const one = await new Promise((res)=>{
30
- get(`http://localhost:${port}/index.html`, {headers: {'accept-encoding': 'gzip'}}, r =>{
31
- const chunks = []; r.on('data', c => chunks.push(c)); r.on('end', ()=> res({r, body: Buffer.concat(chunks)}));
32
- });
33
- });
34
- if(one.r.statusCode !== 200) return fail('first ok');
35
- const two = await new Promise((res)=>{
36
- get(`http://localhost:${port}/index.html`, r =>{
37
- const chunks = []; r.on('data', c => chunks.push(c)); r.on('end', ()=> res({r, body: Buffer.concat(chunks)}));
38
- });
39
- });
40
- if(two.r.statusCode !== 429) return fail('rate limited');
41
- } finally { server.close(); process.chdir(prev); }
7
+ await withTempDir(async (dir) => {
8
+ await write(dir, '.config.json', JSON.stringify({
9
+ middleware: {
10
+ cors: {enabled: true, origin: '*', methods: ['GET'], headers: ['X']},
11
+ compression: {enabled: true, threshold: 1},
12
+ rateLimit: {enabled: true, maxRequests: 1, windowMs: 1000, message: 'Too many'},
13
+ security: {enabled: true, headers: {'X-Test':'1'}},
14
+ logging: {enabled: true, includeUserAgent: false, includeResponseTime: true}
15
+ }
16
+ }));
17
+ await write(dir, 'index.html', 'hello world');
18
+ const prev = process.cwd();
19
+ process.chdir(dir);
20
+ const flags = {root: '.', logging: 0, scan: false};
21
+ const handler = await router(flags, () => {});
22
+ const server = http.createServer(handler);
23
+ const port = randomPort();
24
+ await new Promise(r => server.listen(port, r));
25
+ await new Promise(r => setTimeout(r, 50));
26
+
27
+ const {get} = await import('http');
28
+ const one = await new Promise((res)=>{
29
+ get(`http://localhost:${port}/index.html`, {headers: {'accept-encoding': 'gzip'}}, r =>{
30
+ const chunks = []; r.on('data', c => chunks.push(c)); r.on('end', ()=> res({r, body: Buffer.concat(chunks)}));
31
+ });
42
32
  });
43
- pass('router middleware');
44
- } catch(e){ fail(e.message); }
33
+
34
+ if(one.r.statusCode !== 200) {
35
+ server.close();
36
+ process.chdir(prev);
37
+ return fail('first ok');
38
+ }
39
+
40
+ const two = await new Promise((res)=>{
41
+ get(`http://localhost:${port}/index.html`, r =>{
42
+ const chunks = []; r.on('data', c => chunks.push(c)); r.on('end', ()=> res({r, body: Buffer.concat(chunks)}));
43
+ });
44
+ });
45
+
46
+ if(two.r.statusCode !== 429) {
47
+ server.close();
48
+ process.chdir(prev);
49
+ return fail('rate limited');
50
+ }
51
+
52
+ server.close();
53
+ process.chdir(prev);
54
+ });
55
+
56
+ pass('router middleware');
45
57
  }
46
58
  };
@@ -5,86 +5,104 @@ import router from '../src/router.js';
5
5
  import defaultConfig from '../src/defaultConfig.js';
6
6
 
7
7
  export default {
8
- 'serves static files and 404s unknown': async ({pass, fail, log}) => {
9
- try {
10
- await withTempDir(async (dir) => {
11
- await write(dir, 'index.html', '<h1>Home</h1>');
12
- const prev = process.cwd();
13
- process.chdir(dir);
14
- const flags = {root: '.', logging: 0, scan: false};
15
- const logFn = () => {};
16
- const handler = await router(flags, logFn);
17
- const server = http.createServer(handler);
18
- const port = randomPort();
19
- await new Promise(r => server.listen(port, r));
20
- await new Promise(r => setTimeout(r, 50));
21
- try {
22
- const ok = await httpGet(`http://localhost:${port}/index.html`);
23
- log('ok status: ' + ok.res.statusCode);
24
- if(ok.res.statusCode !== 200) throw new Error('static 200');
25
- const miss = await httpGet(`http://localhost:${port}/nope`);
26
- log('miss status: ' + miss.res.statusCode);
27
- if(miss.res.statusCode !== 404) throw new Error('404');
28
- } finally {
29
- server.close();
8
+ 'serves static files and 404s unknown': async ({pass, fail}) => {
9
+ await withTempDir(async (dir) => {
10
+ await write(dir, 'index.html', '<h1>Home</h1>');
11
+ const prev = process.cwd();
12
+ process.chdir(dir);
13
+ const flags = {root: '.', logging: 0, scan: false};
14
+ const logFn = () => {};
15
+ const handler = await router(flags, logFn);
16
+ const server = http.createServer(handler);
17
+ const port = randomPort();
18
+ await new Promise(r => server.listen(port, r));
19
+ await new Promise(r => setTimeout(r, 50));
20
+
21
+ const ok = await httpGet(`http://localhost:${port}/index.html`);
22
+ if(ok.res.statusCode !== 200) {
23
+ server.close();
24
+ process.chdir(prev);
25
+ return fail('static 200');
26
+ }
27
+
28
+ const miss = await httpGet(`http://localhost:${port}/nope`);
29
+ if(miss.res.statusCode !== 404) {
30
+ server.close();
31
+ process.chdir(prev);
32
+ return fail('404');
33
+ }
34
+
35
+ server.close();
30
36
  process.chdir(prev);
31
- }
32
- });
33
- pass('static + 404');
34
- } catch(e){ fail(e.message); }
37
+ });
38
+ pass('static + 404');
35
39
  },
36
- 'rescan on 404 when enabled and not blacklisted': async ({pass, fail, log}) => {
37
- try {
38
- await withTempDir(async (dir) => {
39
- const prev = process.cwd();
40
- process.chdir(dir);
41
- const flags = {root: '.', logging: 0, scan: true};
42
- const handler = await router(flags, log);
43
- const server = http.createServer(handler);
44
- const port = randomPort();
45
- await new Promise(r => server.listen(port, r));
46
- await new Promise(r => setTimeout(r, 50));
47
- try {
48
- const miss1 = await httpGet(`http://localhost:${port}/late.html`);
49
- log('first miss: ' + miss1.res.statusCode);
50
- if(miss1.res.statusCode !== 404) throw new Error('first 404');
51
- await write(dir, 'late.html', 'later');
52
- const hit = await httpGet(`http://localhost:${port}/late.html`);
53
- log('hit after rescan: ' + hit.res.statusCode);
54
- if(hit.res.statusCode !== 200) throw new Error('served after rescan');
55
- } finally { server.close(); process.chdir(prev); }
56
- });
57
- pass('rescan');
58
- } catch(e){ fail(e.message); }
40
+ 'rescan on 404 when enabled and not blacklisted': async ({pass, fail}) => {
41
+ await withTempDir(async (dir) => {
42
+ const prev = process.cwd();
43
+ process.chdir(dir);
44
+ const flags = {root: '.', logging: 0, scan: true};
45
+ const handler = await router(flags, log);
46
+ const server = http.createServer(handler);
47
+ const port = randomPort();
48
+ await new Promise(r => server.listen(port, r));
49
+ await new Promise(r => setTimeout(r, 50));
50
+
51
+ const miss1 = await httpGet(`http://localhost:${port}/late.html`);
52
+ if(miss1.res.statusCode !== 404) {
53
+ server.close();
54
+ process.chdir(prev);
55
+ return fail('first 404');
56
+ }
57
+
58
+ await write(dir, 'late.html', 'later');
59
+ const hit = await httpGet(`http://localhost:${port}/late.html`);
60
+ if(hit.res.statusCode !== 200) {
61
+ server.close();
62
+ process.chdir(prev);
63
+ return fail('served after rescan');
64
+ }
65
+
66
+ server.close();
67
+ process.chdir(prev);
68
+ });
69
+ pass('rescan');
59
70
  },
60
- 'custom and wildcard routes serve mapped files': async ({pass, fail, log}) => {
61
- try {
62
- await withTempDir(async (dir) => {
63
- const fileA = await write(dir, 'a.txt', 'A');
64
- const fileB = await write(dir, 'b/1.txt', 'B1');
65
- const prev = process.cwd();
66
- process.chdir(dir);
67
- const flags = {root: '.', logging: 0, scan: false};
68
- const logFn = () => {};
69
- // write config before init
70
- await write(dir, '.config.json', JSON.stringify({
71
- customRoutes: {'/a': fileA, 'b/*': path.join(dir, 'b/*')}
72
- }));
73
- const handler = await router(flags, logFn);
74
- const server = http.createServer(handler);
75
- const port = randomPort();
76
- await new Promise(r => server.listen(port, r));
77
- await new Promise(r => setTimeout(r, 50));
78
- try {
79
- const r1 = await httpGet(`http://localhost:${port}/a`);
80
- log('custom status: ' + r1.res.statusCode);
81
- if(r1.body.toString() !== 'A') throw new Error('custom route');
82
- const r2 = await httpGet(`http://localhost:${port}/b/1.txt`);
83
- log('wildcard status: ' + r2.res.statusCode);
84
- if(r2.body.toString() !== 'B1') throw new Error('wildcard');
85
- } finally { server.close(); process.chdir(prev); }
86
- });
87
- pass('custom+wildcard');
88
- } catch(e){ fail(e.message); }
71
+ 'custom and wildcard routes serve mapped files': async ({pass, fail}) => {
72
+ await withTempDir(async (dir) => {
73
+ const fileA = await write(dir, 'a.txt', 'A');
74
+ const fileB = await write(dir, 'b/1.txt', 'B1');
75
+ const prev = process.cwd();
76
+ process.chdir(dir);
77
+ const flags = {root: '.', logging: 0, scan: false};
78
+ const logFn = () => {};
79
+ // write config before init
80
+ await write(dir, '.config.json', JSON.stringify({
81
+ customRoutes: {'/a': fileA, 'b/*': path.join(dir, 'b/*')}
82
+ }));
83
+ const handler = await router(flags, logFn);
84
+ const server = http.createServer(handler);
85
+ const port = randomPort();
86
+ await new Promise(r => server.listen(port, r));
87
+ await new Promise(r => setTimeout(r, 50));
88
+
89
+ const r1 = await httpGet(`http://localhost:${port}/a`);
90
+ if(r1.body.toString() !== 'A') {
91
+ server.close();
92
+ process.chdir(prev);
93
+ return fail('custom route');
94
+ }
95
+
96
+ const r2 = await httpGet(`http://localhost:${port}/b/1.txt`);
97
+ if(r2.body.toString() !== 'B1') {
98
+ server.close();
99
+ process.chdir(prev);
100
+ return fail('wildcard');
101
+ }
102
+
103
+ server.close();
104
+ process.chdir(prev);
105
+ });
106
+ pass('custom+wildcard');
89
107
  }
90
108
  };