express-cache-ctrl 1.1.8 → 1.1.9
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/.github/renovate.json +16 -0
- package/AGENTS.md +106 -0
- package/package.json +6 -6
- package/src/cache.js +1 -0
- package/test/cache.js +117 -0
- package/test/unit/cache.js +253 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
|
3
|
+
"extends": [
|
|
4
|
+
"config:base"
|
|
5
|
+
],
|
|
6
|
+
"semanticCommits": "enabled",
|
|
7
|
+
"rangeStrategy": "bump",
|
|
8
|
+
"packageRules": [
|
|
9
|
+
{
|
|
10
|
+
"matchUpdateTypes": [
|
|
11
|
+
"major"
|
|
12
|
+
],
|
|
13
|
+
"enabled": false
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
package/AGENTS.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This file provides guidelines for AI coding agents working on the express-cache-ctrl repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
An Express.js middleware for managing Cache-Control headers with support for public/private caching, TTL, and OWASP secure caching recommendations.
|
|
8
|
+
|
|
9
|
+
## Build/Test Commands
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Run all tests
|
|
13
|
+
npm test
|
|
14
|
+
|
|
15
|
+
# Run specific test file
|
|
16
|
+
npx mocha 'test/cache.js'
|
|
17
|
+
npx mocha 'test/unit/cache.js'
|
|
18
|
+
|
|
19
|
+
# Run tests matching a pattern (grep)
|
|
20
|
+
npx mocha 'test/**/*.js' --grep "cache disabled"
|
|
21
|
+
|
|
22
|
+
# Run with different reporter
|
|
23
|
+
npx mocha 'test/**/*.js' --reporter spec
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Note: This project uses Mocha (test runner) + Chai (assertions). Tests use BDD style with `describe()` and `it()` blocks.
|
|
27
|
+
|
|
28
|
+
## Code Style Guidelines
|
|
29
|
+
|
|
30
|
+
### Formatting
|
|
31
|
+
- Indent: 4 spaces for `.js` files, 2 spaces for `package.json` (see `.editorconfig`)
|
|
32
|
+
- Use double quotes for strings
|
|
33
|
+
- Always use semicolons
|
|
34
|
+
- Insert final newline at end of files
|
|
35
|
+
- Trim trailing whitespace
|
|
36
|
+
|
|
37
|
+
### Language & Imports
|
|
38
|
+
- Use ES5/CommonJS (no ES6 modules)
|
|
39
|
+
- Import style: `const module = require("module");`
|
|
40
|
+
- Use `"use strict";` directive at top of source files
|
|
41
|
+
- Node.js version: >= 12.0
|
|
42
|
+
|
|
43
|
+
### Naming Conventions
|
|
44
|
+
- Functions: camelCase (e.g., `cacheCustom`, `toTimespan`)
|
|
45
|
+
- Variables: camelCase (e.g., `cacheControl`, `defaultTTL`)
|
|
46
|
+
- Constants: Use descriptive names, may use ALL_CAPS for true constants
|
|
47
|
+
- Files: camelCase for source files (e.g., `cache.js`)
|
|
48
|
+
|
|
49
|
+
### Functions & Structure
|
|
50
|
+
- Prefer traditional function declarations over arrow functions in source
|
|
51
|
+
- Arrow functions acceptable in tests
|
|
52
|
+
- Group related functions together with clear section comments
|
|
53
|
+
- Export pattern: `exports.functionName = functionName;` at end of file
|
|
54
|
+
|
|
55
|
+
### Testing Conventions
|
|
56
|
+
- Test files: Located in `test/` directory with `.js` extension
|
|
57
|
+
- Unit tests: Place in `test/unit/` subdirectory
|
|
58
|
+
- Mock objects: Place in `test/mocks/` subdirectory
|
|
59
|
+
- Use Chai's `expect()` assertion style
|
|
60
|
+
- Use descriptive test names that explain behavior
|
|
61
|
+
- Group related tests with nested `describe()` blocks
|
|
62
|
+
- Follow pattern: `it("should do something", function (done) { ... });`
|
|
63
|
+
- Call `done()` callback for async tests
|
|
64
|
+
|
|
65
|
+
### Error Handling
|
|
66
|
+
- Middleware must call `next()` to pass control
|
|
67
|
+
- Validate inputs with truthy checks: `opts = opts || {};`
|
|
68
|
+
- Use `parseInt()` for numeric conversions
|
|
69
|
+
- Avoid throwing errors for expected edge cases
|
|
70
|
+
|
|
71
|
+
### Comments
|
|
72
|
+
- Use `//` for single-line comments
|
|
73
|
+
- Add descriptive headers for sections: `// Public functions`, `// Module requires`
|
|
74
|
+
- JSDoc-style comments acceptable but not required
|
|
75
|
+
|
|
76
|
+
## File Organization
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
src/
|
|
80
|
+
cache.js # Main middleware implementation
|
|
81
|
+
test/
|
|
82
|
+
cache.js # Integration tests
|
|
83
|
+
unit/
|
|
84
|
+
cache.js # Unit tests for internal functions
|
|
85
|
+
mocks/
|
|
86
|
+
response.js # Mock Express response object
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Dependencies
|
|
90
|
+
|
|
91
|
+
Production:
|
|
92
|
+
- express: ^4.18.2
|
|
93
|
+
- ms: ^2.1.3
|
|
94
|
+
|
|
95
|
+
Development:
|
|
96
|
+
- mocha: ^10.2.0
|
|
97
|
+
- chai: ^4.3.7
|
|
98
|
+
- mock-res: ^0.6.0
|
|
99
|
+
|
|
100
|
+
## Important Notes
|
|
101
|
+
|
|
102
|
+
- Default TTL is "1h" (3600 seconds) when not specified
|
|
103
|
+
- Uses `ms` library for human-readable time parsing
|
|
104
|
+
- Middleware follows Express convention: `(req, res, next) => {}`
|
|
105
|
+
- Supports both `res.setHeader()` and `res.set()` methods
|
|
106
|
+
- Always exports internal functions for testability
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "express-cache-ctrl",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.9",
|
|
4
4
|
"description": "Express middleware to handle content expiration using Cache-Control header.",
|
|
5
5
|
"main": "src/cache.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "mocha test
|
|
7
|
+
"test": "mocha 'test/**/*.js'"
|
|
8
8
|
},
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
@@ -22,13 +22,13 @@
|
|
|
22
22
|
"author": "Carlos Luis Castro Márquez <carlosluiscastro@gmail.com>",
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"express": "^4.
|
|
25
|
+
"express": "^4.22.1",
|
|
26
26
|
"ms": "^2.1.3"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"chai": "^4.
|
|
30
|
-
"mocha": "^10.2
|
|
29
|
+
"chai": "^4.5.0",
|
|
30
|
+
"mocha": "^10.8.2",
|
|
31
31
|
"mock-res": "^0.6.0",
|
|
32
|
-
"morgan": "^1.10.
|
|
32
|
+
"morgan": "^1.10.1"
|
|
33
33
|
}
|
|
34
34
|
}
|
package/src/cache.js
CHANGED
package/test/cache.js
CHANGED
|
@@ -154,6 +154,123 @@ describe("Cache Middleware", function () {
|
|
|
154
154
|
});
|
|
155
155
|
});
|
|
156
156
|
|
|
157
|
+
describe("Edge Cases", function () {
|
|
158
|
+
it("cache private with TTL = 0 defaults to defaultTTL", function (done) {
|
|
159
|
+
const middleware = cache.private(0);
|
|
160
|
+
runMiddleware(middleware, function (res) {
|
|
161
|
+
const cacheControl = res.get("Cache-Control");
|
|
162
|
+
const controls = parseCacheControl(cacheControl);
|
|
163
|
+
const defaultTtlSeconds = cache.toTimespan(cache.defaultTTL);
|
|
164
|
+
// 0 is falsy, so it defaults to defaultTTL (1h = 3600)
|
|
165
|
+
expect(controls).to.property("max-age").and.to.equal(defaultTtlSeconds);
|
|
166
|
+
done();
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("cache public with string TTL '1d'", function (done) {
|
|
171
|
+
const middleware = cache.public("1d");
|
|
172
|
+
runMiddleware(middleware, function (res) {
|
|
173
|
+
const cacheControl = res.get("Cache-Control");
|
|
174
|
+
const controls = parseCacheControl(cacheControl);
|
|
175
|
+
expect(controls).to.property("max-age").and.to.equal(86400);
|
|
176
|
+
expect(controls).to.property("s-maxage").and.to.equal(86400);
|
|
177
|
+
done();
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("cache public with string TTL '2h'", function (done) {
|
|
182
|
+
const middleware = cache.public("2h");
|
|
183
|
+
runMiddleware(middleware, function (res) {
|
|
184
|
+
const cacheControl = res.get("Cache-Control");
|
|
185
|
+
const controls = parseCacheControl(cacheControl);
|
|
186
|
+
expect(controls).to.property("max-age").and.to.equal(7200);
|
|
187
|
+
expect(controls).to.property("s-maxage").and.to.equal(7200);
|
|
188
|
+
done();
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("cache public with string TTL '30m'", function (done) {
|
|
193
|
+
const middleware = cache.public("30m");
|
|
194
|
+
runMiddleware(middleware, function (res) {
|
|
195
|
+
const cacheControl = res.get("Cache-Control");
|
|
196
|
+
const controls = parseCacheControl(cacheControl);
|
|
197
|
+
expect(controls).to.property("max-age").and.to.equal(1800);
|
|
198
|
+
expect(controls).to.property("s-maxage").and.to.equal(1800);
|
|
199
|
+
done();
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("cache custom with no options", function (done) {
|
|
204
|
+
const middleware = cache.custom();
|
|
205
|
+
runMiddleware(middleware, function (res) {
|
|
206
|
+
const cacheControl = res.get("Cache-Control");
|
|
207
|
+
expect(cacheControl).to.not.be.null;
|
|
208
|
+
expect(cacheControl).to.be.a("string");
|
|
209
|
+
done();
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it("cache custom with empty options", function (done) {
|
|
214
|
+
const middleware = cache.custom({});
|
|
215
|
+
runMiddleware(middleware, function (res) {
|
|
216
|
+
const cacheControl = res.get("Cache-Control");
|
|
217
|
+
expect(cacheControl).to.not.be.null;
|
|
218
|
+
const controls = parseCacheControl(cacheControl);
|
|
219
|
+
expect(controls).to.property("private");
|
|
220
|
+
done();
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it("should remove Pragma header when noCache is false", function (done) {
|
|
225
|
+
const middleware = cache.private(3600);
|
|
226
|
+
const res = new Response();
|
|
227
|
+
// Set Pragma header first
|
|
228
|
+
res.setHeader("Pragma", "no-cache");
|
|
229
|
+
middleware.call(middleware, {}, res, function () {
|
|
230
|
+
const pragma = res.get("Pragma");
|
|
231
|
+
expect(pragma).to.be.undefined;
|
|
232
|
+
done();
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it("should call next() callback", function (done) {
|
|
237
|
+
const middleware = cache.private(3600);
|
|
238
|
+
const res = new Response();
|
|
239
|
+
let nextCalled = false;
|
|
240
|
+
middleware.call(middleware, {}, res, function () {
|
|
241
|
+
nextCalled = true;
|
|
242
|
+
expect(nextCalled).to.be.true;
|
|
243
|
+
done();
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it("cache public with 1 week TTL", function (done) {
|
|
248
|
+
const middleware = cache.public("1w");
|
|
249
|
+
runMiddleware(middleware, function (res) {
|
|
250
|
+
const cacheControl = res.get("Cache-Control");
|
|
251
|
+
const controls = parseCacheControl(cacheControl);
|
|
252
|
+
expect(controls).to.property("max-age").and.to.equal(604800);
|
|
253
|
+
expect(controls).to.property("s-maxage").and.to.equal(604800);
|
|
254
|
+
done();
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it("cache custom with different max-age and s-maxage", function (done) {
|
|
259
|
+
const middleware = cache.custom({
|
|
260
|
+
scope: "public",
|
|
261
|
+
ttl: "2h",
|
|
262
|
+
sttl: "1h",
|
|
263
|
+
});
|
|
264
|
+
runMiddleware(middleware, function (res) {
|
|
265
|
+
const cacheControl = res.get("Cache-Control");
|
|
266
|
+
const controls = parseCacheControl(cacheControl);
|
|
267
|
+
expect(controls).to.property("max-age").and.to.equal(7200);
|
|
268
|
+
expect(controls).to.property("s-maxage").and.to.equal(3600);
|
|
269
|
+
done();
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
|
|
157
274
|
function runMiddleware(middleware, callback) {
|
|
158
275
|
const res = new Response();
|
|
159
276
|
middleware.call(middleware, {}, res, function () {
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
const { expect } = require("chai");
|
|
2
|
+
const cache = require("../../src/cache");
|
|
3
|
+
|
|
4
|
+
describe("Cache Internal Functions", function () {
|
|
5
|
+
describe("toTimespan()", function () {
|
|
6
|
+
describe("numeric inputs", function () {
|
|
7
|
+
it("should return numeric value as-is for positive integers", function () {
|
|
8
|
+
expect(cache.toTimespan(3600)).to.equal(3600);
|
|
9
|
+
expect(cache.toTimespan(60)).to.equal(60);
|
|
10
|
+
expect(cache.toTimespan(1)).to.equal(1);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("should return numeric value for large numbers", function () {
|
|
14
|
+
expect(cache.toTimespan(86400)).to.equal(86400);
|
|
15
|
+
expect(cache.toTimespan(31536000)).to.equal(31536000);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("should return 0 for zero value", function () {
|
|
19
|
+
expect(cache.toTimespan(0)).to.equal(0);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe("string inputs", function () {
|
|
24
|
+
it("should convert days to seconds", function () {
|
|
25
|
+
expect(cache.toTimespan("1d")).to.equal(86400);
|
|
26
|
+
expect(cache.toTimespan("2d")).to.equal(172800);
|
|
27
|
+
expect(cache.toTimespan("7d")).to.equal(604800);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("should convert hours to seconds", function () {
|
|
31
|
+
expect(cache.toTimespan("1h")).to.equal(3600);
|
|
32
|
+
expect(cache.toTimespan("2h")).to.equal(7200);
|
|
33
|
+
expect(cache.toTimespan("24h")).to.equal(86400);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should convert minutes to seconds", function () {
|
|
37
|
+
expect(cache.toTimespan("1m")).to.equal(60);
|
|
38
|
+
expect(cache.toTimespan("30m")).to.equal(1800);
|
|
39
|
+
expect(cache.toTimespan("60m")).to.equal(3600);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("should convert seconds to seconds", function () {
|
|
43
|
+
expect(cache.toTimespan("1s")).to.equal(1);
|
|
44
|
+
expect(cache.toTimespan("30s")).to.equal(30);
|
|
45
|
+
expect(cache.toTimespan("60s")).to.equal(60);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("should convert weeks to seconds", function () {
|
|
49
|
+
expect(cache.toTimespan("1w")).to.equal(604800);
|
|
50
|
+
expect(cache.toTimespan("2w")).to.equal(1209600);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("should convert milliseconds to seconds", function () {
|
|
54
|
+
expect(cache.toTimespan("1000ms")).to.equal(1);
|
|
55
|
+
expect(cache.toTimespan("60000ms")).to.equal(60);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("should return NaN for compound time strings (not supported)", function () {
|
|
59
|
+
// The ms library doesn't support compound time strings
|
|
60
|
+
expect(cache.toTimespan("1h30m")).to.be.NaN;
|
|
61
|
+
expect(cache.toTimespan("1d12h")).to.be.NaN;
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe("edge cases", function () {
|
|
66
|
+
it("should handle negative numbers", function () {
|
|
67
|
+
expect(cache.toTimespan(-3600)).to.equal(-3600);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("should return NaN for invalid string input", function () {
|
|
71
|
+
expect(cache.toTimespan("invalid")).to.be.NaN;
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("should handle floating point numbers", function () {
|
|
75
|
+
expect(cache.toTimespan(3600.5)).to.equal(3600);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe("generateHeader()", function () {
|
|
81
|
+
describe("scope handling", function () {
|
|
82
|
+
it("should add public scope when specified", function () {
|
|
83
|
+
const result = cache.generateHeader({ scope: "public" });
|
|
84
|
+
expect(result).to.include("public");
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("should add private scope when specified", function () {
|
|
88
|
+
const result = cache.generateHeader({ scope: "private" });
|
|
89
|
+
expect(result).to.include("private");
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("should default to private when no scope is specified and not no-cache", function () {
|
|
93
|
+
const result = cache.generateHeader({ ttl: 3600 });
|
|
94
|
+
expect(result).to.include("private");
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe("noCache handling", function () {
|
|
99
|
+
it("should add no-cache and no-store when noCache is true", function () {
|
|
100
|
+
const result = cache.generateHeader({ noCache: true });
|
|
101
|
+
expect(result).to.include("no-cache");
|
|
102
|
+
expect(result).to.include("no-store");
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("should not add max-age when noCache is true", function () {
|
|
106
|
+
const result = cache.generateHeader({ noCache: true, ttl: 3600 });
|
|
107
|
+
const hasMaxAge = result.some(item => item.startsWith("max-age="));
|
|
108
|
+
expect(hasMaxAge).to.be.false;
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("should not add private scope when noCache is true without explicit scope", function () {
|
|
112
|
+
const result = cache.generateHeader({ noCache: true });
|
|
113
|
+
expect(result).to.not.include("private");
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("should respect explicit scope even with noCache", function () {
|
|
117
|
+
const result = cache.generateHeader({ noCache: true, scope: "public" });
|
|
118
|
+
expect(result).to.include("public");
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe("TTL handling", function () {
|
|
123
|
+
it("should add max-age with numeric TTL", function () {
|
|
124
|
+
const result = cache.generateHeader({ ttl: 3600 });
|
|
125
|
+
expect(result).to.include("max-age=3600");
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("should add max-age with string TTL", function () {
|
|
129
|
+
const result = cache.generateHeader({ ttl: "1h" });
|
|
130
|
+
expect(result).to.include("max-age=3600");
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("should use default TTL when not specified", function () {
|
|
134
|
+
const result = cache.generateHeader({});
|
|
135
|
+
const defaultTtlSeconds = cache.toTimespan(cache.defaultTTL);
|
|
136
|
+
expect(result).to.include(`max-age=${defaultTtlSeconds}`);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("should add s-maxage when sttl is specified", function () {
|
|
140
|
+
const result = cache.generateHeader({ ttl: 3600, sttl: 7200 });
|
|
141
|
+
expect(result).to.include("s-maxage=7200");
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("should add s-maxage with string sttl", function () {
|
|
145
|
+
const result = cache.generateHeader({ ttl: 3600, sttl: "2h" });
|
|
146
|
+
expect(result).to.include("s-maxage=7200");
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
describe("revalidation flags", function () {
|
|
151
|
+
it("should add must-revalidate when specified", function () {
|
|
152
|
+
const result = cache.generateHeader({ mustRevalidate: true });
|
|
153
|
+
expect(result).to.include("must-revalidate");
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it("should add proxy-revalidate when specified", function () {
|
|
157
|
+
const result = cache.generateHeader({ proxyRevalidate: true });
|
|
158
|
+
expect(result).to.include("proxy-revalidate");
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("should add both revalidation flags when both specified", function () {
|
|
162
|
+
const result = cache.generateHeader({
|
|
163
|
+
mustRevalidate: true,
|
|
164
|
+
proxyRevalidate: true,
|
|
165
|
+
});
|
|
166
|
+
expect(result).to.include("must-revalidate");
|
|
167
|
+
expect(result).to.include("proxy-revalidate");
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("should not add revalidation flags when not specified", function () {
|
|
171
|
+
const result = cache.generateHeader({ ttl: 3600 });
|
|
172
|
+
expect(result).to.not.include("must-revalidate");
|
|
173
|
+
expect(result).to.not.include("proxy-revalidate");
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
describe("no-transform flag", function () {
|
|
178
|
+
it("should add no-transform when specified", function () {
|
|
179
|
+
const result = cache.generateHeader({ noTransform: true });
|
|
180
|
+
expect(result).to.include("no-transform");
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it("should not add no-transform when not specified", function () {
|
|
184
|
+
const result = cache.generateHeader({ ttl: 3600 });
|
|
185
|
+
expect(result).to.not.include("no-transform");
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
describe("complex scenarios", function () {
|
|
190
|
+
it("should generate correct header for public cache with all options", function () {
|
|
191
|
+
const result = cache.generateHeader({
|
|
192
|
+
scope: "public",
|
|
193
|
+
ttl: 3600,
|
|
194
|
+
sttl: 7200,
|
|
195
|
+
mustRevalidate: true,
|
|
196
|
+
proxyRevalidate: true,
|
|
197
|
+
noTransform: true,
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
expect(result).to.include("public");
|
|
201
|
+
expect(result).to.include("max-age=3600");
|
|
202
|
+
expect(result).to.include("s-maxage=7200");
|
|
203
|
+
expect(result).to.include("must-revalidate");
|
|
204
|
+
expect(result).to.include("proxy-revalidate");
|
|
205
|
+
expect(result).to.include("no-transform");
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it("should generate correct header for disabled cache", function () {
|
|
209
|
+
const result = cache.generateHeader({
|
|
210
|
+
noCache: true,
|
|
211
|
+
mustRevalidate: true,
|
|
212
|
+
proxyRevalidate: true,
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
expect(result).to.include("no-cache");
|
|
216
|
+
expect(result).to.include("no-store");
|
|
217
|
+
expect(result).to.include("must-revalidate");
|
|
218
|
+
expect(result).to.include("proxy-revalidate");
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it("should generate correct header for secure cache", function () {
|
|
222
|
+
const result = cache.generateHeader({
|
|
223
|
+
scope: "private",
|
|
224
|
+
noCache: true,
|
|
225
|
+
mustRevalidate: true,
|
|
226
|
+
noTransform: true,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
expect(result).to.include("private");
|
|
230
|
+
expect(result).to.include("no-cache");
|
|
231
|
+
expect(result).to.include("no-store");
|
|
232
|
+
expect(result).to.include("must-revalidate");
|
|
233
|
+
expect(result).to.include("no-transform");
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it("should handle empty options object", function () {
|
|
237
|
+
const result = cache.generateHeader({});
|
|
238
|
+
expect(result).to.be.an("array");
|
|
239
|
+
expect(result.length).to.be.greaterThan(0);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it("should throw error for undefined options", function () {
|
|
243
|
+
// The code doesn't handle undefined, which is expected behavior
|
|
244
|
+
expect(() => cache.generateHeader(undefined)).to.throw(TypeError);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it("should throw error for null options", function () {
|
|
248
|
+
// The code doesn't handle null, which is expected behavior
|
|
249
|
+
expect(() => cache.generateHeader(null)).to.throw(TypeError);
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
});
|