galbe 0.2.0 → 0.4.1
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/workflows/build_test.yml +2 -4
- package/.github/workflows/release.yml +2 -2
- package/bin/cli.ts +8 -104
- package/bin/commands/build.ts +95 -0
- package/bin/commands/dev.ts +53 -0
- package/bin/commands/generate/client.ts +192 -0
- package/bin/commands/generate/code/openapi.parser.ts +479 -0
- package/bin/commands/generate/code.ts +75 -0
- package/bin/commands/generate/index.ts +12 -0
- package/bin/commands/generate/spec.ts +94 -0
- package/bin/res/cli.template.js +120 -0
- package/bin/res/client.template.ts +161 -0
- package/bin/util.ts +164 -0
- package/bun.lockb +0 -0
- package/docs/getting-started.md +8 -0
- package/docs/hooks.md +4 -4
- package/docs/plugins.md +3 -9
- package/docs/routes.md +3 -3
- package/docs/schemas.md +19 -2
- package/package.json +10 -8
- package/scripts/postinstall.ts +1 -3
- package/src/extras/spec/openapi.serializer.ts +264 -0
- package/src/extras.ts +1 -0
- package/src/index.ts +122 -80
- package/src/parser.ts +29 -8
- package/src/router.ts +27 -28
- package/src/routes.ts +142 -40
- package/src/schema.ts +79 -8
- package/src/server.ts +55 -35
- package/src/types.ts +109 -53
- package/src/util.ts +85 -3
- package/src/validator.ts +27 -5
- package/test/parser.test.ts +34 -0
- package/test/requests.test.ts +5 -12
- package/test/resources/test.route.comment.ts +20 -0
- package/test/responses.test.ts +386 -13
- package/test/routeFiles.test.ts +44 -27
- package/test/router.test.ts +67 -42
- package/scripts/build.ts +0 -14
package/test/requests.test.ts
CHANGED
|
@@ -1,18 +1,9 @@
|
|
|
1
1
|
import { expect, test, describe, beforeAll } from 'bun:test'
|
|
2
2
|
import { Galbe, $T } from '../src'
|
|
3
|
-
import {
|
|
4
|
-
formdata,
|
|
5
|
-
type Case,
|
|
6
|
-
fileHash,
|
|
7
|
-
schema_objectBase,
|
|
8
|
-
schema_object,
|
|
9
|
-
handleBody,
|
|
10
|
-
isAsyncIterator,
|
|
11
|
-
handleUrlFormStream
|
|
12
|
-
} from './test.utils'
|
|
3
|
+
import { formdata, type Case, fileHash, handleBody, isAsyncIterator } from './test.utils'
|
|
13
4
|
|
|
14
5
|
const port = 7358
|
|
15
|
-
const METHODS = ['get', 'post', 'put', 'patch', 'delete', 'options']
|
|
6
|
+
const METHODS = ['get', 'post', 'put', 'patch', 'delete', 'options', 'head']
|
|
16
7
|
|
|
17
8
|
describe('requests', () => {
|
|
18
9
|
beforeAll(async () => {
|
|
@@ -24,6 +15,7 @@ describe('requests', () => {
|
|
|
24
15
|
galbe.patch('/test', () => {})
|
|
25
16
|
galbe.delete('/test', () => {})
|
|
26
17
|
galbe.options('/test', () => {})
|
|
18
|
+
galbe.head('/test', () => {})
|
|
27
19
|
|
|
28
20
|
galbe.get('/headers', ctx => {
|
|
29
21
|
return ctx.headers
|
|
@@ -76,7 +68,8 @@ describe('requests', () => {
|
|
|
76
68
|
p2: $T.number(),
|
|
77
69
|
p3: $T.boolean(),
|
|
78
70
|
p4: $T.union([$T.number(), $T.boolean()]),
|
|
79
|
-
p5: $T.optional($T.string())
|
|
71
|
+
p5: $T.optional($T.string()),
|
|
72
|
+
p6: $T.array($T.union([$T.string()]))
|
|
80
73
|
}
|
|
81
74
|
},
|
|
82
75
|
ctx => {
|
|
@@ -35,4 +35,24 @@ export default (g: Galbe) => {
|
|
|
35
35
|
* @other Hello Mom!
|
|
36
36
|
*/
|
|
37
37
|
g.put('/test', { body: $T.object({ foo: $T.string() }) }, [() => {}], _ => {})
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* patch method
|
|
41
|
+
*/
|
|
42
|
+
g.patch('/test', _ => {})
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* options method
|
|
46
|
+
*/
|
|
47
|
+
g.options('/test', _ => {})
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* delete method
|
|
51
|
+
*/
|
|
52
|
+
g.delete('/test', _ => {})
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* head method
|
|
56
|
+
*/
|
|
57
|
+
g.head('/test', _ => {})
|
|
38
58
|
}
|
package/test/responses.test.ts
CHANGED
|
@@ -21,12 +21,14 @@ const rsTxt = (text: string) => {
|
|
|
21
21
|
})
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
const handleResp = ctx => ctx.body
|
|
25
|
+
|
|
24
26
|
describe('responses', () => {
|
|
25
27
|
beforeAll(async () => {
|
|
26
28
|
const galbe = new Galbe()
|
|
27
29
|
|
|
28
30
|
galbe.post(
|
|
29
|
-
'/
|
|
31
|
+
'/none',
|
|
30
32
|
{
|
|
31
33
|
body: $T.optional($T.object($T.any())),
|
|
32
34
|
query: { text: $T.optional($T.string()), stream: $T.optional($T.string()) }
|
|
@@ -42,20 +44,29 @@ describe('responses', () => {
|
|
|
42
44
|
}
|
|
43
45
|
)
|
|
44
46
|
|
|
45
|
-
galbe.
|
|
46
|
-
return { next: () => {} }
|
|
47
|
-
})
|
|
47
|
+
galbe.post('', { response: { test: '' } }, () => {})
|
|
48
48
|
|
|
49
|
-
galbe.
|
|
50
|
-
|
|
51
|
-
})
|
|
49
|
+
galbe.post('/ba', { response: { 200: $T.byteArray() } }, handleResp)
|
|
50
|
+
galbe.post('/bool', { response: { 200: $T.boolean() } }, handleResp)
|
|
51
|
+
galbe.post('/num', { response: { 200: $T.number() } }, handleResp)
|
|
52
|
+
galbe.post('/str', { response: { 200: $T.string() } }, handleResp)
|
|
53
|
+
galbe.post('/json/bool', { response: { 200: $T.json($T.boolean()) } }, handleResp)
|
|
54
|
+
galbe.post('/json/num', { response: { 200: $T.json($T.number()) } }, handleResp)
|
|
55
|
+
galbe.post('/json/str', { response: { 200: $T.json($T.string()) } }, handleResp)
|
|
56
|
+
galbe.post('/json/obj', { response: { 200: $T.json($T.object()) } }, handleResp)
|
|
57
|
+
galbe.post('/arr', { response: { 200: $T.array() } }, handleResp)
|
|
58
|
+
galbe.post('/obj', { response: { 200: $T.object($T.any()) } }, handleResp)
|
|
59
|
+
galbe.post('/stream/ba', { response: { 200: $T.stream($T.byteArray()) } }, ctx =>
|
|
60
|
+
ctx.body ? genTxt(ctx.body) : ''
|
|
61
|
+
)
|
|
62
|
+
galbe.post('/stream/str', { response: { 200: $T.stream($T.string()) } }, ctx => (ctx.body ? genTxt(ctx.body) : 42))
|
|
52
63
|
|
|
53
64
|
await galbe.listen(port)
|
|
54
65
|
})
|
|
55
66
|
|
|
56
|
-
test('response, string', async () => {
|
|
67
|
+
test('response, no schema, string', async () => {
|
|
57
68
|
const reqTxt = 'Hello Mom!'
|
|
58
|
-
let resp = await fetch(`http://localhost:${port}/
|
|
69
|
+
let resp = await fetch(`http://localhost:${port}/none?text=${reqTxt}`, {
|
|
59
70
|
method: 'POST'
|
|
60
71
|
})
|
|
61
72
|
|
|
@@ -66,9 +77,9 @@ describe('responses', () => {
|
|
|
66
77
|
expect(body).toBe(reqTxt)
|
|
67
78
|
})
|
|
68
79
|
|
|
69
|
-
test('response, object', async () => {
|
|
80
|
+
test('response, no schema, object', async () => {
|
|
70
81
|
const reqBody = { foo: 'bar' }
|
|
71
|
-
let resp = await fetch(`http://localhost:${port}/
|
|
82
|
+
let resp = await fetch(`http://localhost:${port}/none`, {
|
|
72
83
|
method: 'POST',
|
|
73
84
|
body: JSON.stringify(reqBody),
|
|
74
85
|
headers: {
|
|
@@ -83,12 +94,12 @@ describe('responses', () => {
|
|
|
83
94
|
expect(body).toEqual(reqBody)
|
|
84
95
|
})
|
|
85
96
|
|
|
86
|
-
test('response, stream', async () => {
|
|
97
|
+
test('response, no schema, stream', async () => {
|
|
87
98
|
const reqTxt = 'Hello Mom!'
|
|
88
99
|
const cases = [{ stream: 'generatorFunction' }, { stream: 'readableStream' }]
|
|
89
100
|
|
|
90
101
|
for (const c of cases) {
|
|
91
|
-
let resp = await fetch(`http://localhost:${port}/
|
|
102
|
+
let resp = await fetch(`http://localhost:${port}/none?text=${reqTxt}&stream=${c.stream}`, {
|
|
92
103
|
method: 'POST',
|
|
93
104
|
headers: {
|
|
94
105
|
'content-type': 'application/json'
|
|
@@ -106,4 +117,366 @@ describe('responses', () => {
|
|
|
106
117
|
expect(body).toMatch(new RegExp(`id:${UUID_RGX}\ndata:Hello\n\nid:${UUID_RGX}\ndata:Mom!\n\n`))
|
|
107
118
|
}
|
|
108
119
|
})
|
|
120
|
+
|
|
121
|
+
test('response, ba, validation OK', async () => {
|
|
122
|
+
let bodyStr = 'Hello mom!'
|
|
123
|
+
let reqBody = new TextEncoder().encode(bodyStr)
|
|
124
|
+
|
|
125
|
+
let resp = await fetch(`http://localhost:${port}/ba`, {
|
|
126
|
+
method: 'POST',
|
|
127
|
+
body: bodyStr,
|
|
128
|
+
headers: {
|
|
129
|
+
'content-type': 'application/octet-stream'
|
|
130
|
+
}
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
const reader = resp.body?.getReader()
|
|
134
|
+
let body = new Uint8Array()
|
|
135
|
+
while (reader) {
|
|
136
|
+
const { value, done } = await reader.read()
|
|
137
|
+
if (done) break
|
|
138
|
+
let buff = new Uint8Array(body.length + value.length)
|
|
139
|
+
buff.set(body)
|
|
140
|
+
buff.set(value, body.length)
|
|
141
|
+
body = buff
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
expect(resp.status).toBe(200)
|
|
145
|
+
expect(resp.headers.get('content-type')).toBe('application/octet-stream')
|
|
146
|
+
expect(body).toEqual(reqBody)
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
test('response, ba, validation error', async () => {
|
|
150
|
+
let bodyStr = 'Hello mom!'
|
|
151
|
+
|
|
152
|
+
let resp = await fetch(`http://localhost:${port}/ba`, {
|
|
153
|
+
method: 'POST',
|
|
154
|
+
body: bodyStr,
|
|
155
|
+
headers: {
|
|
156
|
+
'content-type': 'text/plain'
|
|
157
|
+
}
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
expect(resp.status).toBe(500)
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
test('response, bool, validation OK', async () => {
|
|
164
|
+
let bodyStr = 'true'
|
|
165
|
+
let reqBody = true
|
|
166
|
+
|
|
167
|
+
let resp = await fetch(`http://localhost:${port}/bool`, {
|
|
168
|
+
method: 'POST',
|
|
169
|
+
body: bodyStr,
|
|
170
|
+
headers: {
|
|
171
|
+
'content-type': 'application/json'
|
|
172
|
+
}
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
const body = await resp.json()
|
|
176
|
+
|
|
177
|
+
expect(resp.status).toBe(200)
|
|
178
|
+
expect(resp.headers.get('content-type')).toBe('application/json')
|
|
179
|
+
expect(body).toEqual(reqBody)
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
test('response, bool, validation error', async () => {
|
|
183
|
+
let bodyStr = 'true'
|
|
184
|
+
|
|
185
|
+
let resp = await fetch(`http://localhost:${port}/bool`, {
|
|
186
|
+
method: 'POST',
|
|
187
|
+
body: bodyStr,
|
|
188
|
+
headers: {
|
|
189
|
+
'content-type': 'text/plain'
|
|
190
|
+
}
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
expect(resp.status).toBe(500)
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
test('response, num, validation OK', async () => {
|
|
197
|
+
let bodyStr = '42'
|
|
198
|
+
let reqBody = 42
|
|
199
|
+
|
|
200
|
+
let resp = await fetch(`http://localhost:${port}/num`, {
|
|
201
|
+
method: 'POST',
|
|
202
|
+
body: bodyStr,
|
|
203
|
+
headers: {
|
|
204
|
+
'content-type': 'application/json'
|
|
205
|
+
}
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
const body = await resp.json()
|
|
209
|
+
|
|
210
|
+
expect(resp.status).toBe(200)
|
|
211
|
+
expect(resp.headers.get('content-type')).toBe('application/json')
|
|
212
|
+
expect(body).toEqual(reqBody)
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
test('response, num, validation error', async () => {
|
|
216
|
+
let bodyStr = '"test"'
|
|
217
|
+
|
|
218
|
+
let resp = await fetch(`http://localhost:${port}/num`, {
|
|
219
|
+
method: 'POST',
|
|
220
|
+
body: bodyStr,
|
|
221
|
+
headers: {
|
|
222
|
+
'content-type': 'application/json'
|
|
223
|
+
}
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
expect(resp.status).toBe(500)
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
test('response, str, validation OK', async () => {
|
|
230
|
+
let bodyStr = 'Hello Mom!'
|
|
231
|
+
|
|
232
|
+
let resp = await fetch(`http://localhost:${port}/str`, {
|
|
233
|
+
method: 'POST',
|
|
234
|
+
body: bodyStr,
|
|
235
|
+
headers: {
|
|
236
|
+
'content-type': 'text/plain'
|
|
237
|
+
}
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
const body = await resp.text()
|
|
241
|
+
|
|
242
|
+
expect(resp.status).toBe(200)
|
|
243
|
+
expect(resp.headers.get('content-type')).toBe('text/plain')
|
|
244
|
+
expect(body).toEqual(bodyStr)
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
test('response, json bool, validation OK', async () => {
|
|
248
|
+
let bodyStr = 'false'
|
|
249
|
+
let reqBody = false
|
|
250
|
+
|
|
251
|
+
let resp = await fetch(`http://localhost:${port}/json/bool`, {
|
|
252
|
+
method: 'POST',
|
|
253
|
+
body: bodyStr,
|
|
254
|
+
headers: {
|
|
255
|
+
'content-type': 'application/json'
|
|
256
|
+
}
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
const body = await resp.json()
|
|
260
|
+
|
|
261
|
+
expect(resp.status).toBe(200)
|
|
262
|
+
expect(resp.headers.get('content-type')).toBe('application/json')
|
|
263
|
+
expect(body).toEqual(reqBody)
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
test('response, json bool, validation error', async () => {
|
|
267
|
+
let bodyStr = '3.14'
|
|
268
|
+
|
|
269
|
+
let resp = await fetch(`http://localhost:${port}/json/bool`, {
|
|
270
|
+
method: 'POST',
|
|
271
|
+
body: bodyStr,
|
|
272
|
+
headers: {
|
|
273
|
+
'content-type': 'application/json'
|
|
274
|
+
}
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
expect(resp.status).toBe(500)
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
test('response, json num, validation OK', async () => {
|
|
281
|
+
let bodyStr = '42'
|
|
282
|
+
let reqBody = 42
|
|
283
|
+
|
|
284
|
+
let resp = await fetch(`http://localhost:${port}/json/num`, {
|
|
285
|
+
method: 'POST',
|
|
286
|
+
body: bodyStr,
|
|
287
|
+
headers: {
|
|
288
|
+
'content-type': 'application/json'
|
|
289
|
+
}
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
const body = await resp.json()
|
|
293
|
+
|
|
294
|
+
expect(resp.status).toBe(200)
|
|
295
|
+
expect(resp.headers.get('content-type')).toBe('application/json')
|
|
296
|
+
expect(body).toEqual(reqBody)
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
test('response, json num, validation error', async () => {
|
|
300
|
+
let bodyStr = '"Hi"'
|
|
301
|
+
|
|
302
|
+
let resp = await fetch(`http://localhost:${port}/json/bool`, {
|
|
303
|
+
method: 'POST',
|
|
304
|
+
body: bodyStr,
|
|
305
|
+
headers: {
|
|
306
|
+
'content-type': 'application/json'
|
|
307
|
+
}
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
expect(resp.status).toBe(500)
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
test('response, json str, validation OK', async () => {
|
|
314
|
+
let bodyStr = '"Hello Mom!"'
|
|
315
|
+
let reqBody = 'Hello Mom!'
|
|
316
|
+
|
|
317
|
+
let resp = await fetch(`http://localhost:${port}/json/str`, {
|
|
318
|
+
method: 'POST',
|
|
319
|
+
body: bodyStr,
|
|
320
|
+
headers: {
|
|
321
|
+
'content-type': 'application/json'
|
|
322
|
+
}
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
const body = await resp.json()
|
|
326
|
+
|
|
327
|
+
expect(resp.status).toBe(200)
|
|
328
|
+
expect(resp.headers.get('content-type')).toBe('application/json')
|
|
329
|
+
expect(body).toEqual(reqBody)
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
test('response, json str, validation error', async () => {
|
|
333
|
+
let bodyStr = '3.14'
|
|
334
|
+
|
|
335
|
+
let resp = await fetch(`http://localhost:${port}/json/str`, {
|
|
336
|
+
method: 'POST',
|
|
337
|
+
body: bodyStr,
|
|
338
|
+
headers: {
|
|
339
|
+
'content-type': 'application/json'
|
|
340
|
+
}
|
|
341
|
+
})
|
|
342
|
+
|
|
343
|
+
expect(resp.status).toBe(500)
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
test('response, array, validation OK', async () => {
|
|
347
|
+
let bodyStr = '[false, "one", 2]'
|
|
348
|
+
let reqBody = [false, 'one', 2]
|
|
349
|
+
|
|
350
|
+
let resp = await fetch(`http://localhost:${port}/arr`, {
|
|
351
|
+
method: 'POST',
|
|
352
|
+
body: bodyStr,
|
|
353
|
+
headers: {
|
|
354
|
+
'content-type': 'application/json'
|
|
355
|
+
}
|
|
356
|
+
})
|
|
357
|
+
|
|
358
|
+
const body = await resp.json()
|
|
359
|
+
|
|
360
|
+
expect(resp.status).toBe(200)
|
|
361
|
+
expect(resp.headers.get('content-type')).toBe('application/json')
|
|
362
|
+
expect(body).toEqual(reqBody)
|
|
363
|
+
})
|
|
364
|
+
|
|
365
|
+
test('response, array, validation error', async () => {
|
|
366
|
+
let bodyStr = '0'
|
|
367
|
+
|
|
368
|
+
let resp = await fetch(`http://localhost:${port}/arr`, {
|
|
369
|
+
method: 'POST',
|
|
370
|
+
body: bodyStr,
|
|
371
|
+
headers: {
|
|
372
|
+
'content-type': 'application/json'
|
|
373
|
+
}
|
|
374
|
+
})
|
|
375
|
+
|
|
376
|
+
expect(resp.status).toBe(500)
|
|
377
|
+
})
|
|
378
|
+
|
|
379
|
+
test('response, object, validation OK', async () => {
|
|
380
|
+
let bodyStr = '{"str":"str", "num":0, "arr":[1,2,3], "nested": {"foo":"bar"}}'
|
|
381
|
+
let reqBody = { str: 'str', num: 0, arr: [1, 2, 3], nested: { foo: 'bar' } }
|
|
382
|
+
|
|
383
|
+
let resp = await fetch(`http://localhost:${port}/obj`, {
|
|
384
|
+
method: 'POST',
|
|
385
|
+
body: bodyStr,
|
|
386
|
+
headers: {
|
|
387
|
+
'content-type': 'application/json'
|
|
388
|
+
}
|
|
389
|
+
})
|
|
390
|
+
|
|
391
|
+
const body = await resp.json()
|
|
392
|
+
|
|
393
|
+
expect(resp.status).toBe(200)
|
|
394
|
+
expect(resp.headers.get('content-type')).toBe('application/json')
|
|
395
|
+
expect(body).toEqual(reqBody)
|
|
396
|
+
})
|
|
397
|
+
|
|
398
|
+
test('response, object, validation error', async () => {
|
|
399
|
+
let bodyStr = '"This"'
|
|
400
|
+
|
|
401
|
+
let resp = await fetch(`http://localhost:${port}/obj`, {
|
|
402
|
+
method: 'POST',
|
|
403
|
+
body: bodyStr,
|
|
404
|
+
headers: {
|
|
405
|
+
'content-type': 'application/json'
|
|
406
|
+
}
|
|
407
|
+
})
|
|
408
|
+
|
|
409
|
+
expect(resp.status).toBe(500)
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
test('response, stream ba, validation OK', async () => {
|
|
413
|
+
let bodyStr = 'Hello Mom!'
|
|
414
|
+
|
|
415
|
+
let resp = await fetch(`http://localhost:${port}/stream/ba`, {
|
|
416
|
+
method: 'POST',
|
|
417
|
+
body: bodyStr,
|
|
418
|
+
headers: {
|
|
419
|
+
'content-type': 'text/plain'
|
|
420
|
+
}
|
|
421
|
+
})
|
|
422
|
+
|
|
423
|
+
const reader = resp.body?.getReader()
|
|
424
|
+
let body = ''
|
|
425
|
+
while (reader) {
|
|
426
|
+
const { value, done } = await reader.read()
|
|
427
|
+
if (done) break
|
|
428
|
+
body += decoder.decode(value)
|
|
429
|
+
}
|
|
430
|
+
expect(resp.status).toBe(200)
|
|
431
|
+
expect(resp.headers.get('content-type')).toBe('text/event-stream')
|
|
432
|
+
expect(body).toMatch(new RegExp(`id:${UUID_RGX}\ndata:Hello\n\nid:${UUID_RGX}\ndata:Mom!\n\n`))
|
|
433
|
+
})
|
|
434
|
+
|
|
435
|
+
test('response, stream ba, validation error', async () => {
|
|
436
|
+
let bodyStr = ''
|
|
437
|
+
|
|
438
|
+
let resp = await fetch(`http://localhost:${port}/stream/ba`, {
|
|
439
|
+
method: 'POST',
|
|
440
|
+
body: bodyStr
|
|
441
|
+
})
|
|
442
|
+
|
|
443
|
+
expect(resp.status).toBe(500)
|
|
444
|
+
})
|
|
445
|
+
|
|
446
|
+
test('response, stream str, validation OK', async () => {
|
|
447
|
+
let bodyStr = 'Hello Mom!'
|
|
448
|
+
|
|
449
|
+
let resp = await fetch(`http://localhost:${port}/stream/str`, {
|
|
450
|
+
method: 'POST',
|
|
451
|
+
body: bodyStr,
|
|
452
|
+
headers: {
|
|
453
|
+
'content-type': 'text/plain'
|
|
454
|
+
}
|
|
455
|
+
})
|
|
456
|
+
|
|
457
|
+
const reader = resp.body?.getReader()
|
|
458
|
+
let body = ''
|
|
459
|
+
while (reader) {
|
|
460
|
+
const { value, done } = await reader.read()
|
|
461
|
+
if (done) break
|
|
462
|
+
body += decoder.decode(value)
|
|
463
|
+
}
|
|
464
|
+
expect(resp.status).toBe(200)
|
|
465
|
+
expect(resp.headers.get('content-type')).toBe('text/event-stream')
|
|
466
|
+
expect(body).toMatch(new RegExp(`id:${UUID_RGX}\ndata:Hello\n\nid:${UUID_RGX}\ndata:Mom!\n\n`))
|
|
467
|
+
})
|
|
468
|
+
|
|
469
|
+
test('response, stream str, validation error', async () => {
|
|
470
|
+
let bodyStr = '0'
|
|
471
|
+
|
|
472
|
+
let resp = await fetch(`http://localhost:${port}/stream/str`, {
|
|
473
|
+
method: 'POST',
|
|
474
|
+
body: bodyStr,
|
|
475
|
+
headers: {
|
|
476
|
+
'content-type': 'application/json'
|
|
477
|
+
}
|
|
478
|
+
})
|
|
479
|
+
|
|
480
|
+
expect(resp.status).toBe(500)
|
|
481
|
+
})
|
|
109
482
|
})
|
package/test/routeFiles.test.ts
CHANGED
|
@@ -49,6 +49,18 @@ describe('routeFiles', () => {
|
|
|
49
49
|
put: {
|
|
50
50
|
tags: 'tag1, tag2',
|
|
51
51
|
other: 'Hello Mom!'
|
|
52
|
+
},
|
|
53
|
+
patch: {
|
|
54
|
+
head: 'patch method'
|
|
55
|
+
},
|
|
56
|
+
options: {
|
|
57
|
+
head: 'options method'
|
|
58
|
+
},
|
|
59
|
+
delete: {
|
|
60
|
+
head: 'delete method'
|
|
61
|
+
},
|
|
62
|
+
head: {
|
|
63
|
+
head: 'head method'
|
|
52
64
|
}
|
|
53
65
|
}
|
|
54
66
|
}
|
|
@@ -59,12 +71,7 @@ describe('routeFiles', () => {
|
|
|
59
71
|
const k = new Galbe()
|
|
60
72
|
await defineRoutes({}, k)
|
|
61
73
|
expect(k.router.routes).toEqual({
|
|
62
|
-
|
|
63
|
-
POST: {},
|
|
64
|
-
PUT: {},
|
|
65
|
-
PATCH: {},
|
|
66
|
-
DELETE: {},
|
|
67
|
-
OPTIONS: {}
|
|
74
|
+
routes: {}
|
|
68
75
|
})
|
|
69
76
|
})
|
|
70
77
|
|
|
@@ -72,12 +79,7 @@ describe('routeFiles', () => {
|
|
|
72
79
|
const k = new Galbe({ routes: false })
|
|
73
80
|
await defineRoutes({}, k)
|
|
74
81
|
expect(k.router.routes).toEqual({
|
|
75
|
-
|
|
76
|
-
POST: {},
|
|
77
|
-
PUT: {},
|
|
78
|
-
PATCH: {},
|
|
79
|
-
DELETE: {},
|
|
80
|
-
OPTIONS: {}
|
|
82
|
+
routes: {}
|
|
81
83
|
})
|
|
82
84
|
})
|
|
83
85
|
|
|
@@ -85,12 +87,7 @@ describe('routeFiles', () => {
|
|
|
85
87
|
const k = new Galbe()
|
|
86
88
|
await defineRoutes({ routes: 'unexisting_route' }, k)
|
|
87
89
|
expect(k.router.routes).toEqual({
|
|
88
|
-
|
|
89
|
-
POST: {},
|
|
90
|
-
PUT: {},
|
|
91
|
-
PATCH: {},
|
|
92
|
-
DELETE: {},
|
|
93
|
-
OPTIONS: {}
|
|
90
|
+
routes: {}
|
|
94
91
|
})
|
|
95
92
|
})
|
|
96
93
|
|
|
@@ -100,17 +97,17 @@ describe('routeFiles', () => {
|
|
|
100
97
|
await defineRoutes({ routes: 'test/resources/test.route.empty.ts' }, k)
|
|
101
98
|
|
|
102
99
|
const r = k.router.routes
|
|
103
|
-
expect(r
|
|
100
|
+
expect(r?.children?.one?.routes.get).toMatchObject({
|
|
104
101
|
method: 'get',
|
|
105
102
|
path: '/one',
|
|
106
103
|
handler: () => {}
|
|
107
104
|
})
|
|
108
|
-
expect(r
|
|
105
|
+
expect(r?.children?.two?.routes.post).toMatchObject({
|
|
109
106
|
method: 'post',
|
|
110
107
|
path: '/two',
|
|
111
108
|
handler: () => {}
|
|
112
109
|
})
|
|
113
|
-
expect(r
|
|
110
|
+
expect(r?.children?.three?.routes.put).toMatchObject({
|
|
114
111
|
method: 'put',
|
|
115
112
|
path: '/three',
|
|
116
113
|
handler: () => {}
|
|
@@ -140,36 +137,56 @@ describe('routeFiles', () => {
|
|
|
140
137
|
await defineRoutes({ routes: ['test/resources/test.route.*.ts'] }, k)
|
|
141
138
|
|
|
142
139
|
const r = k.router.routes
|
|
143
|
-
expect(r
|
|
140
|
+
expect(r?.children?.one?.routes.get).toMatchObject({
|
|
144
141
|
method: 'get',
|
|
145
142
|
path: '/one',
|
|
146
143
|
handler: () => {}
|
|
147
144
|
})
|
|
148
|
-
expect(r
|
|
145
|
+
expect(r?.children?.two?.routes.post).toMatchObject({
|
|
149
146
|
method: 'post',
|
|
150
147
|
path: '/two',
|
|
151
148
|
handler: () => {}
|
|
152
149
|
})
|
|
153
|
-
expect(r
|
|
150
|
+
expect(r?.children?.three?.routes.put).toMatchObject({
|
|
154
151
|
method: 'put',
|
|
155
152
|
path: '/three',
|
|
156
153
|
handler: () => {}
|
|
157
154
|
})
|
|
158
|
-
expect(r
|
|
155
|
+
expect(r?.children?.test?.param?.routes.get).toMatchObject({
|
|
159
156
|
method: 'get',
|
|
160
157
|
path: '/test/:param1',
|
|
161
158
|
handler: () => {}
|
|
162
159
|
})
|
|
163
|
-
expect(r
|
|
160
|
+
expect(r?.children?.test?.routes.post).toMatchObject({
|
|
164
161
|
method: 'post',
|
|
165
162
|
path: '/test',
|
|
166
163
|
handler: () => {}
|
|
167
164
|
})
|
|
168
|
-
expect(r
|
|
165
|
+
expect(r?.children?.test?.routes.put).toMatchObject({
|
|
169
166
|
method: 'put',
|
|
170
167
|
path: '/test',
|
|
171
168
|
handler: () => {}
|
|
172
169
|
})
|
|
170
|
+
expect(r?.children?.test?.routes.patch).toMatchObject({
|
|
171
|
+
method: 'patch',
|
|
172
|
+
path: '/test',
|
|
173
|
+
handler: () => {}
|
|
174
|
+
})
|
|
175
|
+
expect(r?.children?.test?.routes.options).toMatchObject({
|
|
176
|
+
method: 'options',
|
|
177
|
+
path: '/test',
|
|
178
|
+
handler: () => {}
|
|
179
|
+
})
|
|
180
|
+
expect(r?.children?.test?.routes.delete).toMatchObject({
|
|
181
|
+
method: 'delete',
|
|
182
|
+
path: '/test',
|
|
183
|
+
handler: () => {}
|
|
184
|
+
})
|
|
185
|
+
expect(r?.children?.test?.routes.head).toMatchObject({
|
|
186
|
+
method: 'head',
|
|
187
|
+
path: '/test',
|
|
188
|
+
handler: () => {}
|
|
189
|
+
})
|
|
173
190
|
expect(k.meta?.sort((a, b) => (a.file < b.file ? 1 : -1))).toMatchObject([
|
|
174
191
|
{
|
|
175
192
|
header: {},
|