mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-25 13:45:52 +00:00
feat: add ajv-formats support to jsonSchema assertion (#7897)
* Enhance JSON schema validation by integrating ajv-formats for additional format support in tests and runtime assertions. * fix: update pre-request script to stop execution instead of running it * fix: ensure newline at end of file in pre-request script for ping.bru * refactor: update JSON schema validation tests to assert rejection of invalid formats * refactor: streamline JSON schema validation by using a default AJV instance and enhance tests for various ajvOptions scenarios * refactor: update JSON schema tests to use more descriptive property names and improve error handling for invalid formats * feat: add support for Draft-07 JSON Schema validation and improve error handling for unsupported schema versions * fix: improve error message for unsupported JSON Schema versions in runtime assertions and tests
This commit is contained in:
@@ -8,6 +8,7 @@ const { interpolateString } = require('../interpolate-string');
|
||||
const { executeQuickJsVm } = require('../sandbox/quickjs');
|
||||
|
||||
const Ajv = require('ajv');
|
||||
const addFormats = require('ajv-formats');
|
||||
const { expect } = chai;
|
||||
chai.use(require('chai-string'));
|
||||
chai.use(function (chai, utils) {
|
||||
@@ -26,9 +27,30 @@ chai.use(function (chai, utils) {
|
||||
});
|
||||
|
||||
// Custom assertion for JSON Schema validation
|
||||
const defaultAjv = new Ajv({ allErrors: true });
|
||||
addFormats(defaultAjv);
|
||||
|
||||
const SUPPORTED_SCHEMA_VERSIONS = [
|
||||
'http://json-schema.org/draft-07/schema#',
|
||||
'http://json-schema.org/draft-07/schema'
|
||||
];
|
||||
|
||||
chai.use(function (chai) {
|
||||
chai.Assertion.addMethod('jsonSchema', function (schema, ajvOptions) {
|
||||
const ajv = new Ajv({ allErrors: true, ...ajvOptions });
|
||||
if (schema && schema.$schema && !SUPPORTED_SCHEMA_VERSIONS.includes(schema.$schema)) {
|
||||
this.assert(
|
||||
false,
|
||||
`Unsupported JSON Schema version: "${schema.$schema}". Bruno currently only supports Draft-07 (http://json-schema.org/draft-07/schema#). Please update your schema to be Draft-07 compatible and remove the $schema property.`,
|
||||
`Unsupported JSON Schema version: "${schema.$schema}".`
|
||||
);
|
||||
}
|
||||
let ajv;
|
||||
if (ajvOptions) {
|
||||
ajv = new Ajv({ allErrors: true, ...ajvOptions });
|
||||
addFormats(ajv);
|
||||
} else {
|
||||
ajv = defaultAjv;
|
||||
}
|
||||
let validate;
|
||||
try {
|
||||
validate = ajv.compile(schema);
|
||||
|
||||
@@ -15,6 +15,7 @@ const bundleLibraries = async () => {
|
||||
import * as cryptoJs from 'crypto-js';
|
||||
import tv4 from "tv4";
|
||||
import Ajv from "ajv";
|
||||
import addFormats from "ajv-formats";
|
||||
globalThis.expect = expect;
|
||||
globalThis.assert = assert;
|
||||
globalThis.moment = moment;
|
||||
@@ -23,6 +24,7 @@ const bundleLibraries = async () => {
|
||||
globalThis.Buffer = Buffer;
|
||||
globalThis.tv4 = tv4;
|
||||
globalThis.Ajv = Ajv;
|
||||
globalThis.addFormats = addFormats;
|
||||
globalThis.requireObject = {
|
||||
...(globalThis.requireObject || {}),
|
||||
'chai': { expect, assert },
|
||||
@@ -32,7 +34,8 @@ const bundleLibraries = async () => {
|
||||
'atob': atob,
|
||||
'crypto-js': cryptoJs,
|
||||
'tv4': tv4,
|
||||
'ajv': Ajv
|
||||
'ajv': Ajv,
|
||||
'ajv-formats': addFormats
|
||||
};
|
||||
`;
|
||||
|
||||
|
||||
@@ -84,9 +84,29 @@ const addBruShimToContext = (vm, __brunoTestResults) => {
|
||||
`
|
||||
(function() {
|
||||
var Ajv = require('ajv');
|
||||
var addFormats = require('ajv-formats');
|
||||
var defaultAjv = new Ajv({ allErrors: true });
|
||||
addFormats(defaultAjv);
|
||||
var SUPPORTED_SCHEMA_VERSIONS = [
|
||||
'http://json-schema.org/draft-07/schema#',
|
||||
'http://json-schema.org/draft-07/schema'
|
||||
];
|
||||
var proto = Object.getPrototypeOf(expect(null));
|
||||
proto.jsonSchema = function(schema, ajvOptions) {
|
||||
var ajv = new Ajv(Object.assign({ allErrors: true }, ajvOptions || {}));
|
||||
if (schema && schema.$schema && !SUPPORTED_SCHEMA_VERSIONS.includes(schema.$schema)) {
|
||||
this.assert(
|
||||
false,
|
||||
'Unsupported JSON Schema version: "' + schema.$schema + '". Bruno currently only supports Draft-07 (http://json-schema.org/draft-07/schema#). Please update your schema to be Draft-07 compatible and remove the $schema property.',
|
||||
'Unsupported JSON Schema version: "' + schema.$schema + '".'
|
||||
);
|
||||
}
|
||||
var ajv;
|
||||
if (ajvOptions) {
|
||||
ajv = new Ajv(Object.assign({ allErrors: true }, ajvOptions));
|
||||
addFormats(ajv);
|
||||
} else {
|
||||
ajv = defaultAjv;
|
||||
}
|
||||
var validate;
|
||||
try {
|
||||
validate = ajv.compile(schema);
|
||||
|
||||
@@ -501,6 +501,40 @@ describe('runtime', () => {
|
||||
const schema = { type: 'array' };
|
||||
chai.expect(body).to.not.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
it('should throw a clear error for unsupported Draft 2020-12 $schema', () => {
|
||||
const body = { name: 'John' };
|
||||
const schema = {
|
||||
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
||||
type: 'object',
|
||||
properties: { name: { type: 'string' } }
|
||||
};
|
||||
expect(() => chai.expect(body).to.have.jsonSchema(schema)).toThrow(/Unsupported JSON Schema version.*2020-12.*only supports Draft-07/);
|
||||
});
|
||||
|
||||
it('should throw a clear error for unsupported Draft 2019-09 $schema', () => {
|
||||
const body = { name: 'John' };
|
||||
const schema = {
|
||||
$schema: 'https://json-schema.org/draft/2019-09/schema',
|
||||
type: 'object',
|
||||
properties: { name: { type: 'string' } }
|
||||
};
|
||||
expect(() => chai.expect(body).to.have.jsonSchema(schema)).toThrow(/Unsupported JSON Schema version.*2019-09.*only supports Draft-07/);
|
||||
});
|
||||
|
||||
it('should allow explicit Draft-07 $schema', () => {
|
||||
const body = { name: 'John', age: 30 };
|
||||
const schema = {
|
||||
$schema: 'http://json-schema.org/draft-07/schema#',
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
age: { type: 'number' }
|
||||
},
|
||||
required: ['name', 'age']
|
||||
};
|
||||
chai.expect(body).to.have.jsonSchema(schema);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -23,7 +23,27 @@ body:json {
|
||||
"street": "123 Main St",
|
||||
"city": "Springfield",
|
||||
"zip": "62701"
|
||||
}
|
||||
},
|
||||
"website": "https://example.com/john",
|
||||
"createdAt": "2024-01-15T10:30:00Z",
|
||||
"birthDate": "1994-05-20",
|
||||
"loginTime": "10:30:00Z",
|
||||
"ipv4": "192.168.1.1",
|
||||
"ipv6": "::1",
|
||||
"id": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"encodedData": "SGVsbG8gV29ybGQ=",
|
||||
"int32Val": 2147483647,
|
||||
"int64Val": 2147483648,
|
||||
"floatVal": 3.14,
|
||||
"doubleVal": 1.7976931348623157e+308,
|
||||
"duration": "P3Y6M4DT12H30M5S",
|
||||
"hostname": "example.com",
|
||||
"regexPattern": "^[a-z]+$",
|
||||
"jsonPointer": "/foo/bar/0",
|
||||
"uriRef": "/relative/path",
|
||||
"uriTemplate": "https://example.com/{user}",
|
||||
"invalidRegex": "[invalid",
|
||||
"invalidUriTemplate": "https://example.com/{invalid"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +186,7 @@ tests {
|
||||
expect(res.getBody()).to.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("jsonSchema with ajvOptions", function() {
|
||||
test("jsonSchema with ajvOptions - allErrors", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -178,6 +198,525 @@ tests {
|
||||
expect(res.getBody()).to.have.jsonSchema(schema, { allErrors: true });
|
||||
});
|
||||
|
||||
test("jsonSchema with ajvOptions - format validation with allErrors", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
email: { type: 'string', format: 'email' },
|
||||
website: { type: 'string', format: 'uri' }
|
||||
},
|
||||
required: ['email', 'website']
|
||||
};
|
||||
expect(res.getBody()).to.have.jsonSchema(schema, { allErrors: true });
|
||||
});
|
||||
|
||||
test("jsonSchema with ajvOptions - format rejection with allErrors", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', format: 'email' },
|
||||
age: { type: 'string', format: 'uri' }
|
||||
},
|
||||
required: ['name', 'age']
|
||||
};
|
||||
expect(res.getBody()).to.not.have.jsonSchema(schema, { allErrors: true });
|
||||
});
|
||||
|
||||
test("jsonSchema with ajvOptions - additionalProperties false", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' }
|
||||
},
|
||||
additionalProperties: false
|
||||
};
|
||||
expect(res.getBody()).to.not.have.jsonSchema(schema, { allErrors: true });
|
||||
});
|
||||
|
||||
test("jsonSchema with ajvOptions - coerceTypes allows string as number", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
zip: { type: 'integer' }
|
||||
},
|
||||
required: ['zip']
|
||||
};
|
||||
// zip is "62701" (string) - fails without coercion
|
||||
expect(res.getBody().address).to.not.have.jsonSchema(schema);
|
||||
// passes with coerceTypes since "62701" can be coerced to integer
|
||||
expect(res.getBody().address).to.have.jsonSchema(schema, { coerceTypes: true });
|
||||
});
|
||||
|
||||
test("jsonSchema with ajvOptions - coerceTypes allows number as string", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
age: { type: 'string' }
|
||||
},
|
||||
required: ['age']
|
||||
};
|
||||
// age is 30 (number) - fails without coercion
|
||||
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
||||
// passes with coerceTypes since 30 can be coerced to "30"
|
||||
expect(res.getBody()).to.have.jsonSchema(schema, { coerceTypes: true });
|
||||
});
|
||||
|
||||
test("jsonSchema with ajvOptions - strict false allows unknown keywords", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', customKeyword: true }
|
||||
},
|
||||
required: ['name']
|
||||
};
|
||||
// unknown keyword "customKeyword" throws in strict mode (default)
|
||||
expect(() => expect(res.getBody()).to.have.jsonSchema(schema)).to.throw('JSON schema compile error');
|
||||
// passes with strict: false
|
||||
expect(res.getBody()).to.have.jsonSchema(schema, { strict: false });
|
||||
});
|
||||
|
||||
// --- ajv-formats: Passing validations ---
|
||||
|
||||
test("format: email - valid email", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
email: { type: 'string', format: 'email' }
|
||||
},
|
||||
required: ['email']
|
||||
};
|
||||
expect(res.getBody()).to.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: uri - valid URI", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
website: { type: 'string', format: 'uri' }
|
||||
},
|
||||
required: ['website']
|
||||
};
|
||||
expect(res.getBody()).to.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: date-time - valid ISO 8601 date-time", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
createdAt: { type: 'string', format: 'date-time' }
|
||||
},
|
||||
required: ['createdAt']
|
||||
};
|
||||
expect(res.getBody()).to.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: date - valid date", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
birthDate: { type: 'string', format: 'date' }
|
||||
},
|
||||
required: ['birthDate']
|
||||
};
|
||||
expect(res.getBody()).to.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: time - valid time", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
loginTime: { type: 'string', format: 'time' }
|
||||
},
|
||||
required: ['loginTime']
|
||||
};
|
||||
expect(res.getBody()).to.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: ipv4 - valid IPv4 address", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
ipv4: { type: 'string', format: 'ipv4' }
|
||||
},
|
||||
required: ['ipv4']
|
||||
};
|
||||
expect(res.getBody()).to.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: ipv6 - valid IPv6 address", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
ipv6: { type: 'string', format: 'ipv6' }
|
||||
},
|
||||
required: ['ipv6']
|
||||
};
|
||||
expect(res.getBody()).to.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: uuid - valid UUID", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', format: 'uuid' }
|
||||
},
|
||||
required: ['id']
|
||||
};
|
||||
expect(res.getBody()).to.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: byte - valid base64 string", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
encodedData: { type: 'string', format: 'byte' }
|
||||
},
|
||||
required: ['encodedData']
|
||||
};
|
||||
expect(res.getBody()).to.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: int32 - valid 32-bit integer", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
int32Val: { type: 'integer', format: 'int32' }
|
||||
},
|
||||
required: ['int32Val']
|
||||
};
|
||||
expect(res.getBody()).to.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: int64 - valid 64-bit integer", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
int64Val: { type: 'integer', format: 'int64' }
|
||||
},
|
||||
required: ['int64Val']
|
||||
};
|
||||
expect(res.getBody()).to.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: float - valid float", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
floatVal: { type: 'number', format: 'float' }
|
||||
},
|
||||
required: ['floatVal']
|
||||
};
|
||||
expect(res.getBody()).to.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: double - valid double", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
doubleVal: { type: 'number', format: 'double' }
|
||||
},
|
||||
required: ['doubleVal']
|
||||
};
|
||||
expect(res.getBody()).to.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: duration - valid ISO 8601 duration", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
duration: { type: 'string', format: 'duration' }
|
||||
},
|
||||
required: ['duration']
|
||||
};
|
||||
expect(res.getBody()).to.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: hostname - valid hostname", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hostname: { type: 'string', format: 'hostname' }
|
||||
},
|
||||
required: ['hostname']
|
||||
};
|
||||
expect(res.getBody()).to.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: regex - valid regex pattern", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
regexPattern: { type: 'string', format: 'regex' }
|
||||
},
|
||||
required: ['regexPattern']
|
||||
};
|
||||
expect(res.getBody()).to.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: json-pointer - valid JSON pointer", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
jsonPointer: { type: 'string', format: 'json-pointer' }
|
||||
},
|
||||
required: ['jsonPointer']
|
||||
};
|
||||
expect(res.getBody()).to.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: uri-reference - valid URI reference", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
uriRef: { type: 'string', format: 'uri-reference' }
|
||||
},
|
||||
required: ['uriRef']
|
||||
};
|
||||
expect(res.getBody()).to.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: uri-template - valid URI template", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
uriTemplate: { type: 'string', format: 'uri-template' }
|
||||
},
|
||||
required: ['uriTemplate']
|
||||
};
|
||||
expect(res.getBody()).to.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("Multiple formats in one schema", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
email: { type: 'string', format: 'email' },
|
||||
website: { type: 'string', format: 'uri' },
|
||||
createdAt: { type: 'string', format: 'date-time' },
|
||||
ipv4: { type: 'string', format: 'ipv4' },
|
||||
id: { type: 'string', format: 'uuid' },
|
||||
encodedData: { type: 'string', format: 'byte' },
|
||||
int32Val: { type: 'integer', format: 'int32' },
|
||||
floatVal: { type: 'number', format: 'float' },
|
||||
duration: { type: 'string', format: 'duration' },
|
||||
hostname: { type: 'string', format: 'hostname' }
|
||||
},
|
||||
required: ['email', 'website', 'createdAt', 'ipv4', 'id', 'encodedData', 'int32Val', 'floatVal', 'duration', 'hostname']
|
||||
};
|
||||
expect(res.getBody()).to.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
// --- ajv-formats: Failure validations ---
|
||||
|
||||
test("format: email - rejects non-email string", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', format: 'email' }
|
||||
},
|
||||
required: ['name']
|
||||
};
|
||||
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: uri - rejects non-URI string", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', format: 'uri' }
|
||||
},
|
||||
required: ['name']
|
||||
};
|
||||
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: date-time - rejects plain date string", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
birthDate: { type: 'string', format: 'date-time' }
|
||||
},
|
||||
required: ['birthDate']
|
||||
};
|
||||
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: ipv4 - rejects non-IP string", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', format: 'ipv4' }
|
||||
},
|
||||
required: ['name']
|
||||
};
|
||||
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: uuid - rejects non-UUID string", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', format: 'uuid' }
|
||||
},
|
||||
required: ['name']
|
||||
};
|
||||
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: byte - rejects non-base64 string", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
email: { type: 'string', format: 'byte' }
|
||||
},
|
||||
required: ['email']
|
||||
};
|
||||
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: int32 - rejects value exceeding 32-bit range", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
int64Val: { type: 'integer', format: 'int32' }
|
||||
},
|
||||
required: ['int64Val']
|
||||
};
|
||||
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: float - rejects non-number field", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'number', format: 'float' }
|
||||
},
|
||||
required: ['name']
|
||||
};
|
||||
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: duration - rejects non-duration string", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', format: 'duration' }
|
||||
},
|
||||
required: ['name']
|
||||
};
|
||||
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: hostname - rejects invalid hostname", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
email: { type: 'string', format: 'hostname' }
|
||||
},
|
||||
required: ['email']
|
||||
};
|
||||
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: json-pointer - rejects non-pointer string", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', format: 'json-pointer' }
|
||||
},
|
||||
required: ['name']
|
||||
};
|
||||
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: date - rejects non-date string", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', format: 'date' }
|
||||
},
|
||||
required: ['name']
|
||||
};
|
||||
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: time - rejects non-time string", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', format: 'time' }
|
||||
},
|
||||
required: ['name']
|
||||
};
|
||||
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: ipv6 - rejects non-IPv6 string", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', format: 'ipv6' }
|
||||
},
|
||||
required: ['name']
|
||||
};
|
||||
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: int64 - rejects non-integer field", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'integer', format: 'int64' }
|
||||
},
|
||||
required: ['name']
|
||||
};
|
||||
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: double - rejects non-number field", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'number', format: 'double' }
|
||||
},
|
||||
required: ['name']
|
||||
};
|
||||
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: regex - rejects invalid regex pattern", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
invalidRegex: { type: 'string', format: 'regex' }
|
||||
},
|
||||
required: ['invalidRegex']
|
||||
};
|
||||
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: uri-reference - rejects invalid URI reference string", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
invalidRegex: { type: 'string', format: 'uri-reference' }
|
||||
},
|
||||
required: ['invalidRegex']
|
||||
};
|
||||
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
test("format: uri-template - rejects invalid URI template string", function() {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
invalidUriTemplate: { type: 'string', format: 'uri-template' }
|
||||
},
|
||||
required: ['invalidUriTemplate']
|
||||
};
|
||||
expect(res.getBody()).to.not.have.jsonSchema(schema);
|
||||
});
|
||||
|
||||
// --- Failure validations ---
|
||||
|
||||
test("Type mismatch - schema expects array, response is object", function() {
|
||||
|
||||
Reference in New Issue
Block a user