diff --git a/.gitignore b/.gitignore index 3c21249..2b6aed4 100644 --- a/.gitignore +++ b/.gitignore @@ -147,3 +147,6 @@ yarn.lock # editor files .vscode .idea + +#tap files +.tap/ diff --git a/index.js b/index.js index 7a5a01f..3e97bde 100644 --- a/index.js +++ b/index.js @@ -2,10 +2,11 @@ const fp = require('fastify-plugin') const Ajv = require('ajv') +const AjvCore = require('ajv/dist/core') function fastifyResponseValidation (fastify, opts, next) { let ajv - if (opts.ajv && opts.ajv instanceof Ajv) { + if (opts.ajv && opts.ajv instanceof AjvCore.default) { ajv = opts.ajv } else { const { plugins: ajvPlugins, ...ajvOptions } = Object.assign({ diff --git a/package.json b/package.json index b5db3f2..77173d0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@fastify/response-validation", - "version": "2.5.1", + "version": "2.6.0", "description": "A simple plugin that enables response validation for Fastify.", "main": "index.js", "type": "commonjs", @@ -16,7 +16,7 @@ "fastify": "^4.2.1", "standard": "^17.0.0", "tap": "^16.3.0", - "tsd": "^0.29.0" + "tsd": "^0.30.1" }, "scripts": { "lint": "standard", diff --git a/test/ajv.test.js b/test/ajv.test.js index a6f252f..c0d61e9 100644 --- a/test/ajv.test.js +++ b/test/ajv.test.js @@ -4,6 +4,8 @@ const test = require('tap').test const Fastify = require('fastify') const plugin = require('..') const Ajv = require('ajv') +const Ajv2019 = require('ajv/dist/2019') +const Ajv2020 = require('ajv/dist/2020') const ajvFormats = require('ajv-formats') const ajvErrors = require('ajv-errors') @@ -171,6 +173,144 @@ test('use ajv errors with Ajv instance', async t => { t.equal(response.json().message, 'response should be an object with an integer property answer only') }) +test('use ajv formats with 2019 Ajv instance', async t => { + const fastify = Fastify() + const ajv = new Ajv2019() + ajvFormats(ajv) + await fastify.register(plugin, { ajv }) + + fastify.route({ + method: 'GET', + url: '/', + schema: { + response: { + '2xx': { + type: 'object', + properties: { + answer: { type: 'number', format: 'float' } + } + } + } + }, + handler: async (req, reply) => { + return { answer: 2.4 } + } + }) + + const response = await fastify.inject({ + method: 'GET', + url: '/' + }) + + t.equal(response.statusCode, 200) + t.strictSame(JSON.parse(response.payload), { answer: 2.4 }) +}) + +test('use ajv errors with 2019 Ajv instance', async t => { + const fastify = Fastify() + const ajv = new Ajv2019({ allErrors: true }) + ajvErrors(ajv, { singleError: true }) + await fastify.register(plugin, { ajv }) + + fastify.route({ + method: 'GET', + url: '/', + schema: { + response: { + '2xx': { + type: 'object', + required: ['answer'], + properties: { + answer: { type: 'number' } + }, + additionalProperties: false, + errorMessage: 'should be an object with an integer property answer only' + } + } + }, + handler: async (req, reply) => { + return { notAnAnswer: 24 } + } + }) + + const response = await fastify.inject({ + method: 'GET', + url: '/' + }) + + t.equal(response.statusCode, 500) + t.equal(response.json().message, 'response should be an object with an integer property answer only') +}) + +test('use ajv formats with 2020 Ajv instance', async t => { + const fastify = Fastify() + const ajv = new Ajv2020() + ajvFormats(ajv) + await fastify.register(plugin, { ajv }) + + fastify.route({ + method: 'GET', + url: '/', + schema: { + response: { + '2xx': { + type: 'object', + properties: { + answer: { type: 'number', format: 'float' } + } + } + } + }, + handler: async (req, reply) => { + return { answer: 2.4 } + } + }) + + const response = await fastify.inject({ + method: 'GET', + url: '/' + }) + + t.equal(response.statusCode, 200) + t.strictSame(JSON.parse(response.payload), { answer: 2.4 }) +}) + +test('use ajv errors with 2019 Ajv instance', async t => { + const fastify = Fastify() + const ajv = new Ajv2020({ allErrors: true }) + ajvErrors(ajv, { singleError: true }) + await fastify.register(plugin, { ajv }) + + fastify.route({ + method: 'GET', + url: '/', + schema: { + response: { + '2xx': { + type: 'object', + required: ['answer'], + properties: { + answer: { type: 'number' } + }, + additionalProperties: false, + errorMessage: 'should be an object with an integer property answer only' + } + } + }, + handler: async (req, reply) => { + return { notAnAnswer: 24 } + } + }) + + const response = await fastify.inject({ + method: 'GET', + url: '/' + }) + + t.equal(response.statusCode, 500) + t.equal(response.json().message, 'response should be an object with an integer property answer only') +}) + test('should throw an error if ajv.plugins is not passed to instance and not array', async t => { t.plan(1) const fastify = Fastify()