You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					214 lines
				
				4.9 KiB
			
		
		
			
		
	
	
					214 lines
				
				4.9 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								'use strict'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const fs = require('fs')
							 | 
						||
| 
								 | 
							
								const path = require('path')
							 | 
						||
| 
								 | 
							
								const t = require('tap')
							 | 
						||
| 
								 | 
							
								const fastify = require('fastify')
							 | 
						||
| 
								 | 
							
								const sanitize = require('sanitize-filename')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const { StandaloneSerializer: FjsStandaloneCompiler } = require('../')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function generateFileName (routeOpts) {
							 | 
						||
| 
								 | 
							
								  return `/fjs-generated-${sanitize(routeOpts.schema.$id)}-${routeOpts.method}-${routeOpts.httpPart}-${sanitize(routeOpts.url)}.js`
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								t.test('errors', t => {
							 | 
						||
| 
								 | 
							
								  t.plan(2)
							 | 
						||
| 
								 | 
							
								  t.throws(() => {
							 | 
						||
| 
								 | 
							
								    FjsStandaloneCompiler()
							 | 
						||
| 
								 | 
							
								  }, 'missing restoreFunction')
							 | 
						||
| 
								 | 
							
								  t.throws(() => {
							 | 
						||
| 
								 | 
							
								    FjsStandaloneCompiler({ readMode: false })
							 | 
						||
| 
								 | 
							
								  }, 'missing storeFunction')
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								t.test('generate standalone code', t => {
							 | 
						||
| 
								 | 
							
								  t.plan(5)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const base = {
							 | 
						||
| 
								 | 
							
								    $id: 'urn:schema:base',
							 | 
						||
| 
								 | 
							
								    definitions: {
							 | 
						||
| 
								 | 
							
								      hello: { type: 'string' }
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								    type: 'object',
							 | 
						||
| 
								 | 
							
								    properties: {
							 | 
						||
| 
								 | 
							
								      hello: { $ref: '#/definitions/hello' }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const refSchema = {
							 | 
						||
| 
								 | 
							
								    $id: 'urn:schema:ref',
							 | 
						||
| 
								 | 
							
								    type: 'object',
							 | 
						||
| 
								 | 
							
								    properties: {
							 | 
						||
| 
								 | 
							
								      hello: { $ref: 'urn:schema:base#/definitions/hello' }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const endpointSchema = {
							 | 
						||
| 
								 | 
							
								    schema: {
							 | 
						||
| 
								 | 
							
								      $id: 'urn:schema:endpoint',
							 | 
						||
| 
								 | 
							
								      $ref: 'urn:schema:ref'
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const schemaMap = {
							 | 
						||
| 
								 | 
							
								    [base.$id]: base,
							 | 
						||
| 
								 | 
							
								    [refSchema.$id]: refSchema
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const factory = FjsStandaloneCompiler({
							 | 
						||
| 
								 | 
							
								    readMode: false,
							 | 
						||
| 
								 | 
							
								    storeFunction (routeOpts, schemaSerializerCode) {
							 | 
						||
| 
								 | 
							
								      t.same(routeOpts, endpointSchema)
							 | 
						||
| 
								 | 
							
								      t.type(schemaSerializerCode, 'string')
							 | 
						||
| 
								 | 
							
								      fs.writeFileSync(path.join(__dirname, '/fjs-generated.js'), schemaSerializerCode)
							 | 
						||
| 
								 | 
							
								      t.pass('stored the serializer function')
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const compiler = factory(schemaMap)
							 | 
						||
| 
								 | 
							
								  compiler(endpointSchema)
							 | 
						||
| 
								 | 
							
								  t.pass('compiled the endpoint schema')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  t.test('usage standalone code', t => {
							 | 
						||
| 
								 | 
							
								    t.plan(3)
							 | 
						||
| 
								 | 
							
								    const standaloneSerializer = require('./fjs-generated')
							 | 
						||
| 
								 | 
							
								    t.ok(standaloneSerializer)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const valid = standaloneSerializer({ hello: 'world' })
							 | 
						||
| 
								 | 
							
								    t.same(valid, JSON.stringify({ hello: 'world' }))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const invalid = standaloneSerializer({ hello: [] })
							 | 
						||
| 
								 | 
							
								    t.same(invalid, '{"hello":""}')
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								t.test('fastify integration - writeMode', async t => {
							 | 
						||
| 
								 | 
							
								  t.plan(4)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const factory = FjsStandaloneCompiler({
							 | 
						||
| 
								 | 
							
								    readMode: false,
							 | 
						||
| 
								 | 
							
								    storeFunction (routeOpts, schemaSerializationCode) {
							 | 
						||
| 
								 | 
							
								      const fileName = generateFileName(routeOpts)
							 | 
						||
| 
								 | 
							
								      t.ok(routeOpts)
							 | 
						||
| 
								 | 
							
								      fs.writeFileSync(path.join(__dirname, fileName), schemaSerializationCode)
							 | 
						||
| 
								 | 
							
								      t.pass(`stored the serializer function ${fileName}`)
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								    restoreFunction () {
							 | 
						||
| 
								 | 
							
								      t.fail('write mode ON')
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const app = buildApp(factory)
							 | 
						||
| 
								 | 
							
								  await app.ready()
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								t.test('fastify integration - writeMode forces standalone', async t => {
							 | 
						||
| 
								 | 
							
								  t.plan(4)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const factory = FjsStandaloneCompiler({
							 | 
						||
| 
								 | 
							
								    readMode: false,
							 | 
						||
| 
								 | 
							
								    storeFunction (routeOpts, schemaSerializationCode) {
							 | 
						||
| 
								 | 
							
								      const fileName = generateFileName(routeOpts)
							 | 
						||
| 
								 | 
							
								      t.ok(routeOpts)
							 | 
						||
| 
								 | 
							
								      fs.writeFileSync(path.join(__dirname, fileName), schemaSerializationCode)
							 | 
						||
| 
								 | 
							
								      t.pass(`stored the serializer function ${fileName}`)
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								    restoreFunction () {
							 | 
						||
| 
								 | 
							
								      t.fail('write mode ON')
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const app = buildApp(factory, {
							 | 
						||
| 
								 | 
							
								    mode: 'not-standalone',
							 | 
						||
| 
								 | 
							
								    rounding: 'ceil'
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  await app.ready()
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								t.test('fastify integration - readMode', async t => {
							 | 
						||
| 
								 | 
							
								  t.plan(6)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const factory = FjsStandaloneCompiler({
							 | 
						||
| 
								 | 
							
								    readMode: true,
							 | 
						||
| 
								 | 
							
								    storeFunction () {
							 | 
						||
| 
								 | 
							
								      t.fail('read mode ON')
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								    restoreFunction (routeOpts) {
							 | 
						||
| 
								 | 
							
								      const fileName = generateFileName(routeOpts)
							 | 
						||
| 
								 | 
							
								      t.pass(`restore the serializer function ${fileName}}`)
							 | 
						||
| 
								 | 
							
								      return require(path.join(__dirname, fileName))
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const app = buildApp(factory)
							 | 
						||
| 
								 | 
							
								  await app.ready()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  let res = await app.inject({
							 | 
						||
| 
								 | 
							
								    url: '/foo',
							 | 
						||
| 
								 | 
							
								    method: 'POST'
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								  t.equal(res.statusCode, 200)
							 | 
						||
| 
								 | 
							
								  t.equal(res.payload, JSON.stringify({ hello: 'world' }))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  res = await app.inject({
							 | 
						||
| 
								 | 
							
								    url: '/bar?lang=it',
							 | 
						||
| 
								 | 
							
								    method: 'GET'
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								  t.equal(res.statusCode, 200)
							 | 
						||
| 
								 | 
							
								  t.equal(res.payload, JSON.stringify({ lang: 'en' }))
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function buildApp (factory, serializerOpts) {
							 | 
						||
| 
								 | 
							
								  const app = fastify({
							 | 
						||
| 
								 | 
							
								    exposeHeadRoutes: false,
							 | 
						||
| 
								 | 
							
								    jsonShorthand: false,
							 | 
						||
| 
								 | 
							
								    schemaController: {
							 | 
						||
| 
								 | 
							
								      compilersFactory: {
							 | 
						||
| 
								 | 
							
								        buildSerializer: factory
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								    serializerOpts
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  app.addSchema({
							 | 
						||
| 
								 | 
							
								    $id: 'urn:schema:foo',
							 | 
						||
| 
								 | 
							
								    type: 'object',
							 | 
						||
| 
								 | 
							
								    properties: {
							 | 
						||
| 
								 | 
							
								      name: { type: 'string' },
							 | 
						||
| 
								 | 
							
								      id: { type: 'integer' }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  app.post('/foo', {
							 | 
						||
| 
								 | 
							
								    schema: {
							 | 
						||
| 
								 | 
							
								      response: {
							 | 
						||
| 
								 | 
							
								        200: {
							 | 
						||
| 
								 | 
							
								          $id: 'urn:schema:response',
							 | 
						||
| 
								 | 
							
								          type: 'object',
							 | 
						||
| 
								 | 
							
								          properties: {
							 | 
						||
| 
								 | 
							
								            hello: { $ref: 'urn:schema:foo#/properties/name' }
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }, () => { return { hello: 'world' } })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  app.get('/bar', {
							 | 
						||
| 
								 | 
							
								    schema: {
							 | 
						||
| 
								 | 
							
								      response: {
							 | 
						||
| 
								 | 
							
								        200: {
							 | 
						||
| 
								 | 
							
								          $id: 'urn:schema:response:bar',
							 | 
						||
| 
								 | 
							
								          type: 'object',
							 | 
						||
| 
								 | 
							
								          properties: {
							 | 
						||
| 
								 | 
							
								            lang: { type: 'string', enum: ['it', 'en'] }
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }, () => { return { lang: 'en' } })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return app
							 | 
						||
| 
								 | 
							
								}
							 |