@fastify/static 5.0.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/.gitattributes +5 -0
- package/.github/dependabot.yml +13 -0
- package/.github/stale.yml +21 -0
- package/.github/workflows/ci.yml +46 -0
- package/LICENSE +21 -0
- package/README.md +440 -0
- package/example/public/images/sample.jpg +0 -0
- package/example/public/index.css +9 -0
- package/example/public/index.html +11 -0
- package/example/public/index.js +8 -0
- package/example/public2/test.css +4 -0
- package/example/public2/test.html +8 -0
- package/example/server-compress.js +15 -0
- package/example/server-dir-list.js +49 -0
- package/example/server.js +13 -0
- package/index.d.ts +98 -0
- package/index.js +509 -0
- package/lib/dirList.js +199 -0
- package/package.json +71 -0
- package/test/dir-list.test.js +675 -0
- package/test/static/.example +1 -0
- package/test/static/a .md +1 -0
- package/test/static/deep/path/for/test/index.html +5 -0
- package/test/static/deep/path/for/test/purpose/foo.html +5 -0
- package/test/static/foo.html +3 -0
- package/test/static/foobar.html +3 -0
- package/test/static/index.css +0 -0
- package/test/static/index.html +5 -0
- package/test/static/shallow/sample.jpg +0 -0
- package/test/static-pre-compressed/all-three.html +5 -0
- package/test/static-pre-compressed/all-three.html.br +0 -0
- package/test/static-pre-compressed/all-three.html.gz +0 -0
- package/test/static-pre-compressed/dir/index.html +5 -0
- package/test/static-pre-compressed/dir/index.html.br +0 -0
- package/test/static-pre-compressed/empty/.gitkeep +0 -0
- package/test/static-pre-compressed/gzip-only.html +3 -0
- package/test/static-pre-compressed/gzip-only.html.gz +0 -0
- package/test/static-pre-compressed/index.html +5 -0
- package/test/static-pre-compressed/index.html.br +0 -0
- package/test/static-pre-compressed/sample.jpg +0 -0
- package/test/static-pre-compressed/sample.jpg.br +0 -0
- package/test/static-pre-compressed/uncompressed.html +3 -0
- package/test/static.test.js +3482 -0
- package/test/static2/bar.html +3 -0
- package/test/static2/index.html +3 -0
- package/test/types/index.ts +105 -0
|
@@ -0,0 +1,675 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/* eslint n/no-deprecated-api: "off" */
|
|
4
|
+
|
|
5
|
+
const fs = require('fs')
|
|
6
|
+
const path = require('path')
|
|
7
|
+
const t = require('tap')
|
|
8
|
+
const simple = require('simple-get')
|
|
9
|
+
const Fastify = require('fastify')
|
|
10
|
+
|
|
11
|
+
const fastifyStatic = require('..')
|
|
12
|
+
const dirList = require('../lib/dirList')
|
|
13
|
+
|
|
14
|
+
const helper = {
|
|
15
|
+
arrange: function (t, options, f) {
|
|
16
|
+
return helper.arrangeModule(t, options, fastifyStatic, f)
|
|
17
|
+
},
|
|
18
|
+
arrangeModule: function (t, options, mock, f) {
|
|
19
|
+
const fastify = Fastify()
|
|
20
|
+
fastify.register(mock, options)
|
|
21
|
+
t.teardown(fastify.close.bind(fastify))
|
|
22
|
+
fastify.listen(0, err => {
|
|
23
|
+
t.error(err)
|
|
24
|
+
fastify.server.unref()
|
|
25
|
+
f('http://localhost:' + fastify.server.address().port)
|
|
26
|
+
})
|
|
27
|
+
return f
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
fs.mkdirSync(path.join(__dirname, 'static/shallow/empty'))
|
|
33
|
+
} catch (error) {}
|
|
34
|
+
|
|
35
|
+
t.test('throws when `root` is an array', t => {
|
|
36
|
+
t.plan(2)
|
|
37
|
+
|
|
38
|
+
const err = dirList.validateOptions({ root: ['hello', 'world'], list: true })
|
|
39
|
+
t.type(err, TypeError)
|
|
40
|
+
t.equal(err.message, 'multi-root with list option is not supported')
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
t.test('throws when `list.format option` is invalid', t => {
|
|
44
|
+
t.plan(2)
|
|
45
|
+
|
|
46
|
+
const err = dirList.validateOptions({ list: { format: 'hello' } })
|
|
47
|
+
t.type(err, TypeError)
|
|
48
|
+
t.equal(err.message, 'The `list.format` option must be json or html')
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
t.test('throws when `list.names option` is not an array', t => {
|
|
52
|
+
t.plan(2)
|
|
53
|
+
|
|
54
|
+
const err = dirList.validateOptions({ list: { names: 'hello' } })
|
|
55
|
+
t.type(err, TypeError)
|
|
56
|
+
t.equal(err.message, 'The `list.names` option must be an array')
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
t.test('throws when `list.format` is html and `list render` is not a function', t => {
|
|
60
|
+
t.plan(2)
|
|
61
|
+
|
|
62
|
+
const err = dirList.validateOptions({ list: { format: 'html', render: 'hello' } })
|
|
63
|
+
t.type(err, TypeError)
|
|
64
|
+
t.equal(err.message, 'The `list.render` option must be a function and is required with html format')
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
t.test('dir list wrong options', t => {
|
|
68
|
+
t.plan(3)
|
|
69
|
+
|
|
70
|
+
const cases = [
|
|
71
|
+
{
|
|
72
|
+
options: {
|
|
73
|
+
root: path.join(__dirname, '/static'),
|
|
74
|
+
prefix: '/public',
|
|
75
|
+
list: {
|
|
76
|
+
format: 'no-json,no-html'
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
error: new TypeError('The `list.format` option must be json or html')
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
options: {
|
|
83
|
+
root: path.join(__dirname, '/static'),
|
|
84
|
+
list: {
|
|
85
|
+
format: 'html'
|
|
86
|
+
// no render function
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
error: new TypeError('The `list.render` option must be a function and is required with html format')
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
options: {
|
|
93
|
+
root: path.join(__dirname, '/static'),
|
|
94
|
+
list: {
|
|
95
|
+
names: 'not-an-array'
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
error: new TypeError('The `list.names` option must be an array')
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
for (const case_ of cases) {
|
|
103
|
+
const fastify = Fastify()
|
|
104
|
+
fastify.register(fastifyStatic, case_.options)
|
|
105
|
+
fastify.listen(0, err => {
|
|
106
|
+
t.equal(err.message, case_.error.message)
|
|
107
|
+
fastify.server.unref()
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
t.test('dir list default options', t => {
|
|
113
|
+
t.plan(2)
|
|
114
|
+
|
|
115
|
+
const options = {
|
|
116
|
+
root: path.join(__dirname, '/static'),
|
|
117
|
+
prefix: '/public',
|
|
118
|
+
list: true
|
|
119
|
+
}
|
|
120
|
+
const route = '/public/shallow'
|
|
121
|
+
const content = { dirs: ['empty'], files: ['sample.jpg'] }
|
|
122
|
+
|
|
123
|
+
helper.arrange(t, options, (url) => {
|
|
124
|
+
t.test(route, t => {
|
|
125
|
+
t.plan(3)
|
|
126
|
+
simple.concat({
|
|
127
|
+
method: 'GET',
|
|
128
|
+
url: url + route
|
|
129
|
+
}, (err, response, body) => {
|
|
130
|
+
t.error(err)
|
|
131
|
+
t.equal(response.statusCode, 200)
|
|
132
|
+
t.equal(body.toString(), JSON.stringify(content))
|
|
133
|
+
})
|
|
134
|
+
})
|
|
135
|
+
})
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
t.test('dir list, custom options', t => {
|
|
139
|
+
t.plan(2)
|
|
140
|
+
|
|
141
|
+
const options = {
|
|
142
|
+
root: path.join(__dirname, '/static'),
|
|
143
|
+
prefix: '/public',
|
|
144
|
+
index: false,
|
|
145
|
+
list: true
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const route = '/public/'
|
|
149
|
+
const content = { dirs: ['deep', 'shallow'], files: ['.example', 'a .md', 'foo.html', 'foobar.html', 'index.css', 'index.html'] }
|
|
150
|
+
|
|
151
|
+
helper.arrange(t, options, (url) => {
|
|
152
|
+
t.test(route, t => {
|
|
153
|
+
t.plan(3)
|
|
154
|
+
simple.concat({
|
|
155
|
+
method: 'GET',
|
|
156
|
+
url: url + route
|
|
157
|
+
}, (err, response, body) => {
|
|
158
|
+
t.error(err)
|
|
159
|
+
t.equal(response.statusCode, 200)
|
|
160
|
+
t.equal(body.toString(), JSON.stringify(content))
|
|
161
|
+
})
|
|
162
|
+
})
|
|
163
|
+
})
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
t.test('dir list html format', t => {
|
|
167
|
+
t.plan(6)
|
|
168
|
+
|
|
169
|
+
// render html in 2 ways: one with handlebars and one with template string
|
|
170
|
+
|
|
171
|
+
const Handlebars = require('handlebars')
|
|
172
|
+
const source = `
|
|
173
|
+
<html><body>
|
|
174
|
+
<ul>
|
|
175
|
+
{{#dirs}}
|
|
176
|
+
<li><a href="{{href}}">{{name}}</a></li>
|
|
177
|
+
{{/dirs}}
|
|
178
|
+
</ul>
|
|
179
|
+
<ul>
|
|
180
|
+
{{#files}}
|
|
181
|
+
<li><a href="{{href}}" target="_blank">{{name}}</a></li>
|
|
182
|
+
{{/files}}
|
|
183
|
+
</ul>
|
|
184
|
+
</body></html>
|
|
185
|
+
`
|
|
186
|
+
const handlebarTemplate = Handlebars.compile(source)
|
|
187
|
+
const templates = [
|
|
188
|
+
{
|
|
189
|
+
render: (dirs, files) => {
|
|
190
|
+
return handlebarTemplate({ dirs, files })
|
|
191
|
+
},
|
|
192
|
+
output: `
|
|
193
|
+
<html><body>
|
|
194
|
+
<ul>
|
|
195
|
+
<li><a href="/public/deep">deep</a></li>
|
|
196
|
+
<li><a href="/public/shallow">shallow</a></li>
|
|
197
|
+
</ul>
|
|
198
|
+
<ul>
|
|
199
|
+
<li><a href="/public/.example" target="_blank">.example</a></li>
|
|
200
|
+
<li><a href="/public/a .md" target="_blank">a .md</a></li>
|
|
201
|
+
<li><a href="/public/foo.html" target="_blank">foo.html</a></li>
|
|
202
|
+
<li><a href="/public/foobar.html" target="_blank">foobar.html</a></li>
|
|
203
|
+
<li><a href="/public/index.css" target="_blank">index.css</a></li>
|
|
204
|
+
<li><a href="/public/index.html" target="_blank">index.html</a></li>
|
|
205
|
+
</ul>
|
|
206
|
+
</body></html>
|
|
207
|
+
`
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
{
|
|
211
|
+
render: (dirs, files) => {
|
|
212
|
+
return `
|
|
213
|
+
<html><body>
|
|
214
|
+
<ul>
|
|
215
|
+
${dirs.map(dir => `<li><a href="${dir.href}">${dir.name}</a></li>`).join('\n ')}
|
|
216
|
+
</ul>
|
|
217
|
+
<ul>
|
|
218
|
+
${files.map(file => `<li><a href="${file.href}" target="_blank">${file.name}</a></li>`).join('\n ')}
|
|
219
|
+
</ul>
|
|
220
|
+
</body></html>
|
|
221
|
+
`
|
|
222
|
+
},
|
|
223
|
+
output: `
|
|
224
|
+
<html><body>
|
|
225
|
+
<ul>
|
|
226
|
+
<li><a href="/public/deep">deep</a></li>
|
|
227
|
+
<li><a href="/public/shallow">shallow</a></li>
|
|
228
|
+
</ul>
|
|
229
|
+
<ul>
|
|
230
|
+
<li><a href="/public/.example" target="_blank">.example</a></li>
|
|
231
|
+
<li><a href="/public/a .md" target="_blank">a .md</a></li>
|
|
232
|
+
<li><a href="/public/foo.html" target="_blank">foo.html</a></li>
|
|
233
|
+
<li><a href="/public/foobar.html" target="_blank">foobar.html</a></li>
|
|
234
|
+
<li><a href="/public/index.css" target="_blank">index.css</a></li>
|
|
235
|
+
<li><a href="/public/index.html" target="_blank">index.html</a></li>
|
|
236
|
+
</ul>
|
|
237
|
+
</body></html>
|
|
238
|
+
`
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
]
|
|
242
|
+
|
|
243
|
+
for (const template of templates) {
|
|
244
|
+
const options = {
|
|
245
|
+
root: path.join(__dirname, '/static'),
|
|
246
|
+
prefix: '/public',
|
|
247
|
+
index: false,
|
|
248
|
+
list: {
|
|
249
|
+
format: 'html',
|
|
250
|
+
names: ['index', 'index.htm'],
|
|
251
|
+
render: template.render
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
const routes = ['/public/index.htm', '/public/index']
|
|
255
|
+
|
|
256
|
+
// check all routes by names
|
|
257
|
+
|
|
258
|
+
helper.arrange(t, options, (url) => {
|
|
259
|
+
for (const route of routes) {
|
|
260
|
+
t.test(route, t => {
|
|
261
|
+
t.plan(3)
|
|
262
|
+
simple.concat({
|
|
263
|
+
method: 'GET',
|
|
264
|
+
url: url + route
|
|
265
|
+
}, (err, response, body) => {
|
|
266
|
+
t.error(err)
|
|
267
|
+
t.equal(response.statusCode, 200)
|
|
268
|
+
t.equal(body.toString(), template.output)
|
|
269
|
+
})
|
|
270
|
+
})
|
|
271
|
+
}
|
|
272
|
+
})
|
|
273
|
+
}
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
t.test('dir list href nested structure', t => {
|
|
277
|
+
t.plan(6)
|
|
278
|
+
|
|
279
|
+
const options = {
|
|
280
|
+
root: path.join(__dirname, '/static'),
|
|
281
|
+
prefix: '/public',
|
|
282
|
+
index: false,
|
|
283
|
+
list: {
|
|
284
|
+
format: 'html',
|
|
285
|
+
names: ['index', 'index.htm'],
|
|
286
|
+
render (dirs, files) {
|
|
287
|
+
return dirs[0].href
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const routes = [
|
|
293
|
+
{ path: '/public/', response: '/public/deep' },
|
|
294
|
+
{ path: '/public/index', response: '/public/deep' },
|
|
295
|
+
{ path: '/public/deep/', response: '/public/deep/path' },
|
|
296
|
+
{ path: '/public/deep/index.htm', response: '/public/deep/path' },
|
|
297
|
+
{ path: '/public/deep/path/', response: '/public/deep/path/for' }
|
|
298
|
+
]
|
|
299
|
+
helper.arrange(t, options, (url) => {
|
|
300
|
+
for (const route of routes) {
|
|
301
|
+
t.test(route.path, t => {
|
|
302
|
+
t.plan(5)
|
|
303
|
+
simple.concat({
|
|
304
|
+
method: 'GET',
|
|
305
|
+
url: url + route.path
|
|
306
|
+
}, (err, response, body) => {
|
|
307
|
+
t.error(err)
|
|
308
|
+
t.equal(response.statusCode, 200)
|
|
309
|
+
t.equal(body.toString(), route.response)
|
|
310
|
+
simple.concat({
|
|
311
|
+
method: 'GET',
|
|
312
|
+
url: url + body.toString()
|
|
313
|
+
}, (err, response, body) => {
|
|
314
|
+
t.error(err)
|
|
315
|
+
t.equal(response.statusCode, 200)
|
|
316
|
+
})
|
|
317
|
+
})
|
|
318
|
+
})
|
|
319
|
+
}
|
|
320
|
+
})
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
t.test('dir list html format - stats', t => {
|
|
324
|
+
t.plan(7)
|
|
325
|
+
|
|
326
|
+
const options1 = {
|
|
327
|
+
root: path.join(__dirname, '/static'),
|
|
328
|
+
prefix: '/public',
|
|
329
|
+
index: false,
|
|
330
|
+
list: {
|
|
331
|
+
format: 'html',
|
|
332
|
+
render (dirs, files) {
|
|
333
|
+
t.ok(dirs.length > 0)
|
|
334
|
+
t.ok(files.length > 0)
|
|
335
|
+
|
|
336
|
+
t.ok(dirs.every(every))
|
|
337
|
+
t.ok(files.every(every))
|
|
338
|
+
|
|
339
|
+
function every (value) {
|
|
340
|
+
return value.stats &&
|
|
341
|
+
value.stats.atime &&
|
|
342
|
+
!value.extendedInfo
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const route = '/public/'
|
|
349
|
+
|
|
350
|
+
helper.arrange(t, options1, (url) => {
|
|
351
|
+
simple.concat({
|
|
352
|
+
method: 'GET',
|
|
353
|
+
url: url + route
|
|
354
|
+
}, (err, response, body) => {
|
|
355
|
+
t.error(err)
|
|
356
|
+
t.equal(response.statusCode, 200)
|
|
357
|
+
})
|
|
358
|
+
})
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
t.test('dir list html format - extended info', t => {
|
|
362
|
+
t.plan(4)
|
|
363
|
+
|
|
364
|
+
const route = '/public/'
|
|
365
|
+
|
|
366
|
+
const options = {
|
|
367
|
+
root: path.join(__dirname, '/static'),
|
|
368
|
+
prefix: '/public',
|
|
369
|
+
index: false,
|
|
370
|
+
list: {
|
|
371
|
+
format: 'html',
|
|
372
|
+
extendedFolderInfo: true,
|
|
373
|
+
render (dirs, files) {
|
|
374
|
+
t.test('dirs', t => {
|
|
375
|
+
t.plan(dirs.length * 7)
|
|
376
|
+
|
|
377
|
+
for (const value of dirs) {
|
|
378
|
+
t.ok(value.extendedInfo)
|
|
379
|
+
|
|
380
|
+
t.equal(typeof value.extendedInfo.fileCount, 'number')
|
|
381
|
+
t.equal(typeof value.extendedInfo.totalFileCount, 'number')
|
|
382
|
+
t.equal(typeof value.extendedInfo.folderCount, 'number')
|
|
383
|
+
t.equal(typeof value.extendedInfo.totalFolderCount, 'number')
|
|
384
|
+
t.equal(typeof value.extendedInfo.totalSize, 'number')
|
|
385
|
+
t.equal(typeof value.extendedInfo.lastModified, 'number')
|
|
386
|
+
}
|
|
387
|
+
})
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
helper.arrange(t, options, (url) => {
|
|
393
|
+
simple.concat({
|
|
394
|
+
method: 'GET',
|
|
395
|
+
url: url + route
|
|
396
|
+
}, (err, response, body) => {
|
|
397
|
+
t.error(err)
|
|
398
|
+
t.equal(response.statusCode, 200)
|
|
399
|
+
})
|
|
400
|
+
})
|
|
401
|
+
})
|
|
402
|
+
|
|
403
|
+
t.test('dir list json format', t => {
|
|
404
|
+
t.plan(2)
|
|
405
|
+
|
|
406
|
+
const options = {
|
|
407
|
+
root: path.join(__dirname, '/static'),
|
|
408
|
+
prefix: '/public',
|
|
409
|
+
prefixAvoidTrailingSlash: true,
|
|
410
|
+
list: {
|
|
411
|
+
format: 'json',
|
|
412
|
+
names: ['index', 'index.json', '/']
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
const routes = ['/public/shallow/']
|
|
416
|
+
const content = { dirs: ['empty'], files: ['sample.jpg'] }
|
|
417
|
+
|
|
418
|
+
helper.arrange(t, options, (url) => {
|
|
419
|
+
for (const route of routes) {
|
|
420
|
+
t.test(route, t => {
|
|
421
|
+
t.plan(3)
|
|
422
|
+
simple.concat({
|
|
423
|
+
method: 'GET',
|
|
424
|
+
url: url + route
|
|
425
|
+
}, (err, response, body) => {
|
|
426
|
+
t.error(err)
|
|
427
|
+
t.equal(response.statusCode, 200)
|
|
428
|
+
t.equal(body.toString(), JSON.stringify(content))
|
|
429
|
+
})
|
|
430
|
+
})
|
|
431
|
+
}
|
|
432
|
+
})
|
|
433
|
+
})
|
|
434
|
+
|
|
435
|
+
t.test('dir list json format - extended info', t => {
|
|
436
|
+
t.plan(2)
|
|
437
|
+
|
|
438
|
+
const options = {
|
|
439
|
+
root: path.join(__dirname, '/static'),
|
|
440
|
+
prefix: '/public',
|
|
441
|
+
prefixAvoidTrailingSlash: true,
|
|
442
|
+
list: {
|
|
443
|
+
format: 'json',
|
|
444
|
+
names: ['index', 'index.json', '/'],
|
|
445
|
+
extendedFolderInfo: true,
|
|
446
|
+
jsonFormat: 'extended'
|
|
447
|
+
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
const routes = ['/public/shallow/']
|
|
451
|
+
|
|
452
|
+
helper.arrange(t, options, (url) => {
|
|
453
|
+
for (const route of routes) {
|
|
454
|
+
t.test(route, t => {
|
|
455
|
+
t.plan(5)
|
|
456
|
+
simple.concat({
|
|
457
|
+
method: 'GET',
|
|
458
|
+
url: url + route
|
|
459
|
+
}, (err, response, body) => {
|
|
460
|
+
t.error(err)
|
|
461
|
+
t.equal(response.statusCode, 200)
|
|
462
|
+
const bodyObject = JSON.parse(body.toString())
|
|
463
|
+
t.equal(bodyObject.dirs[0].name, 'empty')
|
|
464
|
+
t.equal(typeof bodyObject.dirs[0].stats.atime, 'string')
|
|
465
|
+
t.equal(typeof bodyObject.dirs[0].extendedInfo.totalSize, 'number')
|
|
466
|
+
})
|
|
467
|
+
})
|
|
468
|
+
}
|
|
469
|
+
})
|
|
470
|
+
})
|
|
471
|
+
|
|
472
|
+
t.test('dir list - url parameter format', t => {
|
|
473
|
+
t.plan(13)
|
|
474
|
+
|
|
475
|
+
const options = {
|
|
476
|
+
root: path.join(__dirname, '/static'),
|
|
477
|
+
prefix: '/public',
|
|
478
|
+
index: false,
|
|
479
|
+
list: {
|
|
480
|
+
format: 'html',
|
|
481
|
+
render (dirs, files) {
|
|
482
|
+
return 'html'
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
const route = '/public/'
|
|
487
|
+
|
|
488
|
+
helper.arrange(t, options, (url) => {
|
|
489
|
+
simple.concat({
|
|
490
|
+
method: 'GET',
|
|
491
|
+
url: url + route
|
|
492
|
+
}, (err, response, body) => {
|
|
493
|
+
t.error(err)
|
|
494
|
+
t.equal(response.statusCode, 200)
|
|
495
|
+
t.equal(body.toString(), 'html')
|
|
496
|
+
t.ok(response.headers['content-type'].includes('text/html'))
|
|
497
|
+
})
|
|
498
|
+
|
|
499
|
+
simple.concat({
|
|
500
|
+
method: 'GET',
|
|
501
|
+
url: url + route + '?format=html'
|
|
502
|
+
}, (err, response, body) => {
|
|
503
|
+
t.error(err)
|
|
504
|
+
t.equal(response.statusCode, 200)
|
|
505
|
+
t.equal(body.toString(), 'html')
|
|
506
|
+
t.ok(response.headers['content-type'].includes('text/html'))
|
|
507
|
+
})
|
|
508
|
+
|
|
509
|
+
simple.concat({
|
|
510
|
+
method: 'GET',
|
|
511
|
+
url: url + route + '?format=json'
|
|
512
|
+
}, (err, response, body) => {
|
|
513
|
+
t.error(err)
|
|
514
|
+
t.equal(response.statusCode, 200)
|
|
515
|
+
t.ok(body.toString())
|
|
516
|
+
t.ok(response.headers['content-type'].includes('application/json'))
|
|
517
|
+
})
|
|
518
|
+
})
|
|
519
|
+
})
|
|
520
|
+
|
|
521
|
+
t.test('dir list on empty dir', t => {
|
|
522
|
+
t.plan(2)
|
|
523
|
+
|
|
524
|
+
const options = {
|
|
525
|
+
root: path.join(__dirname, '/static'),
|
|
526
|
+
prefix: '/public',
|
|
527
|
+
list: true
|
|
528
|
+
}
|
|
529
|
+
const route = '/public/shallow/empty'
|
|
530
|
+
const content = { dirs: [], files: [] }
|
|
531
|
+
|
|
532
|
+
helper.arrange(t, options, (url) => {
|
|
533
|
+
t.test(route, t => {
|
|
534
|
+
t.plan(3)
|
|
535
|
+
simple.concat({
|
|
536
|
+
method: 'GET',
|
|
537
|
+
url: url + route
|
|
538
|
+
}, (err, response, body) => {
|
|
539
|
+
t.error(err)
|
|
540
|
+
t.equal(response.statusCode, 200)
|
|
541
|
+
t.equal(body.toString(), JSON.stringify(content))
|
|
542
|
+
})
|
|
543
|
+
})
|
|
544
|
+
})
|
|
545
|
+
})
|
|
546
|
+
|
|
547
|
+
t.test('dir list serve index.html on index option', t => {
|
|
548
|
+
t.plan(2)
|
|
549
|
+
|
|
550
|
+
const options = {
|
|
551
|
+
root: path.join(__dirname, '/static'),
|
|
552
|
+
prefix: '/public',
|
|
553
|
+
index: false,
|
|
554
|
+
list: {
|
|
555
|
+
format: 'html',
|
|
556
|
+
names: ['index', 'index.html'],
|
|
557
|
+
render: () => 'dir list index'
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
helper.arrange(t, options, (url) => {
|
|
562
|
+
t.test('serve index.html from fs', t => {
|
|
563
|
+
t.plan(6)
|
|
564
|
+
|
|
565
|
+
let route = '/public/index.html'
|
|
566
|
+
|
|
567
|
+
simple.concat({
|
|
568
|
+
method: 'GET',
|
|
569
|
+
url: url + route
|
|
570
|
+
}, (err, response, body) => {
|
|
571
|
+
t.error(err)
|
|
572
|
+
t.equal(response.statusCode, 200)
|
|
573
|
+
t.equal(body.toString(), '<html>\n <body>\n the body\n </body>\n</html>\n')
|
|
574
|
+
})
|
|
575
|
+
|
|
576
|
+
route = '/public/index'
|
|
577
|
+
simple.concat({
|
|
578
|
+
method: 'GET',
|
|
579
|
+
url: url + route
|
|
580
|
+
}, (err, response, body) => {
|
|
581
|
+
t.error(err)
|
|
582
|
+
t.equal(response.statusCode, 200)
|
|
583
|
+
t.equal(body.toString(), 'dir list index')
|
|
584
|
+
})
|
|
585
|
+
})
|
|
586
|
+
})
|
|
587
|
+
})
|
|
588
|
+
|
|
589
|
+
t.test('serve a non existent dir and get error', t => {
|
|
590
|
+
t.plan(2)
|
|
591
|
+
|
|
592
|
+
const options = {
|
|
593
|
+
root: '/none',
|
|
594
|
+
prefix: '/public',
|
|
595
|
+
list: true
|
|
596
|
+
}
|
|
597
|
+
const route = '/public/'
|
|
598
|
+
|
|
599
|
+
helper.arrange(t, options, (url) => {
|
|
600
|
+
t.test(route, t => {
|
|
601
|
+
t.plan(2)
|
|
602
|
+
simple.concat({
|
|
603
|
+
method: 'GET',
|
|
604
|
+
url: url + route
|
|
605
|
+
}, (err, response, body) => {
|
|
606
|
+
t.error(err)
|
|
607
|
+
t.equal(response.statusCode, 404)
|
|
608
|
+
})
|
|
609
|
+
})
|
|
610
|
+
})
|
|
611
|
+
})
|
|
612
|
+
|
|
613
|
+
t.test('serve a non existent dir and get error', t => {
|
|
614
|
+
t.plan(2)
|
|
615
|
+
|
|
616
|
+
const options = {
|
|
617
|
+
root: path.join(__dirname, '/static'),
|
|
618
|
+
prefix: '/public',
|
|
619
|
+
list: {
|
|
620
|
+
names: ['index']
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
const route = '/public/none/index'
|
|
624
|
+
|
|
625
|
+
helper.arrange(t, options, (url) => {
|
|
626
|
+
t.test(route, t => {
|
|
627
|
+
t.plan(2)
|
|
628
|
+
simple.concat({
|
|
629
|
+
method: 'GET',
|
|
630
|
+
url: url + route
|
|
631
|
+
}, (err, response, body) => {
|
|
632
|
+
t.error(err)
|
|
633
|
+
t.equal(response.statusCode, 404)
|
|
634
|
+
})
|
|
635
|
+
})
|
|
636
|
+
})
|
|
637
|
+
})
|
|
638
|
+
|
|
639
|
+
t.test('dir list error', t => {
|
|
640
|
+
t.plan(7)
|
|
641
|
+
|
|
642
|
+
const options = {
|
|
643
|
+
root: path.join(__dirname, '/static'),
|
|
644
|
+
prefix: '/public',
|
|
645
|
+
prefixAvoidTrailingSlash: true,
|
|
646
|
+
index: false,
|
|
647
|
+
list: {
|
|
648
|
+
format: 'html',
|
|
649
|
+
names: ['index', 'index.htm'],
|
|
650
|
+
render: () => ''
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
const errorMessage = 'mocking send'
|
|
655
|
+
dirList.send = async () => { throw new Error(errorMessage) }
|
|
656
|
+
|
|
657
|
+
const mock = t.mock('..', {
|
|
658
|
+
'../lib/dirList.js': dirList
|
|
659
|
+
})
|
|
660
|
+
|
|
661
|
+
const routes = ['/public/', '/public/index.htm']
|
|
662
|
+
|
|
663
|
+
helper.arrangeModule(t, options, mock, (url) => {
|
|
664
|
+
for (const route of routes) {
|
|
665
|
+
simple.concat({
|
|
666
|
+
method: 'GET',
|
|
667
|
+
url: url + route
|
|
668
|
+
}, (err, response, body) => {
|
|
669
|
+
t.error(err)
|
|
670
|
+
t.equal(JSON.parse(body.toString()).message, errorMessage)
|
|
671
|
+
t.equal(response.statusCode, 500)
|
|
672
|
+
})
|
|
673
|
+
}
|
|
674
|
+
})
|
|
675
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
contents of a dotfile
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
example
|
|
File without changes
|
|
Binary file
|