UNPKG

19.1 kBPlain TextView Raw
1import { FastifyError } from '@fastify/error'
2import * as http from 'http'
3import { expectAssignable, expectError, expectType } from 'tsd'
4import fastify, { FastifyInstance, FastifyReply, FastifyRequest, RouteHandlerMethod } from '../../fastify'
5import { RequestPayload } from '../../types/hooks'
6import { FindMyWayFindResult } from '../../types/instance'
7import { HTTPMethods, RawServerDefault } from '../../types/utils'
8
9/*
10 * Testing Fastify HTTP Routes and Route Shorthands.
11 * Verifies Request and Reply types as well.
12 * For the route shorthand tests the argument orders are:
13 * - `(path, handler)`
14 * - `(path, options, handler)`
15 * - `(path, options)`
16 */
17
18declare module '../../fastify' {
19 interface FastifyContextConfig {
20 foo: string;
21 bar: number;
22 }
23}
24
25const routeHandler: RouteHandlerMethod = function (request, reply) {
26 expectType<FastifyInstance>(this)
27 expectType<FastifyRequest>(request)
28 expectType<FastifyReply>(reply)
29}
30
31const routeHandlerWithReturnValue: RouteHandlerMethod = function (request, reply) {
32 expectType<FastifyInstance>(this)
33 expectType<FastifyRequest>(request)
34 expectType<FastifyReply>(reply)
35
36 return reply.send()
37}
38
39type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete' | 'options';
40
41['GET', 'POST', 'PUT', 'PATCH', 'HEAD', 'DELETE', 'OPTIONS'].forEach(method => {
42 // route method
43 expectType<FastifyInstance>(fastify().route({
44 method: method as HTTPMethods,
45 url: '/',
46 handler: routeHandler
47 }))
48
49 const lowerCaseMethod: LowerCaseHTTPMethods = method.toLowerCase() as LowerCaseHTTPMethods
50
51 // method as method
52 expectType<FastifyInstance>(fastify()[lowerCaseMethod]('/', routeHandler))
53 expectType<FastifyInstance>(fastify()[lowerCaseMethod]('/', {}, routeHandler))
54 expectType<FastifyInstance>(fastify()[lowerCaseMethod]('/', { handler: routeHandler }))
55
56 expectType<FastifyInstance>(fastify()[lowerCaseMethod]('/', {
57 handler: routeHandler,
58 errorHandler: (error, request, reply) => {
59 expectType<FastifyError>(error)
60 reply.send('error')
61 },
62 childLoggerFactory: function (logger, bindings, opts) {
63 return logger.child(bindings, opts)
64 }
65 }))
66
67 interface BodyInterface { prop: string }
68 interface QuerystringInterface { prop: number }
69 interface ParamsInterface { prop: boolean }
70 interface HeadersInterface { prop: string }
71 interface RouteSpecificContextConfigType {
72 extra: boolean
73 }
74 interface RouteGeneric {
75 Body: BodyInterface;
76 Querystring: QuerystringInterface;
77 Params: ParamsInterface;
78 Headers: HeadersInterface;
79 }
80
81 fastify()[lowerCaseMethod]<RouteGeneric, RouteSpecificContextConfigType>('/', { config: { foo: 'bar', bar: 100, extra: true } }, (req, res) => {
82 expectType<BodyInterface>(req.body)
83 expectType<QuerystringInterface>(req.query)
84 expectType<ParamsInterface>(req.params)
85 expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
86 expectType<string>(req.context.config.foo)
87 expectType<number>(req.context.config.bar)
88 expectType<boolean>(req.context.config.extra)
89 expectType<string>(req.context.config.url)
90 expectType<HTTPMethods | HTTPMethods[]>(req.context.config.method)
91 expectType<string>(res.context.config.foo)
92 expectType<number>(res.context.config.bar)
93 expectType<boolean>(res.context.config.extra)
94 expectType<string>(req.routeConfig.url)
95 expectType<HTTPMethods | HTTPMethods[]>(req.routeConfig.method)
96 })
97
98 fastify().route<RouteGeneric>({
99 url: '/',
100 method: method as HTTPMethods,
101 config: { foo: 'bar', bar: 100 },
102 prefixTrailingSlash: 'slash',
103 onRequest: (req, res, done) => { // these handlers are tested in `hooks.test-d.ts`
104 expectType<BodyInterface>(req.body)
105 expectType<QuerystringInterface>(req.query)
106 expectType<ParamsInterface>(req.params)
107 expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
108 expectType<string>(req.context.config.foo)
109 expectType<number>(req.context.config.bar)
110 expectType<string>(req.context.config.url)
111 expectType<HTTPMethods | HTTPMethods[]>(req.context.config.method)
112 expectType<string>(res.context.config.foo)
113 expectType<number>(res.context.config.bar)
114 expectType<string>(req.routeConfig.url)
115 expectType<HTTPMethods | HTTPMethods[]>(req.routeConfig.method)
116 },
117 preParsing: (req, res, payload, done) => {
118 expectType<BodyInterface>(req.body)
119 expectType<QuerystringInterface>(req.query)
120 expectType<ParamsInterface>(req.params)
121 expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
122 expectType<string>(req.context.config.foo)
123 expectType<number>(req.context.config.bar)
124 expectType<string>(req.context.config.url)
125 expectType<HTTPMethods | HTTPMethods[]>(req.context.config.method)
126 expectType<string>(res.context.config.foo)
127 expectType<number>(res.context.config.bar)
128 expectType<string>(req.routeConfig.url)
129 expectType<HTTPMethods | HTTPMethods[]>(req.routeConfig.method)
130 expectType<RequestPayload>(payload)
131 expectAssignable<(err?: FastifyError | null, res?: RequestPayload) => void>(done)
132 expectAssignable<(err?: NodeJS.ErrnoException) => void>(done)
133 },
134 preValidation: (req, res, done) => {
135 expectType<BodyInterface>(req.body)
136 expectType<QuerystringInterface>(req.query)
137 expectType<ParamsInterface>(req.params)
138 expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
139 expectType<string>(req.context.config.foo)
140 expectType<number>(req.context.config.bar)
141 expectType<string>(req.context.config.url)
142 expectType<HTTPMethods | HTTPMethods[]>(req.context.config.method)
143 expectType<string>(res.context.config.foo)
144 expectType<number>(res.context.config.bar)
145 expectType<string>(req.routeConfig.url)
146 expectType<HTTPMethods | HTTPMethods[]>(req.routeConfig.method)
147 },
148 preHandler: (req, res, done) => {
149 expectType<BodyInterface>(req.body)
150 expectType<QuerystringInterface>(req.query)
151 expectType<ParamsInterface>(req.params)
152 expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
153 expectType<string>(req.context.config.foo)
154 expectType<number>(req.context.config.bar)
155 expectType<string>(req.context.config.url)
156 expectType<HTTPMethods | HTTPMethods[]>(req.context.config.method)
157 expectType<string>(res.context.config.foo)
158 expectType<number>(res.context.config.bar)
159 expectType<string>(req.routeConfig.url)
160 expectType<HTTPMethods | HTTPMethods[]>(req.routeConfig.method)
161 },
162 onResponse: (req, res, done) => {
163 expectType<BodyInterface>(req.body)
164 expectType<QuerystringInterface>(req.query)
165 expectType<ParamsInterface>(req.params)
166 expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
167 expectType<string>(req.context.config.foo)
168 expectType<number>(req.context.config.bar)
169 expectType<string>(req.context.config.url)
170 expectType<HTTPMethods | HTTPMethods[]>(req.context.config.method)
171 expectType<string>(res.context.config.foo)
172 expectType<number>(res.context.config.bar)
173 expectType<string>(req.routeConfig.url)
174 expectType<HTTPMethods | HTTPMethods[]>(req.routeConfig.method)
175 expectType<number>(res.statusCode)
176 },
177 onError: (req, res, error, done) => {
178 expectType<BodyInterface>(req.body)
179 expectType<QuerystringInterface>(req.query)
180 expectType<ParamsInterface>(req.params)
181 expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
182 expectType<string>(req.context.config.foo)
183 expectType<number>(req.context.config.bar)
184 expectType<string>(req.context.config.url)
185 expectType<HTTPMethods | HTTPMethods[]>(req.context.config.method)
186 expectType<string>(res.context.config.foo)
187 expectType<number>(res.context.config.bar)
188 expectType<string>(req.routeConfig.url)
189 expectType<HTTPMethods | HTTPMethods[]>(req.routeConfig.method)
190 },
191 preSerialization: (req, res, payload, done) => {
192 expectType<BodyInterface>(req.body)
193 expectType<QuerystringInterface>(req.query)
194 expectType<ParamsInterface>(req.params)
195 expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
196 expectType<string>(req.context.config.foo)
197 expectType<number>(req.context.config.bar)
198 expectType<string>(req.context.config.url)
199 expectType<HTTPMethods | HTTPMethods[]>(req.context.config.method)
200 expectType<string>(res.context.config.foo)
201 expectType<number>(res.context.config.bar)
202 expectType<string>(req.routeConfig.url)
203 expectType<HTTPMethods | HTTPMethods[]>(req.routeConfig.method)
204 },
205 onSend: (req, res, payload, done) => {
206 expectType<BodyInterface>(req.body)
207 expectType<QuerystringInterface>(req.query)
208 expectType<ParamsInterface>(req.params)
209 expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
210 expectType<string>(req.context.config.foo)
211 expectType<number>(req.context.config.bar)
212 expectType<string>(req.context.config.url)
213 expectType<HTTPMethods | HTTPMethods[]>(req.context.config.method)
214 expectType<string>(res.context.config.foo)
215 expectType<number>(res.context.config.bar)
216 expectType<string>(req.routeConfig.url)
217 expectType<HTTPMethods | HTTPMethods[]>(req.routeConfig.method)
218 },
219 handler: (req, res) => {
220 expectType<BodyInterface>(req.body)
221 expectType<QuerystringInterface>(req.query)
222 expectType<ParamsInterface>(req.params)
223 expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
224 expectType<string>(req.context.config.foo)
225 expectType<number>(req.context.config.bar)
226 expectType<string>(req.context.config.url)
227 expectType<HTTPMethods | HTTPMethods[]>(req.context.config.method)
228 expectType<string>(res.context.config.foo)
229 expectType<number>(res.context.config.bar)
230 expectType<string>(req.routeConfig.url)
231 expectType<HTTPMethods | HTTPMethods[]>(req.routeConfig.method)
232 }
233 })
234
235 fastify().route<RouteGeneric>({
236 url: '/',
237 method: method as HTTPMethods,
238 config: { foo: 'bar', bar: 100 },
239 prefixTrailingSlash: 'slash',
240 onRequest: async (req, res, done) => { // these handlers are tested in `hooks.test-d.ts`
241 expectType<BodyInterface>(req.body)
242 expectType<QuerystringInterface>(req.query)
243 expectType<ParamsInterface>(req.params)
244 expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
245 expectType<string>(req.context.config.foo)
246 expectType<number>(req.context.config.bar)
247 expectType<string>(req.context.config.url)
248 expectType<HTTPMethods | HTTPMethods[]>(req.context.config.method)
249 expectType<string>(res.context.config.foo)
250 expectType<number>(res.context.config.bar)
251 expectType<string>(req.routeConfig.url)
252 expectType<HTTPMethods | HTTPMethods[]>(req.routeConfig.method)
253 },
254 preParsing: async (req, res, payload, done) => {
255 expectType<BodyInterface>(req.body)
256 expectType<QuerystringInterface>(req.query)
257 expectType<ParamsInterface>(req.params)
258 expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
259 expectType<string>(req.context.config.foo)
260 expectType<number>(req.context.config.bar)
261 expectType<string>(req.context.config.url)
262 expectType<HTTPMethods | HTTPMethods[]>(req.context.config.method)
263 expectType<string>(res.context.config.foo)
264 expectType<number>(res.context.config.bar)
265 expectType<string>(req.routeConfig.url)
266 expectType<HTTPMethods | HTTPMethods[]>(req.routeConfig.method)
267 expectType<RequestPayload>(payload)
268 expectAssignable<(err?: FastifyError | null, res?: RequestPayload) => void>(done)
269 expectAssignable<(err?: NodeJS.ErrnoException) => void>(done)
270 },
271 preValidation: async (req, res, done) => {
272 expectType<BodyInterface>(req.body)
273 expectType<QuerystringInterface>(req.query)
274 expectType<ParamsInterface>(req.params)
275 expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
276 expectType<string>(req.context.config.foo)
277 expectType<number>(req.context.config.bar)
278 expectType<string>(req.context.config.url)
279 expectType<HTTPMethods | HTTPMethods[]>(req.context.config.method)
280 expectType<string>(res.context.config.foo)
281 expectType<number>(res.context.config.bar)
282 expectType<string>(req.routeConfig.url)
283 expectType<HTTPMethods | HTTPMethods[]>(req.routeConfig.method)
284 },
285 preHandler: async (req, res, done) => {
286 expectType<BodyInterface>(req.body)
287 expectType<QuerystringInterface>(req.query)
288 expectType<ParamsInterface>(req.params)
289 expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
290 expectType<string>(req.context.config.foo)
291 expectType<number>(req.context.config.bar)
292 expectType<string>(req.context.config.url)
293 expectType<HTTPMethods | HTTPMethods[]>(req.context.config.method)
294 expectType<string>(res.context.config.foo)
295 expectType<number>(res.context.config.bar)
296 expectType<string>(req.routeConfig.url)
297 expectType<HTTPMethods | HTTPMethods[]>(req.routeConfig.method)
298 },
299 onResponse: async (req, res, done) => {
300 expectType<BodyInterface>(req.body)
301 expectType<QuerystringInterface>(req.query)
302 expectType<ParamsInterface>(req.params)
303 expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
304 expectType<string>(req.context.config.foo)
305 expectType<number>(req.context.config.bar)
306 expectType<string>(req.context.config.url)
307 expectType<HTTPMethods | HTTPMethods[]>(req.context.config.method)
308 expectType<string>(res.context.config.foo)
309 expectType<number>(res.context.config.bar)
310 expectType<string>(req.routeConfig.url)
311 expectType<HTTPMethods | HTTPMethods[]>(req.routeConfig.method)
312 expectType<number>(res.statusCode)
313 },
314 onError: async (req, res, error, done) => {
315 expectType<BodyInterface>(req.body)
316 expectType<QuerystringInterface>(req.query)
317 expectType<ParamsInterface>(req.params)
318 expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
319 expectType<string>(req.context.config.foo)
320 expectType<number>(req.context.config.bar)
321 expectType<string>(req.context.config.url)
322 expectType<HTTPMethods | HTTPMethods[]>(req.context.config.method)
323 expectType<string>(res.context.config.foo)
324 expectType<number>(res.context.config.bar)
325 expectType<string>(req.routeConfig.url)
326 expectType<HTTPMethods | HTTPMethods[]>(req.routeConfig.method)
327 },
328 preSerialization: async (req, res, payload, done) => {
329 expectType<BodyInterface>(req.body)
330 expectType<QuerystringInterface>(req.query)
331 expectType<ParamsInterface>(req.params)
332 expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
333 expectType<string>(req.context.config.foo)
334 expectType<number>(req.context.config.bar)
335 expectType<string>(req.context.config.url)
336 expectType<HTTPMethods | HTTPMethods[]>(req.context.config.method)
337 expectType<string>(res.context.config.foo)
338 expectType<number>(res.context.config.bar)
339 expectType<string>(req.routeConfig.url)
340 expectType<HTTPMethods | HTTPMethods[]>(req.routeConfig.method)
341 },
342 onSend: async (req, res, payload, done) => {
343 expectType<BodyInterface>(req.body)
344 expectType<QuerystringInterface>(req.query)
345 expectType<ParamsInterface>(req.params)
346 expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
347 expectType<string>(req.context.config.foo)
348 expectType<number>(req.context.config.bar)
349 expectType<string>(req.context.config.url)
350 expectType<HTTPMethods | HTTPMethods[]>(req.context.config.method)
351 expectType<string>(res.context.config.foo)
352 expectType<number>(res.context.config.bar)
353 expectType<string>(req.routeConfig.url)
354 expectType<HTTPMethods | HTTPMethods[]>(req.routeConfig.method)
355 },
356 handler: (req, res) => {
357 expectType<BodyInterface>(req.body)
358 expectType<QuerystringInterface>(req.query)
359 expectType<ParamsInterface>(req.params)
360 expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
361 expectType<string>(req.context.config.foo)
362 expectType<number>(req.context.config.bar)
363 expectType<string>(req.context.config.url)
364 expectType<HTTPMethods | HTTPMethods[]>(req.context.config.method)
365 expectType<string>(res.context.config.foo)
366 expectType<number>(res.context.config.bar)
367 expectType<string>(req.routeConfig.url)
368 expectType<HTTPMethods | HTTPMethods[]>(req.routeConfig.method)
369 }
370 })
371})
372
373expectError(fastify().route({
374 url: '/',
375 method: 'CONNECT', // not a valid method
376 handler: routeHandler
377}))
378
379expectType<FastifyInstance>(fastify().route({
380 url: '/',
381 method: ['GET', 'POST'],
382 handler: routeHandler
383}))
384
385expectError(fastify().route({
386 url: '/',
387 method: ['GET', 'POST', 'OPTION'], // OPTION is a typo for OPTIONS
388 handler: routeHandler
389}))
390
391expectError(fastify().route({
392 url: '/',
393 method: 'GET',
394 handler: routeHandler,
395 schemaErrorFormatter: 500 // Not a valid formatter
396}))
397
398expectType<FastifyInstance>(fastify().route({
399 url: '/',
400 method: 'GET',
401 handler: routeHandler,
402 schemaErrorFormatter: (errors, dataVar) => new Error('')
403}))
404
405expectError(fastify().route({
406 prefixTrailingSlash: true // Not a valid value
407}))
408
409expectType<FastifyInstance>(fastify().route({
410 url: '/',
411 method: 'GET',
412 handler: routeHandlerWithReturnValue
413}))
414
415expectType<boolean>(fastify().hasRoute({
416 url: '/',
417 method: 'GET'
418}))
419
420expectType<boolean>(fastify().hasRoute({
421 url: '/',
422 method: 'GET',
423 constraints: { version: '1.2.0' }
424}))
425
426expectType<boolean>(fastify().hasRoute({
427 url: '/',
428 method: 'GET',
429 constraints: { host: 'auth.fastify.dev' }
430}))
431
432expectType<boolean>(fastify().hasRoute({
433 url: '/',
434 method: 'GET',
435 constraints: { host: /.*\.fastify\.dev$/ }
436}))
437
438expectType<boolean>(fastify().hasRoute({
439 url: '/',
440 method: 'GET',
441 constraints: { host: /.*\.fastify\.dev$/, version: '1.2.3' }
442}))
443
444expectType<boolean>(fastify().hasRoute({
445 url: '/',
446 method: 'GET',
447 constraints: {
448 // constraints value should accept any value
449 number: 12,
450 date: new Date(),
451 boolean: true,
452 function: () => {},
453 object: { foo: 'bar' }
454 }
455}))
456
457expectType<Omit<FindMyWayFindResult<RawServerDefault>, 'store'>>(
458 fastify().findRoute({
459 url: '/',
460 method: 'get'
461 })
462)
463
464// we should not expose store
465expectError(fastify().findRoute({
466 url: '/',
467 method: 'get'
468}).store)
469
470expectType<FastifyInstance>(fastify().route({
471 url: '/',
472 method: 'get',
473 handler: routeHandlerWithReturnValue
474}))
475
476expectType<FastifyInstance>(fastify().route({
477 url: '/',
478 method: ['put', 'patch'],
479 handler: routeHandlerWithReturnValue
480}))
481
\No newline at end of file