ajv/spec/issues.spec.js

527 lines
13 KiB
JavaScript

'use strict';
var Ajv = require('./ajv')
, should = require('./chai').should();
describe('issue #8: schema with shared references', function() {
it('should be supported by addSchema', spec('addSchema'));
it('should be supported by compile', spec('compile'));
function spec(method) {
return function() {
var ajv = new Ajv;
var propertySchema = {
type: 'string',
maxLength: 4
};
var schema = {
id: 'obj.json#',
type: 'object',
properties: {
foo: propertySchema,
bar: propertySchema
}
};
ajv[method](schema);
var result = ajv.validate('obj.json#', { foo: 'abc', bar: 'def' });
result .should.equal(true);
result = ajv.validate('obj.json#', { foo: 'abcde', bar: 'fghg' });
result .should.equal(false);
ajv.errors .should.have.length(1);
};
}
});
describe('issue #50: references with "definitions"', function () {
it('should be supported by addSchema', spec('addSchema'));
it('should be supported by compile', spec('addSchema'));
function spec(method) {
return function() {
var result;
var ajv = new Ajv;
ajv[method]({
id: 'http://example.com/test/person.json#',
definitions: {
name: { type: 'string' }
},
type: 'object',
properties: {
name: { $ref: '#/definitions/name'}
}
});
ajv[method]({
id: 'http://example.com/test/employee.json#',
type: 'object',
properties: {
person: { $ref: '/test/person.json#' },
role: { type: 'string' }
}
});
result = ajv.validate('http://example.com/test/employee.json#', {
person: {
name: 'Alice'
},
role: 'Programmer'
});
result. should.equal(true);
should.equal(ajv.errors, null);
};
}
});
describe('issue #182, NaN validation', function() {
it('should not pass minimum/maximum validation', function() {
testNaN({ minimum: 1 }, false);
testNaN({ maximum: 1 }, false);
});
it('should pass type: number validation', function() {
testNaN({ type: 'number' }, true);
});
it('should not pass type: integer validation', function() {
testNaN({ type: 'integer' }, false);
});
function testNaN(schema, NaNisValid) {
var ajv = new Ajv;
var validate = ajv.compile(schema);
validate(NaN) .should.equal(NaNisValid);
}
});
describe('issue #204, options schemas and $data used together', function() {
it('should use v5 metaschemas by default', function() {
var ajv = new Ajv({
schemas: [{id: 'str', type: 'string'}],
$data: true
});
var schema = { const: 42 };
var validate = ajv.compile(schema);
validate(42) .should.equal(true);
validate(43) .should.equal(false);
ajv.validate('str', 'foo') .should.equal(true);
ajv.validate('str', 42) .should.equal(false);
});
});
describe('issue #181, custom keyword is not validated in allErrors mode if there were previous error', function() {
it('should validate custom keyword that doesn\'t create errors', function() {
testCustomKeywordErrors({
type:'object',
errors: true,
validate: function v(/* value */) {
return false;
}
});
});
it('should validate custom keyword that creates errors', function() {
testCustomKeywordErrors({
type:'object',
errors: true,
validate: function v(/* value */) {
v.errors = v.errors || [];
v.errors.push({
keyword: 'alwaysFails',
message: 'alwaysFails error',
params: {
keyword: 'alwaysFails'
}
});
return false;
}
});
});
function testCustomKeywordErrors(def) {
var ajv = new Ajv({ allErrors: true });
ajv.addKeyword('alwaysFails', def);
var schema = {
required: ['foo'],
alwaysFails: true
};
var validate = ajv.compile(schema);
validate({ foo: 1 }) .should.equal(false);
validate.errors .should.have.length(1);
validate.errors[0].keyword .should.equal('alwaysFails');
validate({}) .should.equal(false);
validate.errors .should.have.length(2);
validate.errors[0].keyword .should.equal('required');
validate.errors[1].keyword .should.equal('alwaysFails');
}
});
describe('issue #210, mutual recursive $refs that are schema fragments', function() {
it('should compile and validate schema when one ref is fragment', function() {
var ajv = new Ajv;
ajv.addSchema({
"id" : "foo",
"definitions": {
"bar": {
"properties": {
"baz": {
"anyOf": [
{ "enum": [42] },
{ "$ref": "boo" }
]
}
}
}
}
});
ajv.addSchema({
"id" : "boo",
"type": "object",
"required": ["quux"],
"properties": {
"quux": { "$ref": "foo#/definitions/bar" }
}
});
var validate = ajv.compile({ "$ref": "foo#/definitions/bar" });
validate({ baz: { quux: { baz: 42 } } }) .should.equal(true);
validate({ baz: { quux: { baz: "foo" } } }) .should.equal(false);
});
it('should compile and validate schema when both refs are fragments', function() {
var ajv = new Ajv;
ajv.addSchema({
"id" : "foo",
"definitions": {
"bar": {
"properties": {
"baz": {
"anyOf": [
{ "enum": [42] },
{ "$ref": "boo#/definitions/buu" }
]
}
}
}
}
});
ajv.addSchema({
"id" : "boo",
"definitions": {
"buu": {
"type": "object",
"required": ["quux"],
"properties": {
"quux": { "$ref": "foo#/definitions/bar" }
}
}
}
});
var validate = ajv.compile({ "$ref": "foo#/definitions/bar" });
validate({ baz: { quux: { baz: 42 } } }) .should.equal(true);
validate({ baz: { quux: { baz: "foo" } } }) .should.equal(false);
});
});
describe('issue #240, mutually recursive fragment refs reference a common schema', function() {
var apiSchema = {
$schema: 'http://json-schema.org/draft-06/schema#',
id: 'schema://api.schema#',
resource: {
id: '#resource',
properties: {
id: { type: 'string' }
}
},
resourceIdentifier: {
id: '#resource_identifier',
properties: {
id: { type: 'string' },
type: { type: 'string' }
}
}
};
var domainSchema = {
$schema: 'http://json-schema.org/draft-06/schema#',
id: 'schema://domain.schema#',
properties: {
data: {
oneOf: [
{ $ref: 'schema://library.schema#resource_identifier' },
{ $ref: 'schema://catalog_item.schema#resource_identifier' },
]
}
}
};
it('should compile and validate schema when one ref is fragment', function() {
var ajv = new Ajv;
var librarySchema = {
$schema: 'http://json-schema.org/draft-06/schema#',
id: 'schema://library.schema#',
properties: {
name: { type: 'string' },
links: {
properties: {
catalogItems: {
type: 'array',
items: { $ref: 'schema://catalog_item_resource_identifier.schema#' }
}
}
}
},
definitions: {
resource_identifier: {
id: '#resource_identifier',
allOf: [
{
properties: {
type: {
type: 'string',
'enum': ['Library']
}
}
},
{ $ref: 'schema://api.schema#resource_identifier' }
]
}
}
};
var catalogItemSchema = {
$schema: 'http://json-schema.org/draft-06/schema#',
id: 'schema://catalog_item.schema#',
properties: {
name: { type: 'string' },
links: {
properties: {
library: { $ref: 'schema://library.schema#resource_identifier' }
}
}
},
definitions: {
resource_identifier: {
id: '#resource_identifier',
allOf: [
{
properties: {
type: {
type: 'string',
'enum': ['CatalogItem']
}
}
},
{ $ref: 'schema://api.schema#resource_identifier' }
]
}
}
};
var catalogItemResourceIdentifierSchema = {
$schema: 'http://json-schema.org/draft-06/schema#',
id: 'schema://catalog_item_resource_identifier.schema#',
allOf: [
{
properties: {
type: {
type: 'string',
enum: ['CatalogItem']
}
}
},
{
$ref: 'schema://api.schema#resource_identifier'
}
]
};
ajv.addSchema(librarySchema);
ajv.addSchema(catalogItemSchema);
ajv.addSchema(catalogItemResourceIdentifierSchema);
ajv.addSchema(apiSchema);
var validate = ajv.compile(domainSchema);
testSchema(validate);
});
it('should compile and validate schema when both refs are fragments', function() {
var ajv = new Ajv;
var librarySchema = {
$schema: 'http://json-schema.org/draft-06/schema#',
id: 'schema://library.schema#',
properties: {
name: { type: 'string' },
links: {
properties: {
catalogItems: {
type: 'array',
items: { $ref: 'schema://catalog_item.schema#resource_identifier' }
}
}
}
},
definitions: {
resource_identifier: {
id: '#resource_identifier',
allOf: [
{
properties: {
type: {
type: 'string',
'enum': ['Library']
}
}
},
{ $ref: 'schema://api.schema#resource_identifier' }
]
}
}
};
var catalogItemSchema = {
$schema: 'http://json-schema.org/draft-06/schema#',
id: 'schema://catalog_item.schema#',
properties: {
name: { type: 'string' },
links: {
properties: {
library: { $ref: 'schema://library.schema#resource_identifier' }
}
}
},
definitions: {
resource_identifier: {
id: '#resource_identifier',
allOf: [
{
properties: {
type: {
type: 'string',
'enum': ['CatalogItem']
}
}
},
{ $ref: 'schema://api.schema#resource_identifier' }
]
}
}
};
ajv.addSchema(librarySchema);
ajv.addSchema(catalogItemSchema);
ajv.addSchema(apiSchema);
var validate = ajv.compile(domainSchema);
testSchema(validate);
});
function testSchema(validate) {
validate({ data: { type: 'Library', id: '123' } }) .should.equal(true);
validate({ data: { type: 'Library', id: 123 } }) .should.equal(false);
validate({ data: { type: 'CatalogItem', id: '123' } }) .should.equal(true);
validate({ data: { type: 'CatalogItem', id: 123 } }) .should.equal(false);
validate({ data: { type: 'Foo', id: '123' } }) .should.equal(false);
}
});
describe('issue #259, support validating [meta-]schemas against themselves', function() {
it('should add schema before validation if "id" is the same as "$schema"', function() {
var ajv = new Ajv;
ajv.addMetaSchema(require('../lib/refs/json-schema-draft-04.json'));
var hyperSchema = require('./remotes/hyper-schema.json');
ajv.addMetaSchema(hyperSchema);
});
});
describe.skip('issue #273, schemaPath in error in referenced schema', function() {
it('should have canonic reference with hash after file name', function() {
test(new Ajv);
test(new Ajv({inlineRefs: false}));
function test(ajv) {
var schema = {
"properties": {
"a": { "$ref": "int" }
}
};
var referencedSchema = {
"id": "int",
"type": "integer"
};
ajv.addSchema(referencedSchema);
var validate = ajv.compile(schema);
validate({ "a": "foo" }) .should.equal(false);
validate.errors[0].schemaPath .should.equal('int#/type');
}
});
});
describe('issue #342, support uniqueItems with some non-JSON objects', function() {
var validate;
before(function() {
var ajv = new Ajv;
validate = ajv.compile({ uniqueItems: true });
});
it('should allow different RegExps', function() {
validate([/foo/, /bar/]) .should.equal(true);
validate([/foo/ig, /foo/gi]) .should.equal(false);
validate([/foo/, {}]) .should.equal(true);
});
it('should allow different Dates', function() {
validate([new Date('2016-11-11'), new Date('2016-11-12')]) .should.equal(true);
validate([new Date('2016-11-11'), new Date('2016-11-11')]) .should.equal(false);
validate([new Date('2016-11-11'), {}]) .should.equal(true);
});
it('should allow undefined properties', function() {
validate([{}, {foo: undefined}]) .should.equal(true);
validate([{foo: undefined}, {}]) .should.equal(true);
validate([{foo: undefined}, {bar: undefined}]) .should.equal(true);
validate([{foo: undefined}, {foo: undefined}]) .should.equal(false);
});
});