kempo-server 1.7.5 → 1.7.6
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 +1 -1
- package/tests/getFiles.node-test.js +3 -3
- package/tests/index.node-test.js +3 -2
- package/tests/router-middleware.node-test.js +2 -3
- package/tests/router.node-test.js +7 -8
- package/tests/serveFile.node-test.js +5 -8
- package/tests/test-server-root/.config.json +5 -0
- package/tests/test-server-root/README.md +118 -0
- package/tests/test-server-root/a.txt +1 -0
- package/tests/test-server-root/api/GET.js +1 -0
- package/tests/test-server-root/api/no-default.js +1 -0
- package/tests/test-server-root/b/1.txt +1 -0
- package/tests/test-server-root/custom/data.json +1 -0
- package/tests/test-server-root/docs/.config.json +6 -0
- package/tests/test-server-root/docs/api/data.json +1 -0
- package/tests/test-server-root/docs/src/components/Button.js +1 -0
- package/tests/test-server-root/docs/src/nested/file.js +1 -0
- package/tests/test-server-root/docs/src/utils/helpers/format.js +1 -0
- package/tests/test-server-root/hello.html +1 -0
- package/tests/test-server-root/index.html +1 -0
- package/tests/test-server-root/late.html +1 -0
- package/tests/test-server-root/public/src/file.txt +1 -0
- package/tests/test-server-root/src/components/Button.js +1 -0
- package/tests/test-server-root/src/deep/nested/folder/file.js +1 -0
- package/tests/test-server-root/src/file.js +1 -0
- package/tests/test-server-root/src/file.txt +1 -0
- package/tests/test-server-root/src/nested/file.js +1 -0
- package/tests/test-server-root/src/utils/helpers/format.js +1 -0
- package/tests/test-utils.js +50 -1
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import getFiles from '../src/getFiles.js';
|
|
2
2
|
import defaultConfig from '../src/defaultConfig.js';
|
|
3
3
|
import path from 'path';
|
|
4
|
-
import {
|
|
4
|
+
import {withTestDir, write, log} from './test-utils.js';
|
|
5
5
|
|
|
6
6
|
export default {
|
|
7
7
|
'scans directories recursively and filters by mime and disallowed': async ({pass, fail}) => {
|
|
8
|
-
await
|
|
8
|
+
await withTestDir(async (dir) => {
|
|
9
9
|
const cfg = JSON.parse(JSON.stringify(defaultConfig));
|
|
10
|
-
|
|
10
|
+
// Create test-specific files for this test
|
|
11
11
|
await write(dir, '.env', 'SECRET=1');
|
|
12
12
|
await write(dir, 'notes.xyz', 'unknown');
|
|
13
13
|
await write(dir, 'sub/app.js', 'console.log(1)');
|
package/tests/index.node-test.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {startNode, randomPort, httpGet,
|
|
1
|
+
import {startNode, randomPort, httpGet, withTestDir, write} from './test-utils.js';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
|
|
4
4
|
export default {
|
|
5
5
|
'index.js CLI starts server and serves root': async ({pass, fail}) => {
|
|
6
|
-
await
|
|
6
|
+
await withTestDir(async (dir) => {
|
|
7
|
+
// Create custom index.html for this test
|
|
7
8
|
await write(dir, 'index.html', 'home');
|
|
8
9
|
const port = randomPort();
|
|
9
10
|
const args = [path.join(process.cwd(), 'dist/index.js'), '-r', '.', '-p', String(port), '-l', '0'];
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import http from 'http';
|
|
2
|
-
import {
|
|
2
|
+
import {withTestDir, write, randomPort} from './test-utils.js';
|
|
3
3
|
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
|
-
await
|
|
7
|
+
await withTestDir(async (dir) => {
|
|
8
8
|
await write(dir, '.config.json', JSON.stringify({
|
|
9
9
|
middleware: {
|
|
10
10
|
cors: {enabled: true, origin: '*', methods: ['GET'], headers: ['X']},
|
|
@@ -14,7 +14,6 @@ export default {
|
|
|
14
14
|
logging: {enabled: true, includeUserAgent: false, includeResponseTime: true}
|
|
15
15
|
}
|
|
16
16
|
}));
|
|
17
|
-
await write(dir, 'index.html', 'hello world');
|
|
18
17
|
const prev = process.cwd();
|
|
19
18
|
process.chdir(dir);
|
|
20
19
|
const flags = {root: '.', logging: 0, scan: false};
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import http from 'http';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import {
|
|
3
|
+
import {withTestDir, write, randomPort, httpGet, log} from './test-utils.js';
|
|
4
4
|
import router from '../src/router.js';
|
|
5
5
|
import defaultConfig from '../src/defaultConfig.js';
|
|
6
6
|
|
|
7
7
|
export default {
|
|
8
8
|
'serves static files and 404s unknown': async ({pass, fail}) => {
|
|
9
|
-
await
|
|
10
|
-
await write(dir, 'index.html', '<h1>Home</h1>');
|
|
9
|
+
await withTestDir(async (dir) => {
|
|
11
10
|
const prev = process.cwd();
|
|
12
11
|
process.chdir(dir);
|
|
13
12
|
const flags = {root: '.', logging: 0, scan: false};
|
|
@@ -38,7 +37,7 @@ export default {
|
|
|
38
37
|
pass('static + 404');
|
|
39
38
|
},
|
|
40
39
|
'rescan on 404 when enabled and not blacklisted': async ({pass, fail}) => {
|
|
41
|
-
await
|
|
40
|
+
await withTestDir(async (dir) => {
|
|
42
41
|
const prev = process.cwd();
|
|
43
42
|
process.chdir(dir);
|
|
44
43
|
const flags = {root: '.', logging: 0, scan: true};
|
|
@@ -55,7 +54,7 @@ export default {
|
|
|
55
54
|
return fail('first 404');
|
|
56
55
|
}
|
|
57
56
|
|
|
58
|
-
|
|
57
|
+
// File already exists, should be found on rescan
|
|
59
58
|
const hit = await httpGet(`http://localhost:${port}/late.html`);
|
|
60
59
|
if(hit.res.statusCode !== 200) {
|
|
61
60
|
server.close();
|
|
@@ -69,9 +68,9 @@ export default {
|
|
|
69
68
|
pass('rescan');
|
|
70
69
|
},
|
|
71
70
|
'custom and wildcard routes serve mapped files': async ({pass, fail}) => {
|
|
72
|
-
await
|
|
73
|
-
const fileA =
|
|
74
|
-
const fileB =
|
|
71
|
+
await withTestDir(async (dir) => {
|
|
72
|
+
const fileA = path.join(dir, 'a.txt');
|
|
73
|
+
const fileB = path.join(dir, 'b/1.txt');
|
|
75
74
|
const prev = process.cwd();
|
|
76
75
|
process.chdir(dir);
|
|
77
76
|
const flags = {root: '.', logging: 0, scan: false};
|
|
@@ -2,14 +2,13 @@ import serveFile from '../src/serveFile.js';
|
|
|
2
2
|
import findFile from '../src/findFile.js';
|
|
3
3
|
import defaultConfig from '../src/defaultConfig.js';
|
|
4
4
|
import path from 'path';
|
|
5
|
-
import {createMockReq, createMockRes,
|
|
5
|
+
import {createMockReq, createMockRes, withTestDir, write, log} from './test-utils.js';
|
|
6
6
|
|
|
7
7
|
export default {
|
|
8
8
|
'serves static file with correct mime': async ({pass, fail}) => {
|
|
9
9
|
try {
|
|
10
|
-
await
|
|
10
|
+
await withTestDir(async (dir) => {
|
|
11
11
|
const cfg = JSON.parse(JSON.stringify(defaultConfig));
|
|
12
|
-
await write(dir, 'index.html', '<h1>Hi</h1>');
|
|
13
12
|
const files = [path.join(dir, 'index.html')];
|
|
14
13
|
const res = createMockRes();
|
|
15
14
|
const ok = await serveFile(files, dir, '/index.html', 'GET', cfg, createMockReq(), res, log);
|
|
@@ -22,9 +21,8 @@ export default {
|
|
|
22
21
|
},
|
|
23
22
|
'executes route files by calling default export': async ({pass, fail}) => {
|
|
24
23
|
try {
|
|
25
|
-
await
|
|
24
|
+
await withTestDir(async (dir) => {
|
|
26
25
|
const cfg = JSON.parse(JSON.stringify(defaultConfig));
|
|
27
|
-
await write(dir, 'api/GET.js', "export default async (req, res) => { res.status(201).json({ok:true, params:req.params}); }\n");
|
|
28
26
|
const files = [path.join(dir, 'api/GET.js')];
|
|
29
27
|
const res = createMockRes();
|
|
30
28
|
const ok = await serveFile(files, dir, '/api', 'GET', cfg, createMockReq(), res, log);
|
|
@@ -37,10 +35,9 @@ export default {
|
|
|
37
35
|
},
|
|
38
36
|
'handles route file without default function': async ({pass, fail}) => {
|
|
39
37
|
try {
|
|
40
|
-
await
|
|
38
|
+
await withTestDir(async (dir) => {
|
|
41
39
|
const cfg = JSON.parse(JSON.stringify(defaultConfig));
|
|
42
|
-
|
|
43
|
-
const files = [path.join(dir, 'api/GET.js')];
|
|
40
|
+
const files = [path.join(dir, 'api/no-default.js')];
|
|
44
41
|
const res = createMockRes();
|
|
45
42
|
const ok = await serveFile(files, dir, '/api', 'GET', cfg, createMockReq(), res, log);
|
|
46
43
|
if(ok !== true) return fail('handled');
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Test Server Root
|
|
2
|
+
|
|
3
|
+
This directory contains the persistent test server structure used by unit tests instead of creating temporary files for each test run. Tests use `withTestDir()` to get a temporary copy of this structure, maintaining isolation while providing consistent base files.
|
|
4
|
+
|
|
5
|
+
## Directory Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
test-server-root/
|
|
9
|
+
├── README.md # This file
|
|
10
|
+
├── .config.json # Basic config with middleware settings
|
|
11
|
+
├── index.html # Basic home page: "<h1>Home</h1>"
|
|
12
|
+
├── late.html # For rescan tests: "later"
|
|
13
|
+
├── hello.html # For CLI tests: "hello world"
|
|
14
|
+
├── a.txt # Test file: "A"
|
|
15
|
+
├── b/
|
|
16
|
+
│ └── 1.txt # Test file: "B1"
|
|
17
|
+
├── api/
|
|
18
|
+
│ ├── GET.js # Route handler returning {ok:true, params}
|
|
19
|
+
│ └── no-default.js # Route file without default export
|
|
20
|
+
├── src/
|
|
21
|
+
│ ├── file.js # Content: "single level"
|
|
22
|
+
│ ├── file.txt # Content: "custom"
|
|
23
|
+
│ ├── nested/
|
|
24
|
+
│ │ └── file.js # Content: "nested level"
|
|
25
|
+
│ ├── components/
|
|
26
|
+
│ │ └── Button.js # Content: "export default Button"
|
|
27
|
+
│ ├── utils/
|
|
28
|
+
│ │ └── helpers/
|
|
29
|
+
│ │ └── format.js # Content: "export const format = () => {}"
|
|
30
|
+
│ └── deep/
|
|
31
|
+
│ └── nested/
|
|
32
|
+
│ └── folder/
|
|
33
|
+
│ └── file.js # Content: "export const deep = true"
|
|
34
|
+
├── docs/
|
|
35
|
+
│ ├── .config.json # Config with custom routes to ../src/**
|
|
36
|
+
│ ├── api/
|
|
37
|
+
│ │ └── data.json # Content: {"source": "static"}
|
|
38
|
+
│ └── src/
|
|
39
|
+
│ ├── nested/
|
|
40
|
+
│ │ └── file.js # Content: "fallback file"
|
|
41
|
+
│ ├── components/
|
|
42
|
+
│ │ └── Button.js # Content: "WRONG FILE"
|
|
43
|
+
│ └── utils/
|
|
44
|
+
│ └── helpers/
|
|
45
|
+
│ └── format.js # Content: "WRONG FILE"
|
|
46
|
+
├── custom/
|
|
47
|
+
│ └── data.json # Content: {"source": "custom"}
|
|
48
|
+
└── public/
|
|
49
|
+
└── src/
|
|
50
|
+
└── file.txt # Content: "static"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Configuration Files
|
|
54
|
+
|
|
55
|
+
### Root .config.json
|
|
56
|
+
Basic configuration for middleware testing:
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"middleware": {
|
|
60
|
+
"cors": {}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### docs/.config.json
|
|
66
|
+
Configuration for wildcard routing tests:
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"customRoutes": {
|
|
70
|
+
"/src/*": "../src/$1"
|
|
71
|
+
},
|
|
72
|
+
"routePreference": "customRoute"
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Usage in Tests
|
|
77
|
+
|
|
78
|
+
### Simple Tests
|
|
79
|
+
Use `withTestDir()` for tests that can leverage the existing structure:
|
|
80
|
+
|
|
81
|
+
```javascript
|
|
82
|
+
await withTestDir(async (dir) => {
|
|
83
|
+
// dir contains a copy of all the above files
|
|
84
|
+
// Use existing files or create additional ones as needed
|
|
85
|
+
const handler = await router({root: dir}, log);
|
|
86
|
+
// ... test the handler
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Subdirectory Tests
|
|
91
|
+
Use the `subdir` option to work within a specific folder:
|
|
92
|
+
|
|
93
|
+
```javascript
|
|
94
|
+
await withTestDir(async (dir) => {
|
|
95
|
+
// dir points to test-server-root/docs/
|
|
96
|
+
process.chdir(dir);
|
|
97
|
+
const handler = await router({root: '.'}, log);
|
|
98
|
+
// ... test from docs folder perspective
|
|
99
|
+
}, {subdir: 'docs'});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Complex Tests
|
|
103
|
+
For tests requiring very specific or complex structures, continue using `withTempDir()`:
|
|
104
|
+
|
|
105
|
+
```javascript
|
|
106
|
+
await withTempDir(async (dir) => {
|
|
107
|
+
await write(dir, 'very/specific/structure.js', 'content');
|
|
108
|
+
// ... custom test setup
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Benefits
|
|
113
|
+
|
|
114
|
+
1. **Consistency** - All tests start with the same base structure
|
|
115
|
+
2. **Speed** - No need to recreate common files for each test
|
|
116
|
+
3. **Maintainability** - Centralized test file management
|
|
117
|
+
4. **Documentation** - Clear visibility of what test files exist
|
|
118
|
+
5. **Isolation** - Each test still gets its own temporary copy
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
A
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default async (req, res) => { res.status(201).json({ok:true, params:req.params}); }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const x = 1;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
B1
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"source": "custom"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"source": "static"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
WRONG FILE
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
fallback file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
WRONG FILE
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
hello world
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<h1>Home</h1>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
later
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
static
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default Button
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const deep = true
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
single level
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
custom
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
nested level
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const format = () => {}
|
package/tests/test-utils.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import {Readable} from 'stream';
|
|
2
|
-
import {mkdtemp, rm, writeFile, mkdir} from 'fs/promises';
|
|
2
|
+
import {mkdtemp, rm, writeFile, mkdir, cp} from 'fs/promises';
|
|
3
3
|
import os from 'os';
|
|
4
4
|
import path from 'path';
|
|
5
|
+
import {fileURLToPath} from 'url';
|
|
6
|
+
|
|
7
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const TEST_SERVER_ROOT = path.join(__dirname, 'test-server-root');
|
|
5
9
|
|
|
6
10
|
export const createMockReq = ({method = 'GET', url = '/', headers = {}, body = null, remoteAddress = '127.0.0.1'} = {}) => {
|
|
7
11
|
const stream = new Readable({read(){}});
|
|
@@ -43,6 +47,7 @@ export const createMockRes = () => {
|
|
|
43
47
|
};
|
|
44
48
|
};
|
|
45
49
|
|
|
50
|
+
// Legacy function for backward compatibility - will be deprecated
|
|
46
51
|
export const withTempDir = async (fn) => {
|
|
47
52
|
const dir = await mkdtemp(path.join(os.tmpdir(), 'kempo-tests-'));
|
|
48
53
|
try {
|
|
@@ -52,6 +57,50 @@ export const withTempDir = async (fn) => {
|
|
|
52
57
|
}
|
|
53
58
|
};
|
|
54
59
|
|
|
60
|
+
// New function that uses the persistent test server root as a base
|
|
61
|
+
export const withTestDir = async (fn, {subdir = null} = {}) => {
|
|
62
|
+
const tempDir = await mkdtemp(path.join(os.tmpdir(), 'kempo-tests-'));
|
|
63
|
+
try {
|
|
64
|
+
// Copy the test server root to the temporary directory
|
|
65
|
+
await cp(TEST_SERVER_ROOT, tempDir, {recursive: true});
|
|
66
|
+
let workingDir = tempDir;
|
|
67
|
+
|
|
68
|
+
if (subdir) {
|
|
69
|
+
workingDir = path.join(tempDir, subdir);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return await fn(workingDir);
|
|
73
|
+
} finally {
|
|
74
|
+
await rm(tempDir, {recursive: true, force: true});
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// Helper to get the path to a file in the test server root
|
|
79
|
+
export const getTestFilePath = (relativePath) => {
|
|
80
|
+
return path.join(TEST_SERVER_ROOT, relativePath);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// Helper to reset or prepare specific test scenarios
|
|
84
|
+
export const prepareTestScenario = async (dir, scenario) => {
|
|
85
|
+
switch (scenario) {
|
|
86
|
+
case 'basic-server':
|
|
87
|
+
// Already has index.html, api/GET.js, etc.
|
|
88
|
+
break;
|
|
89
|
+
case 'wildcard-routes':
|
|
90
|
+
await write(dir, 'docs/.config.json', JSON.stringify({
|
|
91
|
+
customRoutes: { '/src/**': '../src/**' }
|
|
92
|
+
}));
|
|
93
|
+
break;
|
|
94
|
+
case 'middleware':
|
|
95
|
+
await write(dir, '.config.json', JSON.stringify({
|
|
96
|
+
middleware: { cors: {enabled: true} }
|
|
97
|
+
}));
|
|
98
|
+
break;
|
|
99
|
+
default:
|
|
100
|
+
// No special preparation needed
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
55
104
|
export const write = async (root, rel, content = '') => {
|
|
56
105
|
const full = path.join(root, rel);
|
|
57
106
|
await mkdir(path.dirname(full), {recursive: true});
|