UNPKG

6.73 kBJavaScriptView Raw
1'use strict'
2
3const t = require('tap')
4const test = t.test
5const semver = require('semver')
6const handleRequest = require('../../lib/handleRequest')
7const internals = require('../../lib/handleRequest')[Symbol.for('internals')]
8const Request = require('../../lib/request')
9const Reply = require('../../lib/reply')
10const buildSchema = require('../../lib/validation').build
11const { Schemas } = require('../../lib/schemas')
12const sget = require('simple-get').concat
13
14const Ajv = require('ajv')
15const ajv = new Ajv({ coerceTypes: true })
16
17function schemaCompiler (schema) {
18 const validateFuncion = ajv.compile(schema)
19 var fn = function (body) {
20 const isOk = validateFuncion(body)
21 if (isOk) return
22 return false
23 }
24 fn.errors = []
25 return fn
26}
27
28test('Request object', t => {
29 t.plan(8)
30 const req = new Request('params', 'req', 'query', 'headers', 'log')
31 t.type(req, Request)
32 t.equal(req.params, 'params')
33 t.deepEqual(req.raw, 'req')
34 t.deepEqual(req.req, req.raw)
35 t.equal(req.query, 'query')
36 t.equal(req.headers, 'headers')
37 t.equal(req.log, 'log')
38 t.strictDeepEqual(req.body, null)
39})
40
41test('handleRequest function - sent reply', t => {
42 t.plan(1)
43 const request = {}
44 const reply = { sent: true }
45 const res = handleRequest(null, request, reply)
46 t.equal(res, undefined)
47})
48
49test('handleRequest function - invoke with error', t => {
50 t.plan(1)
51 const request = {}
52 const reply = {}
53 reply.send = (err) => t.is(err.message, 'Kaboom')
54 handleRequest(new Error('Kaboom'), request, reply)
55})
56
57test('handler function - invalid schema', t => {
58 t.plan(2)
59 const res = {}
60 res.end = () => {
61 t.equal(res.statusCode, 400)
62 t.pass()
63 }
64 res.writeHead = () => {}
65 res.log = { error: () => {}, info: () => {} }
66 const context = {
67 schema: {
68 body: {
69 type: 'object',
70 properties: {
71 hello: { type: 'number' }
72 }
73 }
74 },
75 handler: () => {},
76 Reply: Reply,
77 Request: Request,
78 preValidation: [],
79 preHandler: [],
80 onSend: [],
81 onError: [],
82 attachValidation: false
83 }
84 const schemas = new Schemas()
85 buildSchema(context, schemaCompiler, schemas)
86 const request = {
87 body: { hello: 'world' }
88 }
89 internals.handler(request, new Reply(res, context, request))
90})
91
92test('handler function - reply', t => {
93 t.plan(3)
94 const res = {}
95 res.end = () => {
96 t.equal(res.statusCode, 204)
97 t.pass()
98 }
99 res.writeHead = () => {}
100 const context = {
101 handler: (req, reply) => {
102 t.is(typeof reply, 'object')
103 reply.code(204)
104 reply.send(undefined)
105 },
106 Reply: Reply,
107 Request: Request,
108 preValidation: [],
109 preHandler: [],
110 onSend: [],
111 onError: []
112 }
113 buildSchema(context, schemaCompiler)
114 internals.handler({}, new Reply(res, context, {}))
115})
116
117test('handler function - preValidationCallback with finished response', t => {
118 t.plan(0)
119 const res = {}
120 // Be sure to only check `writableEnded` where is available
121 if (semver.gte(process.versions.node, '12.9.0')) {
122 res.writableEnded = true
123 } else {
124 res.writable = false
125 res.finished = true
126 }
127 res.end = () => {
128 t.fail()
129 }
130 res.writeHead = () => {}
131 const context = {
132 handler: (req, reply) => {
133 t.fail()
134 reply.send(undefined)
135 },
136 Reply: Reply,
137 Request: Request,
138 preValidation: null,
139 preHandler: [],
140 onSend: [],
141 onError: []
142 }
143 buildSchema(context, schemaCompiler)
144 internals.handler({}, new Reply(res, context, {}))
145})
146
147test('request should be defined in onSend Hook on post request with content type application/json', t => {
148 t.plan(8)
149 const fastify = require('../..')()
150
151 fastify.addHook('onSend', (request, reply, payload, done) => {
152 t.ok(request)
153 t.ok(request.raw)
154 t.ok(request.id)
155 t.ok(request.params)
156 t.ok(request.query)
157 done()
158 })
159 fastify.post('/', (request, reply) => {
160 reply.send(200)
161 })
162 fastify.listen(0, err => {
163 fastify.server.unref()
164 t.error(err)
165 sget({
166 method: 'POST',
167 url: 'http://localhost:' + fastify.server.address().port,
168 headers: {
169 'content-type': 'application/json'
170 }
171 }, (err, response, body) => {
172 t.error(err)
173 // a 400 error is expected because of no body
174 t.strictEqual(response.statusCode, 400)
175 })
176 })
177})
178
179test('request should be defined in onSend Hook on post request with content type application/x-www-form-urlencoded', t => {
180 t.plan(7)
181 const fastify = require('../..')()
182
183 fastify.addHook('onSend', (request, reply, payload, done) => {
184 t.ok(request)
185 t.ok(request.raw)
186 t.ok(request.params)
187 t.ok(request.query)
188 done()
189 })
190 fastify.post('/', (request, reply) => {
191 reply.send(200)
192 })
193 fastify.listen(0, err => {
194 fastify.server.unref()
195 t.error(err)
196 sget({
197 method: 'POST',
198 url: 'http://localhost:' + fastify.server.address().port,
199 headers: {
200 'content-type': 'application/x-www-form-urlencoded'
201 }
202 }, (err, response, body) => {
203 t.error(err)
204 // a 415 error is expected because of missing content type parser
205 t.strictEqual(response.statusCode, 415)
206 })
207 })
208})
209
210test('request should be defined in onSend Hook on options request with content type application/x-www-form-urlencoded', t => {
211 t.plan(7)
212 const fastify = require('../..')()
213
214 fastify.addHook('onSend', (request, reply, payload, done) => {
215 t.ok(request)
216 t.ok(request.raw)
217 t.ok(request.params)
218 t.ok(request.query)
219 done()
220 })
221 fastify.options('/', (request, reply) => {
222 reply.send(200)
223 })
224 fastify.listen(0, err => {
225 fastify.server.unref()
226 t.error(err)
227 sget({
228 method: 'OPTIONS',
229 url: 'http://localhost:' + fastify.server.address().port,
230 headers: {
231 'content-type': 'application/x-www-form-urlencoded'
232 }
233 }, (err, response, body) => {
234 t.error(err)
235 // Body parsing skipped, so no body sent
236 t.strictEqual(response.statusCode, 200)
237 })
238 })
239})
240
241test('request should respond with an error if an unserialized payload is sent inside an an async handler', t => {
242 t.plan(3)
243
244 const fastify = require('../..')()
245
246 fastify.get('/', (request, reply) => {
247 reply.type('text/html')
248 return Promise.resolve(request.headers)
249 })
250
251 fastify.inject({
252 method: 'GET',
253 url: '/'
254 }, (err, res) => {
255 t.error(err)
256 t.strictEqual(res.statusCode, 500)
257 t.strictDeepEqual(JSON.parse(res.payload), {
258 error: 'Internal Server Error',
259 code: 'FST_ERR_REP_INVALID_PAYLOAD_TYPE',
260 message: 'FST_ERR_REP_INVALID_PAYLOAD_TYPE: Attempted to send payload of invalid type \'object\'. Expected a string or Buffer.',
261 statusCode: 500
262 })
263 })
264})