Spaces:
Runtime error
Runtime error
| const t = require('tap') | |
| const fastify = require('fastify') | |
| const AjvCompiler = require('../index') | |
| const ajvFormats = require('ajv-formats') | |
| const ajvErrors = require('ajv-errors') | |
| const localize = require('ajv-i18n') | |
| t.test('Format Baseline test', async (t) => { | |
| const app = buildApplication({ | |
| customOptions: { | |
| validateFormats: false | |
| } | |
| }) | |
| const res = await app.inject({ | |
| url: '/hello', | |
| headers: { | |
| 'x-foo': 'hello', | |
| 'x-date': 'not a date', | |
| 'x-email': 'not an email' | |
| }, | |
| query: { | |
| foo: 'hello', | |
| date: 'not a date', | |
| email: 'not an email' | |
| } | |
| }) | |
| t.equal(res.statusCode, 200, 'format validation does not apply as configured') | |
| t.equal(res.payload, 'hello') | |
| }) | |
| t.test('Custom Format plugin loading test', (t) => { | |
| t.plan(6) | |
| const app = buildApplication({ | |
| customOptions: { | |
| validateFormats: true | |
| }, | |
| plugins: [[ajvFormats, { mode: 'fast' }]] | |
| }) | |
| app.inject('/hello', (err, res) => { | |
| t.error(err) | |
| t.equal(res.statusCode, 400, 'format validation applies') | |
| }) | |
| app.inject('/2ad0612c-7578-4b18-9a6f-579863f40e0b', (err, res) => { | |
| t.error(err) | |
| t.equal(res.statusCode, 400, 'format validation applies') | |
| }) | |
| app.inject({ | |
| url: '/2ad0612c-7578-4b18-9a6f-579863f40e0b', | |
| headers: { | |
| 'x-foo': 'hello', | |
| 'x-date': new Date().toISOString(), | |
| 'x-email': 'foo@bar.baz' | |
| }, | |
| query: { | |
| foo: 'hello', | |
| date: new Date().toISOString(), | |
| email: 'foo@bar.baz' | |
| } | |
| }, (err, res) => { | |
| t.error(err) | |
| t.equal(res.statusCode, 200) | |
| }) | |
| }) | |
| t.test('Format plugin set by default test', (t) => { | |
| t.plan(6) | |
| const app = buildApplication({}) | |
| app.inject('/hello', (err, res) => { | |
| t.error(err) | |
| t.equal(res.statusCode, 400, 'format validation applies') | |
| }) | |
| app.inject('/2ad0612c-7578-4b18-9a6f-579863f40e0b', (err, res) => { | |
| t.error(err) | |
| t.equal(res.statusCode, 400, 'format validation applies') | |
| }) | |
| app.inject({ | |
| url: '/2ad0612c-7578-4b18-9a6f-579863f40e0b', | |
| headers: { | |
| 'x-foo': 'hello', | |
| 'x-date': new Date().toISOString(), | |
| 'x-email': 'foo@bar.baz' | |
| }, | |
| query: { | |
| foo: 'hello', | |
| date: new Date().toISOString(), | |
| email: 'foo@bar.baz' | |
| } | |
| }, (err, res) => { | |
| t.error(err) | |
| t.equal(res.statusCode, 200) | |
| }) | |
| }) | |
| t.test('Custom error messages', (t) => { | |
| t.plan(9) | |
| const app = buildApplication({ | |
| customOptions: { | |
| removeAdditional: false, | |
| allErrors: true | |
| }, | |
| plugins: [ajvFormats, ajvErrors] | |
| }) | |
| const errorMessage = { | |
| required: 'custom miss', | |
| type: 'custom type', // will not replace internal "type" error for the property "foo" | |
| _: 'custom type', // this prop will do it | |
| additionalProperties: 'custom too many params' | |
| } | |
| app.post('/', { | |
| handler: () => { t.fail('dont call me') }, | |
| schema: { | |
| body: { | |
| type: 'object', | |
| required: ['foo'], | |
| properties: { | |
| foo: { type: 'integer' } | |
| }, | |
| additionalProperties: false, | |
| errorMessage | |
| } | |
| } | |
| }) | |
| app.inject({ | |
| url: '/', | |
| method: 'post', | |
| payload: {} | |
| }, (err, res) => { | |
| t.error(err) | |
| t.equal(res.statusCode, 400) | |
| t.match(res.json().message, errorMessage.required) | |
| }) | |
| app.inject({ | |
| url: '/', | |
| method: 'post', | |
| payload: { foo: 'not a number' } | |
| }, (err, res) => { | |
| t.error(err) | |
| t.equal(res.statusCode, 400) | |
| t.match(res.json().message, errorMessage.type) | |
| }) | |
| app.inject({ | |
| url: '/', | |
| method: 'post', | |
| payload: { foo: 3, bar: 'ops' } | |
| }, (err, res) => { | |
| t.error(err) | |
| t.equal(res.statusCode, 400) | |
| t.match(res.json().message, errorMessage.additionalProperties) | |
| }) | |
| }) | |
| t.test('Custom i18n error messages', (t) => { | |
| t.plan(3) | |
| const app = buildApplication({ | |
| customOptions: { | |
| allErrors: true, | |
| messages: false | |
| }, | |
| plugins: [ajvFormats] | |
| }) | |
| app.post('/', { | |
| handler: () => { t.fail('dont call me') }, | |
| schema: { | |
| body: { | |
| type: 'object', | |
| required: ['foo'], | |
| properties: { | |
| foo: { type: 'integer' } | |
| } | |
| } | |
| } | |
| }) | |
| app.setErrorHandler((error, request, reply) => { | |
| t.pass('Error handler executed') | |
| if (error.validation) { | |
| localize.ru(error.validation) | |
| reply.status(400).send(error.validation) | |
| return | |
| } | |
| t.fail('not other errors') | |
| }) | |
| app.inject({ | |
| method: 'POST', | |
| url: '/', | |
| payload: { | |
| foo: 'string' | |
| } | |
| }, (err, res) => { | |
| t.error(err) | |
| t.equal(res.json()[0].message, 'должно быть integer') | |
| }) | |
| }) | |
| function buildApplication (ajvOptions) { | |
| const factory = AjvCompiler() | |
| const app = fastify({ | |
| ajv: ajvOptions, | |
| schemaController: { | |
| compilersFactory: { | |
| buildValidator: factory | |
| } | |
| } | |
| }) | |
| app.get('/:id', { | |
| schema: { | |
| headers: { | |
| type: 'object', | |
| required: [ | |
| 'x-foo', | |
| 'x-date', | |
| 'x-email' | |
| ], | |
| properties: { | |
| 'x-foo': { type: 'string' }, | |
| 'x-date': { type: 'string', format: 'date-time' }, | |
| 'x-email': { type: 'string', format: 'email' } | |
| } | |
| }, | |
| query: { | |
| type: 'object', | |
| required: [ | |
| 'foo', | |
| 'date', | |
| 'email' | |
| ], | |
| properties: { | |
| foo: { type: 'string' }, | |
| date: { type: 'string', format: 'date-time' }, | |
| email: { type: 'string', format: 'email' } | |
| } | |
| }, | |
| params: { | |
| type: 'object', | |
| properties: { | |
| id: { type: 'string', format: 'uuid' } | |
| } | |
| } | |
| } | |
| }, async () => 'hello') | |
| return app | |
| } | |