UNPKG

11.7 kBJavaScriptView Raw
1'use strict'
2
3const sget = require('simple-get').concat
4const stream = require('stream')
5const symbols = require('../lib/symbols')
6
7/**
8 * @param method HTTP request method
9 * @param t tap instance
10 * @param isSetErrorHandler true: using setErrorHandler
11 */
12module.exports.payloadMethod = function (method, t, isSetErrorHandler = false) {
13 const test = t.test
14 const fastify = require('..')()
15
16 if (isSetErrorHandler) {
17 fastify.setErrorHandler(function (err, request, reply) {
18 t.type(request, 'object')
19 t.type(request, fastify[symbols.kRequest])
20 reply
21 .code(err.statusCode)
22 .type('application/json; charset=utf-8')
23 .send(err)
24 })
25 }
26
27 const upMethod = method.toUpperCase()
28 const loMethod = method.toLowerCase()
29
30 const schema = {
31 schema: {
32 response: {
33 '2xx': {
34 type: 'object',
35 properties: {
36 hello: {
37 type: 'string'
38 }
39 }
40 }
41 }
42 }
43 }
44
45 test(`${upMethod} can be created`, t => {
46 t.plan(1)
47 try {
48 fastify[loMethod]('/', schema, function (req, reply) {
49 reply.code(200).send(req.body)
50 })
51 t.pass()
52 } catch (e) {
53 t.fail()
54 }
55 })
56
57 test(`${upMethod} without schema can be created`, t => {
58 t.plan(1)
59 try {
60 fastify[loMethod]('/missing', function (req, reply) {
61 reply.code(200).send(req.body)
62 })
63 t.pass()
64 } catch (e) {
65 t.fail()
66 }
67 })
68
69 test(`${upMethod} with body and querystring`, t => {
70 t.plan(1)
71 try {
72 fastify[loMethod]('/with-query', function (req, reply) {
73 req.body.hello = req.body.hello + req.query.foo
74 reply.code(200).send(req.body)
75 })
76 t.pass()
77 } catch (e) {
78 t.fail()
79 }
80 })
81
82 test(`${upMethod} with bodyLimit option`, t => {
83 t.plan(1)
84 try {
85 fastify[loMethod]('/with-limit', { bodyLimit: 1 }, function (req, reply) {
86 reply.send(req.body)
87 })
88 t.pass()
89 } catch (e) {
90 t.fail()
91 }
92 })
93
94 fastify.listen(0, function (err) {
95 if (err) {
96 t.error(err)
97 return
98 }
99
100 fastify.server.unref()
101
102 test(`${upMethod} - correctly replies`, t => {
103 t.plan(3)
104 sget({
105 method: upMethod,
106 url: 'http://localhost:' + fastify.server.address().port,
107 body: {
108 hello: 'world'
109 },
110 json: true
111 }, (err, response, body) => {
112 t.error(err)
113 t.strictEqual(response.statusCode, 200)
114 t.deepEqual(body, { hello: 'world' })
115 })
116 })
117
118 test(`${upMethod} - correctly replies with very large body`, t => {
119 t.plan(3)
120
121 const largeString = 'world'.repeat(13200)
122 sget({
123 method: upMethod,
124 url: 'http://localhost:' + fastify.server.address().port,
125 body: { hello: largeString },
126 json: true
127 }, (err, response, body) => {
128 t.error(err)
129 t.strictEqual(response.statusCode, 200)
130 t.deepEqual(body, { hello: largeString })
131 })
132 })
133
134 test(`${upMethod} - correctly replies if the content type has the charset`, t => {
135 t.plan(3)
136 sget({
137 method: upMethod,
138 url: 'http://localhost:' + fastify.server.address().port,
139 body: JSON.stringify({ hello: 'world' }),
140 headers: {
141 'content-type': 'application/json; charset=utf-8'
142 }
143 }, (err, response, body) => {
144 t.error(err)
145 t.strictEqual(response.statusCode, 200)
146 t.deepEqual(body.toString(), JSON.stringify({ hello: 'world' }))
147 })
148 })
149
150 test(`${upMethod} without schema - correctly replies`, t => {
151 t.plan(3)
152 sget({
153 method: upMethod,
154 url: 'http://localhost:' + fastify.server.address().port + '/missing',
155 body: {
156 hello: 'world'
157 },
158 json: true
159 }, (err, response, body) => {
160 t.error(err)
161 t.strictEqual(response.statusCode, 200)
162 t.deepEqual(body, { hello: 'world' })
163 })
164 })
165
166 test(`${upMethod} with body and querystring - correctly replies`, t => {
167 t.plan(3)
168 sget({
169 method: upMethod,
170 url: 'http://localhost:' + fastify.server.address().port + '/with-query?foo=hello',
171 body: {
172 hello: 'world'
173 },
174 json: true
175 }, (err, response, body) => {
176 t.error(err)
177 t.strictEqual(response.statusCode, 200)
178 t.deepEqual(body, { hello: 'worldhello' })
179 })
180 })
181
182 test(`${upMethod} with no body - correctly replies`, t => {
183 t.plan(6)
184
185 sget({
186 method: upMethod,
187 url: 'http://localhost:' + fastify.server.address().port + '/missing',
188 headers: { 'Content-Length': '0' }
189 }, (err, response, body) => {
190 t.error(err)
191 t.strictEqual(response.statusCode, 200)
192 t.strictEqual(JSON.parse(body.toString()), null)
193 })
194
195 // Must use inject to make a request without a Content-Length header
196 fastify.inject({
197 method: upMethod,
198 url: '/missing'
199 }, (err, res) => {
200 t.error(err)
201 t.strictEqual(res.statusCode, 200)
202 t.strictEqual(JSON.parse(res.payload), null)
203 })
204 })
205
206 test(`${upMethod} returns 415 - incorrect media type if body is not json`, t => {
207 t.plan(2)
208 sget({
209 method: upMethod,
210 url: 'http://localhost:' + fastify.server.address().port + '/missing',
211 body: 'hello world'
212
213 }, (err, response, body) => {
214 t.error(err)
215 if (upMethod === 'OPTIONS') {
216 t.strictEqual(response.statusCode, 200)
217 } else {
218 t.strictEqual(response.statusCode, 415)
219 }
220 })
221 })
222
223 if (loMethod === 'options') {
224 test('OPTIONS returns 415 - should return 415 if Content-Type is not json or plain text', t => {
225 t.plan(2)
226 sget({
227 method: upMethod,
228 url: 'http://localhost:' + fastify.server.address().port + '/missing',
229 body: 'hello world',
230 headers: {
231 'Content-Type': 'text/xml'
232 }
233 }, (err, response, body) => {
234 t.error(err)
235 t.strictEqual(response.statusCode, 415)
236 })
237 })
238 }
239
240 test(`${upMethod} returns 400 - Bad Request`, t => {
241 t.plan(4)
242
243 sget({
244 method: upMethod,
245 url: 'http://localhost:' + fastify.server.address().port,
246 body: 'hello world',
247 headers: {
248 'Content-Type': 'application/json'
249 }
250 }, (err, response, body) => {
251 t.error(err)
252 t.strictEqual(response.statusCode, 400)
253 })
254
255 sget({
256 method: upMethod,
257 url: 'http://localhost:' + fastify.server.address().port,
258 headers: {
259 'Content-Type': 'application/json',
260 'Content-Length': '0'
261 }
262 }, (err, response, body) => {
263 t.error(err)
264 t.strictEqual(response.statusCode, 400)
265 })
266 })
267
268 test(`${upMethod} returns 413 - Payload Too Large`, t => {
269 t.plan(upMethod === 'OPTIONS' ? 4 : 6)
270
271 sget({
272 method: upMethod,
273 url: 'http://localhost:' + fastify.server.address().port,
274 headers: {
275 'Content-Type': 'application/json',
276 'Content-Length': 1024 * 1024 + 1
277 }
278 }, (err, response, body) => {
279 t.error(err)
280 t.strictEqual(response.statusCode, 413)
281 })
282
283 // Node errors for OPTIONS requests with a stream body and no Content-Length header
284 if (upMethod !== 'OPTIONS') {
285 var chunk = Buffer.alloc(1024 * 1024 + 1, 0)
286 const largeStream = new stream.Readable({
287 read () {
288 this.push(chunk)
289 chunk = null
290 }
291 })
292 sget({
293 method: upMethod,
294 url: 'http://localhost:' + fastify.server.address().port,
295 headers: { 'Content-Type': 'application/json' },
296 body: largeStream
297 }, (err, response, body) => {
298 t.error(err)
299 t.strictEqual(response.statusCode, 413)
300 })
301 }
302
303 sget({
304 method: upMethod,
305 url: `http://localhost:${fastify.server.address().port}/with-limit`,
306 headers: { 'Content-Type': 'application/json' },
307 body: {},
308 json: true
309 }, (err, response, body) => {
310 t.error(err)
311 t.strictEqual(response.statusCode, 413)
312 })
313 })
314
315 test(`${upMethod} should fail with empty body and application/json content-type`, t => {
316 if (upMethod === 'OPTIONS') return t.end()
317
318 t.plan(12)
319
320 fastify.inject({
321 method: `${upMethod}`,
322 url: '/',
323 headers: {
324 'Content-Type': 'application/json'
325 }
326 }, (err, res) => {
327 t.error(err)
328 t.strictDeepEqual(JSON.parse(res.payload), {
329 error: 'Bad Request',
330 code: 'FST_ERR_CTP_EMPTY_JSON_BODY',
331 message: "FST_ERR_CTP_EMPTY_JSON_BODY: Body cannot be empty when content-type is set to 'application/json'",
332 statusCode: 400
333 })
334 })
335
336 sget({
337 method: upMethod,
338 url: `http://localhost:${fastify.server.address().port}`,
339 headers: {
340 'Content-Type': 'application/json'
341 }
342 }, (err, res, body) => {
343 t.error(err)
344 t.strictDeepEqual(JSON.parse(body.toString()), {
345 error: 'Bad Request',
346 code: 'FST_ERR_CTP_EMPTY_JSON_BODY',
347 message: "FST_ERR_CTP_EMPTY_JSON_BODY: Body cannot be empty when content-type is set to 'application/json'",
348 statusCode: 400
349 })
350 })
351
352 fastify.inject({
353 method: `${upMethod}`,
354 url: '/',
355 headers: {
356 'Content-Type': 'application/json'
357 },
358 payload: null
359 }, (err, res) => {
360 t.error(err)
361 t.strictDeepEqual(JSON.parse(res.payload), {
362 error: 'Bad Request',
363 code: 'FST_ERR_CTP_EMPTY_JSON_BODY',
364 message: "FST_ERR_CTP_EMPTY_JSON_BODY: Body cannot be empty when content-type is set to 'application/json'",
365 statusCode: 400
366 })
367 })
368
369 sget({
370 method: upMethod,
371 url: `http://localhost:${fastify.server.address().port}`,
372 headers: {
373 'Content-Type': 'application/json'
374 },
375 payload: null
376 }, (err, res, body) => {
377 t.error(err)
378 t.strictDeepEqual(JSON.parse(body.toString()), {
379 error: 'Bad Request',
380 code: 'FST_ERR_CTP_EMPTY_JSON_BODY',
381 message: "FST_ERR_CTP_EMPTY_JSON_BODY: Body cannot be empty when content-type is set to 'application/json'",
382 statusCode: 400
383 })
384 })
385
386 fastify.inject({
387 method: `${upMethod}`,
388 url: '/',
389 headers: {
390 'Content-Type': 'application/json'
391 },
392 payload: undefined
393 }, (err, res) => {
394 t.error(err)
395 t.strictDeepEqual(JSON.parse(res.payload), {
396 error: 'Bad Request',
397 code: 'FST_ERR_CTP_EMPTY_JSON_BODY',
398 message: "FST_ERR_CTP_EMPTY_JSON_BODY: Body cannot be empty when content-type is set to 'application/json'",
399 statusCode: 400
400 })
401 })
402
403 sget({
404 method: upMethod,
405 url: `http://localhost:${fastify.server.address().port}`,
406 headers: {
407 'Content-Type': 'application/json'
408 },
409 payload: undefined
410 }, (err, res, body) => {
411 t.error(err)
412 t.strictDeepEqual(JSON.parse(body.toString()), {
413 error: 'Bad Request',
414 code: 'FST_ERR_CTP_EMPTY_JSON_BODY',
415 message: "FST_ERR_CTP_EMPTY_JSON_BODY: Body cannot be empty when content-type is set to 'application/json'",
416 statusCode: 400
417 })
418 })
419 })
420 })
421}