koa-classic-server 2.1.4 โ 2.4.0
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/README.md +110 -35
- package/__tests__/deprecation-warnings.test.js +217 -0
- package/__tests__/publicWwwTest/test-page.html +1 -0
- package/__tests__/symlink.test.js +438 -0
- package/__tests__/useOriginalUrl.test.js +213 -0
- package/docs/CHANGELOG.md +160 -0
- package/docs/DOCUMENTATION.md +53 -5
- package/index.cjs +140 -38
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,37 +4,31 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/koa-classic-server)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
|
-
[]()
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## ๐ Version 2.
|
|
11
|
+
## ๐ Version 2.X - Production-Ready Release
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
The 2.X series brings major performance improvements, enhanced security, and powerful new features while maintaining full backward compatibility.
|
|
14
14
|
|
|
15
|
-
###
|
|
16
|
-
|
|
17
|
-
โ
**Development-Friendly Defaults** - `enableCaching` now defaults to `false` for easier development
|
|
18
|
-
โ
**Production Guidance** - Clear documentation on enabling caching for production environments
|
|
19
|
-
โ
**Enhanced Documentation** - Comprehensive notes on caching configuration and recommendations
|
|
20
|
-
|
|
21
|
-
### What's New in 2.1.2
|
|
15
|
+
### Key Features in Version 2.X
|
|
22
16
|
|
|
17
|
+
โ
**URL Rewriting Support** - Compatible with i18n and routing middleware via `useOriginalUrl` option
|
|
18
|
+
โ
**Improved Caching Controls** - Clear `browserCacheEnabled` and `browserCacheMaxAge` options
|
|
19
|
+
โ
**Development-Friendly Defaults** - Caching disabled by default for easier development
|
|
20
|
+
โ
**Production Optimized** - Enable caching in production for 80-95% bandwidth reduction
|
|
23
21
|
โ
**Sortable Directory Columns** - Click Name/Type/Size to sort (Apache2-like)
|
|
24
|
-
โ
**Navigation Bug Fixed** - Directory navigation now works correctly after sorting
|
|
25
22
|
โ
**File Size Display** - Human-readable file sizes (B, KB, MB, GB, TB)
|
|
26
|
-
โ
**HTTP Caching** -
|
|
23
|
+
โ
**HTTP Caching** - ETag and Last-Modified headers with 304 responses
|
|
27
24
|
โ
**Async/Await** - Non-blocking I/O for high performance
|
|
28
|
-
โ
**
|
|
29
|
-
โ
**Flow Documentation** - Complete execution flow diagrams
|
|
30
|
-
โ
**Code Review** - Standardized operators and best practices
|
|
31
|
-
|
|
32
|
-
### What's New in 2.0
|
|
33
|
-
|
|
34
|
-
โ
**Performance Optimizations** - 50-70% faster directory listings
|
|
25
|
+
โ
**Performance Optimized** - 50-70% faster directory listings
|
|
35
26
|
โ
**Enhanced Index Option** - Array format with RegExp support
|
|
36
|
-
โ
**Template Engine
|
|
37
|
-
โ
**Security
|
|
27
|
+
โ
**Template Engine Support** - EJS, Pug, Handlebars, Nunjucks, and more
|
|
28
|
+
โ
**Enterprise Security** - Path traversal, XSS, race condition protection
|
|
29
|
+
โ
**Symlink Support** - Full symbolic link support (NixOS, Docker, npm link, Capistrano)
|
|
30
|
+
โ
**Comprehensive Testing** - 214 tests passing with extensive coverage
|
|
31
|
+
โ
**Complete Documentation** - Detailed guides and examples
|
|
38
32
|
|
|
39
33
|
[See full changelog โ](./docs/CHANGELOG.md)
|
|
40
34
|
|
|
@@ -55,7 +49,8 @@ Version 2.1.3 updates the default caching behavior for better development experi
|
|
|
55
49
|
- ๐ **Enterprise Security** - Path traversal, XSS, race condition protection
|
|
56
50
|
- โ๏ธ **Highly Configurable** - URL prefixes, reserved paths, index files
|
|
57
51
|
- ๐ **High Performance** - Async/await, non-blocking I/O, optimized algorithms
|
|
58
|
-
-
|
|
52
|
+
- ๐ **Symlink Support** - Transparent symlink resolution with directory listing indicators
|
|
53
|
+
- ๐งช **Well-Tested** - 214 passing tests with comprehensive coverage
|
|
59
54
|
- ๐ฆ **Dual Module Support** - CommonJS and ES Modules
|
|
60
55
|
|
|
61
56
|
---
|
|
@@ -101,8 +96,8 @@ app.use(koaClassicServer(__dirname + '/public', {
|
|
|
101
96
|
showDirContents: true,
|
|
102
97
|
index: ['index.html', 'index.htm'],
|
|
103
98
|
urlPrefix: '/static',
|
|
104
|
-
|
|
105
|
-
|
|
99
|
+
browserCacheMaxAge: 3600,
|
|
100
|
+
browserCacheEnabled: true
|
|
106
101
|
}));
|
|
107
102
|
|
|
108
103
|
app.listen(3000);
|
|
@@ -229,14 +224,14 @@ Enable aggressive caching for static files:
|
|
|
229
224
|
|
|
230
225
|
```javascript
|
|
231
226
|
app.use(koaClassicServer(__dirname + '/public', {
|
|
232
|
-
|
|
233
|
-
|
|
227
|
+
browserCacheEnabled: true, // Enable ETag and Last-Modified
|
|
228
|
+
browserCacheMaxAge: 86400, // Cache for 24 hours (in seconds)
|
|
234
229
|
}));
|
|
235
230
|
```
|
|
236
231
|
|
|
237
232
|
**โ ๏ธ Important: Production Recommendation**
|
|
238
233
|
|
|
239
|
-
The default value for `
|
|
234
|
+
The default value for `browserCacheEnabled` is `false` to facilitate development (where you want changes to be immediately visible). **For production environments, it is strongly recommended to set `browserCacheEnabled: true`** to benefit from:
|
|
240
235
|
|
|
241
236
|
- 80-95% bandwidth reduction
|
|
242
237
|
- 304 Not Modified responses for unchanged files
|
|
@@ -281,8 +276,8 @@ app.use(koaClassicServer(path.join(__dirname, 'public'), {
|
|
|
281
276
|
index: ['index.html', 'index.htm'],
|
|
282
277
|
urlPrefix: '/assets',
|
|
283
278
|
urlsReserved: ['/admin', '/api', '/.git'],
|
|
284
|
-
|
|
285
|
-
|
|
279
|
+
browserCacheEnabled: true,
|
|
280
|
+
browserCacheMaxAge: 86400, // 24 hours
|
|
286
281
|
}));
|
|
287
282
|
|
|
288
283
|
// Serve dynamic templates
|
|
@@ -366,10 +361,18 @@ Creates a Koa middleware for serving static files.
|
|
|
366
361
|
ext: ['ejs', 'pug', 'hbs']
|
|
367
362
|
},
|
|
368
363
|
|
|
369
|
-
// HTTP caching configuration
|
|
364
|
+
// Browser HTTP caching configuration
|
|
370
365
|
// NOTE: Default is false for development. Set to true in production for better performance!
|
|
371
|
-
|
|
372
|
-
|
|
366
|
+
browserCacheEnabled: false, // Enable ETag & Last-Modified (default: false)
|
|
367
|
+
browserCacheMaxAge: 3600, // Cache-Control max-age in seconds (default: 3600 = 1 hour)
|
|
368
|
+
|
|
369
|
+
// URL resolution
|
|
370
|
+
useOriginalUrl: true, // Use ctx.originalUrl (default) or ctx.url
|
|
371
|
+
// Set false for URL rewriting middleware (i18n, routing)
|
|
372
|
+
|
|
373
|
+
// DEPRECATED (use new names above):
|
|
374
|
+
// enableCaching: use browserCacheEnabled instead
|
|
375
|
+
// cacheMaxAge: use browserCacheMaxAge instead
|
|
373
376
|
}
|
|
374
377
|
```
|
|
375
378
|
|
|
@@ -384,8 +387,52 @@ Creates a Koa middleware for serving static files.
|
|
|
384
387
|
| `urlsReserved` | Array | `[]` | Reserved directory paths (first-level only) |
|
|
385
388
|
| `template.render` | Function | `undefined` | Template rendering function |
|
|
386
389
|
| `template.ext` | Array | `[]` | Extensions for template rendering |
|
|
387
|
-
| `
|
|
388
|
-
| `
|
|
390
|
+
| `browserCacheEnabled` | Boolean | `false` | Enable browser HTTP caching headers (recommended: `true` in production) |
|
|
391
|
+
| `browserCacheMaxAge` | Number | `3600` | Browser cache duration in seconds |
|
|
392
|
+
| `useOriginalUrl` | Boolean | `true` | Use `ctx.originalUrl` (default) or `ctx.url` for URL resolution |
|
|
393
|
+
| ~~`enableCaching`~~ | Boolean | `false` | **DEPRECATED**: Use `browserCacheEnabled` instead |
|
|
394
|
+
| ~~`cacheMaxAge`~~ | Number | `3600` | **DEPRECATED**: Use `browserCacheMaxAge` instead |
|
|
395
|
+
|
|
396
|
+
#### useOriginalUrl (Boolean, default: true)
|
|
397
|
+
|
|
398
|
+
Controls which URL property is used for file resolution:
|
|
399
|
+
- **`true` (default)**: Uses `ctx.originalUrl` (immutable, reflects the original request)
|
|
400
|
+
- **`false`**: Uses `ctx.url` (mutable, can be modified by middleware)
|
|
401
|
+
|
|
402
|
+
**When to use `false`:**
|
|
403
|
+
|
|
404
|
+
Set `useOriginalUrl: false` when using URL rewriting middleware such as i18n routers or path rewriters that modify `ctx.url`. This allows koa-classic-server to serve files based on the rewritten URL instead of the original request URL.
|
|
405
|
+
|
|
406
|
+
**Example with i18n middleware:**
|
|
407
|
+
|
|
408
|
+
```javascript
|
|
409
|
+
const Koa = require('koa');
|
|
410
|
+
const koaClassicServer = require('koa-classic-server');
|
|
411
|
+
|
|
412
|
+
const app = new Koa();
|
|
413
|
+
|
|
414
|
+
// i18n middleware that rewrites URLs
|
|
415
|
+
app.use(async (ctx, next) => {
|
|
416
|
+
if (ctx.path.match(/^\/it\//)) {
|
|
417
|
+
ctx.url = ctx.path.replace(/^\/it/, ''); // /it/page.html โ /page.html
|
|
418
|
+
}
|
|
419
|
+
await next();
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
// Serve files using rewritten URL
|
|
423
|
+
app.use(koaClassicServer(__dirname + '/www', {
|
|
424
|
+
useOriginalUrl: false // Use ctx.url (rewritten) instead of ctx.originalUrl
|
|
425
|
+
}));
|
|
426
|
+
|
|
427
|
+
app.listen(3000);
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
**How it works:**
|
|
431
|
+
- Request: `GET /it/page.html`
|
|
432
|
+
- `ctx.originalUrl`: `/it/page.html` (unchanged)
|
|
433
|
+
- `ctx.url`: `/page.html` (rewritten by middleware)
|
|
434
|
+
- With `useOriginalUrl: false`: Server looks for `/www/page.html` โ
|
|
435
|
+
- With `useOriginalUrl: true` (default): Server looks for `/www/it/page.html` โ 404
|
|
389
436
|
|
|
390
437
|
---
|
|
391
438
|
|
|
@@ -417,6 +464,33 @@ Human-readable format:
|
|
|
417
464
|
- **Click file name** - Download/view file
|
|
418
465
|
- **Parent Directory** - Go up one level
|
|
419
466
|
|
|
467
|
+
### Symlink Support
|
|
468
|
+
|
|
469
|
+
The middleware fully supports symbolic links, which is essential for environments where served files are symlinks rather than regular files:
|
|
470
|
+
|
|
471
|
+
- **NixOS buildFHSEnv** - Files in www/ appear as symlinks to the Nix store
|
|
472
|
+
- **Docker bind mounts** - Mounted files may appear as symlinks
|
|
473
|
+
- **npm link** - Linked packages are symlinks
|
|
474
|
+
- **Capistrano-style deploys** - The `current` directory is a symlink to the active release
|
|
475
|
+
|
|
476
|
+
**How it works:**
|
|
477
|
+
|
|
478
|
+
Symlinks are followed transparently via `fs.promises.stat()`, but only when `dirent.isSymbolicLink()` is true. Regular files incur zero additional overhead.
|
|
479
|
+
|
|
480
|
+
**Directory listing indicators:**
|
|
481
|
+
|
|
482
|
+
| Entry type | Indicator | Clickable | Type shown |
|
|
483
|
+
|------------|-----------|-----------|------------|
|
|
484
|
+
| Symlink to file | `( Symlink )` | Yes | Target MIME type |
|
|
485
|
+
| Symlink to directory | `( Symlink )` | Yes | `DIR` |
|
|
486
|
+
| Broken/circular symlink | `( Broken Symlink )` | No | `unknown` |
|
|
487
|
+
| Regular file/directory | none | Yes | Real type |
|
|
488
|
+
|
|
489
|
+
**Edge cases handled:**
|
|
490
|
+
- Broken symlinks (missing target) return 404 on direct access
|
|
491
|
+
- Circular symlinks (A โ B โ A) are treated as broken, no infinite loops
|
|
492
|
+
- Symlinks to directories are fully navigable
|
|
493
|
+
|
|
420
494
|
---
|
|
421
495
|
|
|
422
496
|
## Security
|
|
@@ -511,10 +585,11 @@ npm run test:performance
|
|
|
511
585
|
```
|
|
512
586
|
|
|
513
587
|
**Test Coverage:**
|
|
514
|
-
- โ
|
|
588
|
+
- โ
214 tests passing
|
|
515
589
|
- โ
Security tests (path traversal, XSS, race conditions)
|
|
516
590
|
- โ
EJS template integration tests
|
|
517
591
|
- โ
Index option tests (strings, arrays, RegExp)
|
|
592
|
+
- โ
Symlink tests (file, directory, broken, circular, indicators)
|
|
518
593
|
- โ
Performance benchmarks
|
|
519
594
|
- โ
Directory sorting tests
|
|
520
595
|
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
//
|
|
3
|
+
// TEST FOR DEPRECATED OPTION NAMES (enableCaching, cacheMaxAge)
|
|
4
|
+
// This test verifies backward compatibility and deprecation warnings
|
|
5
|
+
//
|
|
6
|
+
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
|
+
|
|
8
|
+
const supertest = require('supertest');
|
|
9
|
+
const koaClassicServer = require('../index.cjs');
|
|
10
|
+
const Koa = require('koa');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
|
|
13
|
+
const rootDir = path.join(__dirname, 'publicWwwTest');
|
|
14
|
+
|
|
15
|
+
describe('Deprecated option names (backward compatibility)', () => {
|
|
16
|
+
|
|
17
|
+
describe('Using deprecated enableCaching option', () => {
|
|
18
|
+
let app;
|
|
19
|
+
let server;
|
|
20
|
+
let consoleWarnSpy;
|
|
21
|
+
|
|
22
|
+
beforeAll(() => {
|
|
23
|
+
// Spy on console.warn to capture deprecation warnings
|
|
24
|
+
consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
25
|
+
|
|
26
|
+
app = new Koa();
|
|
27
|
+
|
|
28
|
+
// Use deprecated option name
|
|
29
|
+
app.use(koaClassicServer(rootDir, {
|
|
30
|
+
enableCaching: true // DEPRECATED: should use browserCacheEnabled
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
server = app.listen();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
afterAll(() => {
|
|
37
|
+
server.close();
|
|
38
|
+
consoleWarnSpy.mockRestore();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('should display deprecation warning for enableCaching', () => {
|
|
42
|
+
expect(consoleWarnSpy).toHaveBeenCalled();
|
|
43
|
+
const warningMessage = consoleWarnSpy.mock.calls[0][1];
|
|
44
|
+
expect(warningMessage).toContain('DEPRECATION WARNING');
|
|
45
|
+
expect(warningMessage).toContain('enableCaching');
|
|
46
|
+
expect(warningMessage).toContain('browserCacheEnabled');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('should still work with deprecated option', async () => {
|
|
50
|
+
const response = await supertest(server).get('/test-page.html');
|
|
51
|
+
|
|
52
|
+
// Should return the file
|
|
53
|
+
expect(response.status).toBe(200);
|
|
54
|
+
|
|
55
|
+
// Should have caching headers (because enableCaching: true was set)
|
|
56
|
+
expect(response.headers['etag']).toBeDefined();
|
|
57
|
+
expect(response.headers['last-modified']).toBeDefined();
|
|
58
|
+
expect(response.headers['cache-control']).toContain('public');
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('Using deprecated cacheMaxAge option', () => {
|
|
63
|
+
let app;
|
|
64
|
+
let server;
|
|
65
|
+
let consoleWarnSpy;
|
|
66
|
+
|
|
67
|
+
beforeAll(() => {
|
|
68
|
+
consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
69
|
+
|
|
70
|
+
app = new Koa();
|
|
71
|
+
|
|
72
|
+
// Use deprecated option name
|
|
73
|
+
app.use(koaClassicServer(rootDir, {
|
|
74
|
+
enableCaching: true, // Also deprecated
|
|
75
|
+
cacheMaxAge: 7200 // DEPRECATED: should use browserCacheMaxAge
|
|
76
|
+
}));
|
|
77
|
+
|
|
78
|
+
server = app.listen();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
afterAll(() => {
|
|
82
|
+
server.close();
|
|
83
|
+
consoleWarnSpy.mockRestore();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test('should display deprecation warning for cacheMaxAge', () => {
|
|
87
|
+
const warningCalls = consoleWarnSpy.mock.calls;
|
|
88
|
+
const cacheMaxAgeWarning = warningCalls.find(call =>
|
|
89
|
+
call[1] && call[1].includes('cacheMaxAge')
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
expect(cacheMaxAgeWarning).toBeDefined();
|
|
93
|
+
expect(cacheMaxAgeWarning[1]).toContain('DEPRECATION WARNING');
|
|
94
|
+
expect(cacheMaxAgeWarning[1]).toContain('browserCacheMaxAge');
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('should use the deprecated cacheMaxAge value', async () => {
|
|
98
|
+
const response = await supertest(server).get('/test-page.html');
|
|
99
|
+
|
|
100
|
+
expect(response.status).toBe(200);
|
|
101
|
+
expect(response.headers['cache-control']).toContain('max-age=7200');
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe('Using new option names (no warnings)', () => {
|
|
106
|
+
let app;
|
|
107
|
+
let server;
|
|
108
|
+
let consoleWarnSpy;
|
|
109
|
+
|
|
110
|
+
beforeAll(() => {
|
|
111
|
+
consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
112
|
+
|
|
113
|
+
app = new Koa();
|
|
114
|
+
|
|
115
|
+
// Use NEW option names
|
|
116
|
+
app.use(koaClassicServer(rootDir, {
|
|
117
|
+
browserCacheEnabled: true,
|
|
118
|
+
browserCacheMaxAge: 3600
|
|
119
|
+
}));
|
|
120
|
+
|
|
121
|
+
server = app.listen();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
afterAll(() => {
|
|
125
|
+
server.close();
|
|
126
|
+
consoleWarnSpy.mockRestore();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('should NOT display deprecation warnings', () => {
|
|
130
|
+
// Filter out warnings from other tests (like index option deprecation)
|
|
131
|
+
const cachingWarnings = consoleWarnSpy.mock.calls.filter(call =>
|
|
132
|
+
call[1] && (call[1].includes('enableCaching') || call[1].includes('cacheMaxAge'))
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
expect(cachingWarnings.length).toBe(0);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test('should work correctly with new option names', async () => {
|
|
139
|
+
const response = await supertest(server).get('/test-page.html');
|
|
140
|
+
|
|
141
|
+
expect(response.status).toBe(200);
|
|
142
|
+
expect(response.headers['etag']).toBeDefined();
|
|
143
|
+
expect(response.headers['cache-control']).toContain('max-age=3600');
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
describe('Using both old and new names (new takes precedence)', () => {
|
|
148
|
+
let app;
|
|
149
|
+
let server;
|
|
150
|
+
let consoleWarnSpy;
|
|
151
|
+
|
|
152
|
+
beforeAll(() => {
|
|
153
|
+
consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
|
154
|
+
|
|
155
|
+
app = new Koa();
|
|
156
|
+
|
|
157
|
+
// Use BOTH old and new names - new should take precedence
|
|
158
|
+
app.use(koaClassicServer(rootDir, {
|
|
159
|
+
enableCaching: true, // OLD (deprecated)
|
|
160
|
+
browserCacheEnabled: false, // NEW (should take precedence)
|
|
161
|
+
cacheMaxAge: 7200, // OLD (deprecated)
|
|
162
|
+
browserCacheMaxAge: 9999 // NEW (should take precedence)
|
|
163
|
+
}));
|
|
164
|
+
|
|
165
|
+
server = app.listen();
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
afterAll(() => {
|
|
169
|
+
server.close();
|
|
170
|
+
consoleWarnSpy.mockRestore();
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test('should NOT display warnings when new names are also provided', () => {
|
|
174
|
+
// When both old and new names are provided, no warning should be shown
|
|
175
|
+
const cachingWarnings = consoleWarnSpy.mock.calls.filter(call =>
|
|
176
|
+
call[1] && (call[1].includes('enableCaching') || call[1].includes('cacheMaxAge'))
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
expect(cachingWarnings.length).toBe(0);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test('new option values should take precedence over old ones', async () => {
|
|
183
|
+
const response = await supertest(server).get('/test-page.html');
|
|
184
|
+
|
|
185
|
+
expect(response.status).toBe(200);
|
|
186
|
+
|
|
187
|
+
// browserCacheEnabled: false should take precedence over enableCaching: true
|
|
188
|
+
// So there should be NO caching headers
|
|
189
|
+
expect(response.headers['etag']).toBeUndefined();
|
|
190
|
+
expect(response.headers['cache-control']).toContain('no-cache');
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
describe('Default behavior (no caching options specified)', () => {
|
|
195
|
+
let app;
|
|
196
|
+
let server;
|
|
197
|
+
|
|
198
|
+
beforeAll(() => {
|
|
199
|
+
app = new Koa();
|
|
200
|
+
app.use(koaClassicServer(rootDir));
|
|
201
|
+
server = app.listen();
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
afterAll(() => {
|
|
205
|
+
server.close();
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test('should default to browserCacheEnabled: false', async () => {
|
|
209
|
+
const response = await supertest(server).get('/test-page.html');
|
|
210
|
+
|
|
211
|
+
expect(response.status).toBe(200);
|
|
212
|
+
|
|
213
|
+
// Default is caching disabled
|
|
214
|
+
expect(response.headers['cache-control']).toContain('no-cache');
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<!DOCTYPE html><html><head><title>Test Page</title></head><body><h1>Test Page</h1></body></html>
|