@superhero/oas
Version:
OpenAPI Specification (OAS) router
778 lines (674 loc) • 30.3 kB
JavaScript
import Schemas from '@superhero/oas/components/schemas'
import assert from 'node:assert'
import { suite, test } from 'node:test'
suite('@superhero/oas/schemas', () =>
{
const schemas = new Schemas()
suite('Supported attributes', () =>
{
test('type:boolean', async (sub) =>
{
const component = { type: 'boolean' }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = false
const conformed = schemas.conform(component, instance)
assert.strictEqual(conformed, instance)
await sub.test('nullable enum', () =>
{
const component = { type: 'boolean', nullable: true, enum: [true, null] }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = null
const conformed = schemas.conform(component, instance)
assert.strictEqual(conformed, instance)
})
await sub.test('throws if invalid enum type', () =>
{
const component = { type: 'boolean', enum: [1,2] }
assert.throws(() => schemas.validateComponent(component))
})
await sub.test('casts strings that can be interpreted as a boolean value to boolean', () =>
{
// true
assert.strictEqual(schemas.conform(component, 'true'), true)
assert.strictEqual(schemas.conform(component, 'on'), true)
assert.strictEqual(schemas.conform(component, '1'), true)
assert.strictEqual(schemas.conform(component, 1), true)
// false
assert.strictEqual(schemas.conform(component, 'FALSE'), false)
assert.strictEqual(schemas.conform(component, 'OFF'), false)
assert.strictEqual(schemas.conform(component, '0'), false)
assert.strictEqual(schemas.conform(component, 0), false)
})
await sub.test('throws if invalid', () =>
{
assert.throws(() => schemas.conform(component, 'invalid'))
})
})
test('type:integer', async (sub) =>
{
const component = { type: 'integer' }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = 123
const conformed = schemas.conform(component, instance)
assert.strictEqual(conformed, instance)
await sub.test('nullable enum', () =>
{
const component = { type: 'integer', nullable: true, enum: [1, 2, null] }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = null
const conformed = schemas.conform(component, instance)
assert.strictEqual(conformed, instance)
})
await sub.test('minimum', () =>
{
const component = { type: 'integer', minimum: 2 }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.throws(() => schemas.conform(component, 1))
})
await sub.test('maximum', () =>
{
const component = { type: 'integer', maximum: 2 }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.throws(() => schemas.conform(component, 3))
})
await sub.test('exclusiveMinimum', () =>
{
const component = { type: 'integer', minimum: 2, exclusiveMinimum: true }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.throws(() => schemas.conform(component, 2))
})
await sub.test('exclusiveMaximum', () =>
{
const component = { type: 'integer', maximum: 2, exclusiveMaximum: true }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.throws(() => schemas.conform(component, 2))
})
await sub.test('multipleOf', () =>
{
const component = { type: 'integer', multipleOf: 2 }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.doesNotThrow(() => schemas.conform(component, 4))
assert.throws(() => schemas.conform(component, 3))
})
await sub.test('format int32', () =>
{
const component = { type: 'integer', format: 'int32' }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.doesNotThrow(() => schemas.conform(component, 2147483647))
assert.throws(() => schemas.conform(component, 2147483648))
})
await sub.test('format int64', () =>
{
const component = { type: 'integer', format: 'int64' }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.doesNotThrow(() => schemas.conform(component, 9007199254740991))
assert.throws(() => schemas.conform(component, 9007199254740992))
})
await sub.test('throws if invalid format', () =>
{
const component = { type: 'integer', format: 'invalid' }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.throws(() => schemas.conform(component, 123))
})
await sub.test('throws if invalid enum type', () =>
{
const component = { type: 'integer', enum: ['foo', 'bar'] }
assert.throws(() => schemas.validateComponent(component))
})
await sub.test('throws if a decimal', () =>
{
assert.throws(() => schemas.conform(component, 123.45))
})
})
test('type:number', async (sub) =>
{
const component = { type: 'number' }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = 123.45
const conformed = schemas.conform(component, instance)
assert.strictEqual(conformed, instance)
await sub.test('nullable enum', () =>
{
const component = { type: 'number', nullable: true, enum: [1, 2, null] }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = null
const conformed = schemas.conform(component, instance)
assert.strictEqual(conformed, instance)
})
await sub.test('format float', () =>
{
const component = { type: 'number', format: 'float' }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.doesNotThrow(() => schemas.conform(component, 123.45))
})
await sub.test('format double', () =>
{
const component = { type: 'number', format: 'double' }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.doesNotThrow(() => schemas.conform(component, 123.45))
})
await sub.test('throws if invalid enum type', () =>
{
const component = { type: 'number', enum: ['foo', 'bar'] }
assert.throws(() => schemas.validateComponent(component))
})
await sub.test('casts strings that can be interpreted as a number value to number', () =>
{
assert.strictEqual(schemas.conform(component, '123.456'), 123.456)
})
})
test('type:string', async (sub) =>
{
const component = { type: 'string' }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = 'foobar'
const conformed = schemas.conform(component, instance)
assert.strictEqual(conformed, instance)
await sub.test('nullable enum', () =>
{
const component = { type: 'string', nullable: true, enum: ['foo', 'bar', null] }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = null
const conformed = schemas.conform(component, instance)
assert.strictEqual(conformed, instance)
})
await sub.test('minLength', () =>
{
const component = { type: 'string', minLength: 4 }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.throws(() => schemas.conform(component, 'foo'))
})
await sub.test('maxLength', () =>
{
const component = { type: 'string', maxLength: 4 }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.throws(() => schemas.conform(component, 'foobar'))
})
await sub.test('pattern', () =>
{
const component = { type: 'string', pattern: '^foo' }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.doesNotThrow(() => schemas.conform(component, 'foobar'))
assert.throws(() => schemas.conform(component, 'barfoo'))
})
await sub.test('format date', () =>
{
const component = { type: 'string', format: 'date' }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.doesNotThrow(() => schemas.conform(component, '2021-01-01'))
assert.throws(() => schemas.conform(component, '2021-13-01'))
})
await sub.test('format time', () =>
{
const component = { type: 'string', format: 'time' }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.doesNotThrow(() => schemas.conform(component, '00:00:00'))
assert.throws(() => schemas.conform(component, '00:00:60'))
})
await sub.test('format datetime', () =>
{
const component = { type: 'string', format: 'date-time' }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.doesNotThrow(() => schemas.conform(component, '2021-01-01T00:00:00Z'))
assert.throws(() => schemas.conform(component, 'invalid'))
})
await sub.test('format base64', () =>
{
const component = { type: 'string', format: 'base64' }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.doesNotThrow(() => schemas.conform(component, 'Zm9vYmFy'))
assert.throws(() => schemas.conform(component, '~'))
})
await sub.test('format email', () =>
{
const component = { type: 'string', format: 'email' }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.doesNotThrow(() => schemas.conform(component, 'example@example.com'))
assert.throws(() => schemas.conform(component, 'invalid'))
})
await sub.test('format ipv4', () =>
{
const component = { type: 'string', format: 'ipv4' }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.doesNotThrow(() => schemas.conform(component, '127.0.0.1'))
assert.doesNotThrow(() => schemas.conform(component, '0.0.0.0'))
assert.doesNotThrow(() => schemas.conform(component, '255.255.255.255'))
assert.throws(() => schemas.conform(component, 'invalid'))
assert.throws(() => schemas.conform(component, '255.255.255.255.255'))
assert.throws(() => schemas.conform(component, '355.255.255.255'))
assert.throws(() => schemas.conform(component, '255.265.255.255'))
assert.throws(() => schemas.conform(component, '255.255.256.255'))
assert.throws(() => schemas.conform(component, '255.255.255.256'))
assert.throws(() => schemas.conform(component, '255.255.255.a'))
assert.throws(() => schemas.conform(component, '255.255.255.-1'))
assert.throws(() => schemas.conform(component, '...'))
})
await sub.test('format ipv6', () =>
{
const component = { type: 'string', format: 'ipv6' }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.doesNotThrow(() => schemas.conform(component, '2001:0db8:85a3:0000:0000:8a2e:0370:7334'), 'Fully expanded IPv6 address')
assert.doesNotThrow(() => schemas.conform(component, '2001:db8:85a3:0:0:8a2e:370:7334'), 'Shortened IPv6 address, with zero compression')
assert.doesNotThrow(() => schemas.conform(component, '2001:db8:85a3::8a2e:370:7334'), 'Compressed IPv6 address, :: replaces consecutive zeros')
assert.doesNotThrow(() => schemas.conform(component, '2001:db8::1'), 'Compressed IPv6 address, :: 2')
assert.doesNotThrow(() => schemas.conform(component, '2001:db8::', 'Compressed IPv6 address, :: 3'))
assert.doesNotThrow(() => schemas.conform(component, '2001::', 'Compressed IPv6 address, :: 4'))
assert.doesNotThrow(() => schemas.conform(component, '2001::1', 'Compressed IPv6 address with one trailing value'))
assert.doesNotThrow(() => schemas.conform(component, '::1', 'Compressed IPv6 address representing the loopback address'))
assert.doesNotThrow(() => schemas.conform(component, '::', 'Compressed IPv6 address representing all zeroes'))
assert.doesNotThrow(() => schemas.conform(component, '::ffff:192.168.1.1', 'IPv4-mapped IPv6 address'))
assert.throws(() => schemas.conform(component, 'invalid', 'Invalid IPv6 address'))
assert.throws(() => schemas.conform(component, '2001:::1', 'Triple colons'))
assert.throws(() => schemas.conform(component, '2001:db8:85a3:xyz:0:8a2e:370:7334', 'Non-hex chars'))
assert.throws(() => schemas.conform(component, '2001:db8:85a3:0:0:8a2e:370:7334:1234', 'Too many groups'))
})
await sub.test('url', () =>
{
const component = { type: 'string', format: 'url' }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.doesNotThrow(() => schemas.conform(component, 'https://example.com'))
assert.doesNotThrow(() => schemas.conform(component, 'http://example.com'))
assert.doesNotThrow(() => schemas.conform(component, 'ftps://example.com'))
assert.doesNotThrow(() => schemas.conform(component, 'ftp://example.com'))
assert.doesNotThrow(() => schemas.conform(component, 'ws://example.com'))
assert.throws(() => schemas.conform(component, '://example.com'))
assert.throws(() => schemas.conform(component, '//example.com'))
assert.throws(() => schemas.conform(component, 'example.com'))
assert.throws(() => schemas.conform(component, 'example'))
})
await sub.test('format uuid', () =>
{
const component = { type: 'string', format: 'uuid' }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.doesNotThrow(() => schemas.conform(component, '550e8400-e29b-41d4-a716-446655440000'))
assert.throws(() => schemas.conform(component, 'invalid'))
})
await sub.test('throws if invalid enum type', () =>
{
const component = { type: 'string', enum: [1, 2] }
assert.throws(() => schemas.validateComponent(component))
})
})
test('type:null', async (sub) =>
{
const component = { type: 'null' }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = ''
const conformed = schemas.conform(component, instance)
assert.strictEqual(conformed, null)
await sub.test('throws if not null', () =>
{
assert.throws(() => schemas.conform(component, 'foobar'))
})
await sub.test('throws if value is null and type is not null', () =>
{
const component = { type: 'string' }
assert.throws(() => schemas.conform(component, null))
})
})
test('type:undefined', () =>
{
const component = {}
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = 'foobar'
const conformed = schemas.conform(component, instance)
assert.strictEqual(conformed, instance)
})
test('type:array', async (sub) =>
{
const component = { type: 'array' }
assert.throws(() => schemas.validateComponent(component))
assert.throws(() => schemas.conform(component, [1,2,3]))
await sub.test('throws if invalid type', () =>
{
const component = { type: 'array', items: { type: 'integer' } }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.throws(() => schemas.conform(component, 'foobar'))
})
await sub.test('items', () =>
{
const component = { type: 'array', items: { type: 'integer' } }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = [1,2,3]
const conformed = schemas.conform(component, instance)
assert.deepStrictEqual(conformed, instance)
})
await sub.test('additionalItems', () =>
{
const component = { type: 'array', items: { type: 'integer' }, additionalItems: false }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.throws(() => schemas.conform(component, [1,2]))
})
await sub.test('minItems', () =>
{
const component = { type: 'array', items: { type: 'integer' }, minItems: 2 }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.throws(() => schemas.conform(component, [1]))
})
await sub.test('maxItems', () =>
{
const component = { type: 'array', items: { type: 'integer' }, maxItems: 2 }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.throws(() => schemas.conform(component, [1,2,3]))
})
await sub.test('uniqueItems', () =>
{
const component = { type: 'array', items: { type: 'integer' }, uniqueItems: true }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.doesNotThrow(() => schemas.conform(component, [1,2,3]))
assert.deepStrictEqual(schemas.conform(component, [1,1,2]), [1,2])
})
await sub.test('enum', () =>
{
const component = { type: 'array', items: { type: 'integer' }, enum: [[1,2], [3,4]] }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = [1,2]
const conformed = schemas.conform(component, instance)
assert.deepStrictEqual(conformed, instance)
})
await sub.test('throws if invalid enum type', () =>
{
const component = { type: 'array', items: { type: 'integer' }, enum: [1, 2] }
assert.throws(() => schemas.validateComponent(component))
})
await sub.test('nullable enum', () =>
{
const component = { type: 'array', items: { type: 'integer' }, nullable: true, enum: [[1,2], [3,4], null] }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = null
const conformed = schemas.conform(component, instance)
assert.strictEqual(conformed, instance)
})
await sub.test('nullable items', () =>
{
const component = { type: 'array', items: { type: 'integer', nullable: true } }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = [1,null,3]
const conformed = schemas.conform(component, instance)
assert.deepStrictEqual(conformed, instance)
})
await sub.test('nullable enum items', () =>
{
const component = { type: 'array', items: { type: 'integer', nullable: true }, enum: [[1,null], [2,3]] }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = [1,null]
const conformed = schemas.conform(component, instance)
assert.deepStrictEqual(conformed, instance)
})
})
test('type:object', async (sub) =>
{
const component =
{ type: 'object', properties: { foo: { type: 'object',
properties: { bar: { type: 'object',
properties: { baz: { type: 'string' }}}}}}}
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = { foo: { bar: { baz: 'quz' }}}
const conformed = schemas.conform(component, instance)
assert.deepStrictEqual(conformed, instance)
await sub.test('throws if invalid type', () =>
{
const component = { type: 'object' }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.throws(() => schemas.conform(component, 'foobar'))
})
await sub.test('additionalProperties', () =>
{
const component = { type: 'object', additionalProperties: true }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = { foo: 'bar' }
const conformed = schemas.conform(component, instance)
assert.deepStrictEqual(conformed, instance)
component.additionalProperties = false
assert.deepStrictEqual(schemas.conform(component, instance), {})
})
await sub.test('minProperties', () =>
{
const component = { type: 'object', minProperties: 2, additionalProperties: true }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.throws(() => schemas.conform(component, { foo: 'bar' }))
})
await sub.test('maxProperties', () =>
{
const component = { type: 'object', maxProperties: 2, additionalProperties: true }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.throws(() => schemas.conform(component, { foo: 'bar', bar: 'baz', baz: 'qux' }))
})
await sub.test('propertyNames pattern', () =>
{
const component = { type: 'object', propertyNames: { pattern: '^foo' }, additionalProperties: true }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.doesNotThrow(() => schemas.conform(component, { foo: 'bar' }))
assert.throws(() => schemas.conform(component, { bar: 'foo' }))
})
await sub.test('nullable', () =>
{
const component = { type: 'object', nullable: true }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = null
const conformed = schemas.conform(component, instance)
assert.strictEqual(conformed, instance)
})
await sub.test('enum', () =>
{
const component = { type: 'object', properties: { foo: { type: 'string' }}, enum: [{ foo: 'bar' }] }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = { foo: 'bar' }
const conformed = schemas.conform(component, instance)
assert.deepStrictEqual(conformed, instance)
})
await sub.test('nullable enum', () =>
{
const component = { type: 'object', properties: { foo: { type: 'string' }}, nullable: true, enum: [{ foo: 'bar' }, null] }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = null
const conformed = schemas.conform(component, instance)
assert.strictEqual(conformed, instance)
})
await sub.test('throws if invalid enum type', () =>
{
const component = { type: 'object', properties: { foo: { type: 'string' }}, enum: ['foo', 'bar'] }
assert.throws(() => schemas.validateComponent(component))
})
})
test('type:invalid throws', () =>
{
const component = { type: 'invalid' }
assert.throws(() => schemas.validateComponent(component))
assert.throws(() => schemas.conform(component, 'foobar'))
})
test('readOnly', async (sub) =>
{
await sub.test('when is reading', () =>
{
const component = { type: 'string', readOnly: true }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = 'foobar'
const conformed = schemas.conform(component, instance, false)
assert.strictEqual(conformed, instance)
})
await sub.test('when is writing', () =>
{
const component = { type: 'string', readOnly: true }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = 'foobar'
const conformed = schemas.conform(component, instance, true)
assert.strictEqual(conformed, undefined)
})
})
test('writeOnly', async (sub) =>
{
await sub.test('when is reading', () =>
{
const component = { type: 'string', writeOnly: true }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = 'foobar'
const conformed = schemas.conform(component, instance, false)
assert.strictEqual(conformed, undefined)
})
await sub.test('when is writing', () =>
{
const component = { type: 'string', writeOnly: true }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = 'foobar'
const conformed = schemas.conform(component, instance, true)
assert.strictEqual(conformed, instance)
})
})
test('default', async (sub) =>
{
await sub.test('when no value', () =>
{
const component = { type: 'string', default: 'foobar' }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = undefined
const conformed = schemas.conform(component, instance)
assert.strictEqual(conformed, component.default)
})
await sub.test('when value', () =>
{
const component = { type: 'string', default: 'foobar' }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = 'quz'
const conformed = schemas.conform(component, instance)
assert.strictEqual(conformed, instance)
})
})
test('if/then/else', async (sub) =>
{
const component =
{ if: { type: 'string' },
then: { enum: ['foo','bar'] },
else: { enum: [13,42] }}
assert.doesNotThrow(() => schemas.validateComponent(component))
await sub.test('then', () =>
{
const instance = 'foo'
const conformed = schemas.conform(component, instance)
assert.strictEqual(conformed, instance)
})
await sub.test('else', () =>
{
const instance = 42
const conformed = schemas.conform(component, instance)
assert.strictEqual(conformed, instance)
})
await sub.test('throws if invalid', () =>
{
const instance = 'woops'
assert.throws(() => schemas.conform(component, instance))
})
})
test('not', () =>
{
const component = { not: { type: 'string' }}
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = 123
const conformed = schemas.conform(component, instance)
assert.strictEqual(conformed, instance)
assert.throws(() => schemas.conform(component, 'foobar'))
})
test('allOf', async (sub) =>
{
const component =
{ allOf:
[ { type: 'object', properties: { foo: { type: 'string' }}},
{ type: 'object', properties: { bar: { type: 'string' }}, required: [ 'bar' ] } ] }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = { foo: 'foo', bar: 'bar' }
const conformed = schemas.conform(component, instance)
assert.deepStrictEqual(conformed, instance)
await sub.test('result only what is expected', () =>
{
const instance = { foo: 'foo', bar: 'bar', baz: 'baz' }
const conformed = schemas.conform(component, instance)
assert.deepStrictEqual(conformed, { foo: 'foo', bar: 'bar' })
})
await sub.test('throws if all are not valid', () =>
{
const instance = { foo: 'foo' }
assert.throws(() => schemas.conform(component, instance))
})
})
test('anyOf', async (sub) =>
{
const component =
{ anyOf:
[ { type: 'string' },
{ type: 'integer' } ] }
assert.doesNotThrow(() => schemas.validateComponent(component))
await sub.test('conforms to valid schema', () =>
{
for(const instance of [ 'foo', 123 ])
{
const conformed = schemas.conform(component, instance)
assert.strictEqual(conformed, instance)
}
})
await sub.test('throws if none is valid', () =>
{
assert.throws(() => schemas.conform(component, { foo: 'bar' }))
})
})
test('oneOf', async (sub) =>
{
const component =
{ oneOf:
[ { type: 'string' },
{ type: 'integer' } ] }
assert.doesNotThrow(() => schemas.validateComponent(component))
await sub.test('conforms to valid schema', () =>
{
for(const instance of [ 'foo', 123 ])
{
const conformed = schemas.conform(component, instance)
assert.strictEqual(conformed, instance)
}
})
await sub.test('throws if none is valid', () =>
{
assert.throws(() => schemas.conform(component, { foo: 'bar' }))
})
await sub.test('throws if more than one is valid', () =>
{
const component =
{ oneOf:
[ { type: 'string' },
{ type: 'string' } ] }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.throws(() => schemas.conform(component, 'foobar'))
})
})
test('const', async () =>
{
const component = { const: 'foo' }
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = 'foo'
const conformed = schemas.conform(component, instance)
assert.strictEqual(conformed, instance)
assert.throws(() => schemas.conform(component, 'bar'))
})
test('deep const', async () =>
{
const component = { const: { foo: 'foo' }}
assert.doesNotThrow(() => schemas.validateComponent(component))
const instance = { foo: 'foo' }
const conformed = schemas.conform(component, instance)
assert.deepStrictEqual(conformed, instance)
assert.throws(() => schemas.conform(component, { foo: 'bar' }))
})
test('throws on invalid $ref', () =>
{
const component = { '$ref': '#/components/invalid/' }
assert.doesNotThrow(() => schemas.validateComponent(component))
assert.throws(
() => schemas.conform(component, 'foobar'),
{ code: 'E_OAS_INVALID_SPECIFICATION' })
})
test('throws on invalid schema', () =>
{
assert.throws(() => schemas.validateComponent({ foo: 'bar' }))
assert.throws(() => schemas.validateComponent({ type: 'object', items: {}}))
})
})
})