json-schema-library
Version:
Customizable and hackable json-validator and json-schema utilities for traversal, data generation and validation
321 lines (317 loc) • 14.4 kB
text/typescript
import { compileSchema } from "./compileSchema";
import { strict as assert } from "assert";
import { extendDraft } from "./Draft";
import { draft2020 } from "./draft2020";
import { propertyDependenciesKeyword } from "./keywords/propertyDependencies";
import { draft07 } from "./draft07";
const withAdditionalKeywords = {
drafts: [
extendDraft(draft2020, {
keywords: [propertyDependenciesKeyword]
})
]
};
describe("validateSchema", () => {
it("should error if `$defs` is not an object", () => {
const { schemaErrors } = compileSchema({ $defs: true });
assert.equal(schemaErrors?.length, 1);
});
it("should throw an error if schema is invalid and option 'throwOnInvalidSchema = true'", () => {
assert.throws(() => {
compileSchema({ $defs: true }, { throwOnInvalidSchema: true });
});
});
it("should error for missing `$ref` target in $defs", () => {
const { schemaErrors } = compileSchema({
type: "object",
properties: {
invalid: { $ref: "#/$defs/invalid" }
}
});
assert.equal(schemaErrors?.length, 1);
assert.equal(schemaErrors[0].data.pointer, "#/properties/invalid/$ref");
assert.equal(schemaErrors[0].data.value, "#/$defs/invalid");
});
it("should error if `additionalProperties` is not a valid JSON Schema", () => {
const { schemaErrors } = compileSchema({ additionalProperties: 999 });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `allOf` is not a an array", () => {
const { schemaErrors } = compileSchema({ allOf: {} });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `allOf schema` is not a valid JSON Schema", () => {
const { schemaErrors } = compileSchema({ allOf: [999] });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `anyOf` is not a an array", () => {
const { schemaErrors } = compileSchema({ anyOf: {} });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `anyOf schema` is not a valid JSON Schema", () => {
const { schemaErrors } = compileSchema({ anyOf: [999] });
assert.equal(schemaErrors?.length, 1);
});
// any const is valid: https://json-schema.org/draft/2020-12/json-schema-validation#name-const
it("should error if `contains` is not a valid JSON Schema", () => {
const { schemaErrors } = compileSchema({ contains: [] });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `dependencies` is not a an object", () => {
const { schemaErrors } = compileSchema({ dependencies: [] });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `dependentRequired` is not a an object", () => {
const { schemaErrors } = compileSchema({ dependentRequired: [] });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `dependentRequired` is not a an object with a list of strings", () => {
const { schemaErrors } = compileSchema({
dependentRequired: {
property: ["title", true]
}
});
assert.equal(schemaErrors?.length, 1);
});
it("should error if `dependentSchemas` is not a an object containing schemata", () => {
const { schemaErrors } = compileSchema({
dependentSchemas: {
valid: { type: "string" },
stillValid: true,
invalid: 999
}
});
assert.equal(schemaErrors?.length, 1);
assert.equal(schemaErrors[0].data.pointer, "#/dependentSchemas/invalid");
});
it("should error if `deprecated` is not a a boolean", () => {
const { schemaErrors } = compileSchema({ deprecated: {} });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `enum` is not an array", () => {
const { schemaErrors } = compileSchema({ type: "string", enum: true });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `exclusiveMaximum` is not a number", () => {
const { schemaErrors } = compileSchema({ exclusiveMaximum: true });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `exclusiveMinimum` is not a number", () => {
const { schemaErrors } = compileSchema({ exclusiveMinimum: true });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `format` is not a string", () => {
const { schemaErrors } = compileSchema({ format: {} });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `if` is not a valid JSON Schema", () => {
const { schemaErrors } = compileSchema({ if: 999, then: false, else: true });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `then` is not a valid JSON Schema", () => {
const { schemaErrors } = compileSchema({ if: {}, then: [], else: true });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `else` is not a valid JSON Schema", () => {
const { schemaErrors } = compileSchema({ if: {}, then: false, else: 999 });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `items` is not a valid JSON Schema", () => {
const { schemaErrors } = compileSchema({ items: [] });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `maximum` is not a number", () => {
const { schemaErrors } = compileSchema({ maximum: true });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `maxItems` is not a number", () => {
const { schemaErrors } = compileSchema({ maxItems: true });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `maxLength` is not a number", () => {
const { schemaErrors } = compileSchema({ maxLength: true });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `maxProperties` is not a number", () => {
const { schemaErrors } = compileSchema({ maxProperties: true });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `minimum` is not a number", () => {
const { schemaErrors } = compileSchema({ minimum: true });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `minItems` is not a number", () => {
const { schemaErrors } = compileSchema({ minItems: true });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `minLength` is not a number", () => {
const { schemaErrors } = compileSchema({ minLength: true });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `minProperties` is not a number", () => {
const { schemaErrors } = compileSchema({ minProperties: true });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `multipleOf` is not a number", () => {
const { schemaErrors } = compileSchema({ multipleOf: true });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `not` is not a JSON Schema", () => {
const { schemaErrors } = compileSchema({ not: [] });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `oneOf` is not a an array", () => {
const { schemaErrors } = compileSchema({ oneOf: {} });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `oneOf schema` is not a valid JSON Schema", () => {
const { schemaErrors } = compileSchema({ oneOf: [999] });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `pattern` is not a string", () => {
const { schemaErrors } = compileSchema({ type: "string", pattern: true });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `pattern` is an invalid regexp", () => {
const { schemaErrors } = compileSchema({ type: "string", pattern: "(" });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `properties` is not an object", () => {
const { schemaErrors } = compileSchema({ type: "object", properties: 999 });
assert.equal(schemaErrors?.length, 1);
});
it("should error if `properties[string]` is not a JSON Schema", () => {
const { schemaErrors } = compileSchema({
type: "object",
properties: {
valid: { type: "string" },
alsoValid: false,
invalid: 999
}
});
assert.equal(schemaErrors?.length, 1);
assert.equal(schemaErrors[0].data.pointer, "#/properties/invalid");
});
it("should error if `propertyDependencies` is not an object", () => {
const { schemaErrors } = compileSchema({ propertyDependencies: true }, withAdditionalKeywords);
assert.equal(schemaErrors?.length, 1);
});
it("should error if `propertyDependencies[string]` is not an object", () => {
const { schemaErrors } = compileSchema({ propertyDependencies: { invalid: true } }, withAdditionalKeywords);
assert.equal(schemaErrors?.length, 1);
});
it("should error if `propertyDependencies[string][string]` is not JSON Schema", () => {
const { schemaErrors } = compileSchema(
{ propertyDependencies: { valid: { invalid: 999 } } },
withAdditionalKeywords
);
assert.equal(schemaErrors?.length, 1);
});
it("should error if `propertyNames` is not a JSON Schema type", () => {
const { schemaErrors } = compileSchema({ propertyNames: "error" });
assert.equal(schemaErrors?.length, 1);
assert.equal(schemaErrors[0].data.pointer, "#/propertyNames");
});
it("should error if `required` is not a string[]", () => {
const { schemaErrors } = compileSchema({ type: "object", required: [123, "valid"] });
assert.equal(schemaErrors?.length, 1);
assert.equal(schemaErrors[0].data.pointer, "#/required");
});
it("should error if `type` is not a JSON Schema type", () => {
const { schemaErrors } = compileSchema({ type: "error" });
assert.equal(schemaErrors?.length, 1);
assert.equal(schemaErrors[0].data.pointer, "#/type");
});
it("should error if `type` is not a valid JSON Schema type format", () => {
const { schemaErrors } = compileSchema({ type: {} });
assert.equal(schemaErrors?.length, 1);
assert.equal(schemaErrors[0].data.pointer, "#/type");
});
it("should error if `type` is not a valid JSON Schema", () => {
const { schemaErrors } = compileSchema({ type: "error" });
assert.equal(schemaErrors?.length, 1);
assert.equal(schemaErrors[0].data.pointer, "#/type");
});
it("should error if `unevaluatedItems` is not a valid JSON Schema", () => {
const { schemaErrors } = compileSchema({ unevaluatedItems: [] });
assert.equal(schemaErrors?.length, 1);
assert.equal(schemaErrors[0].data.pointer, "#/unevaluatedItems");
});
it("should error if `unevaluatedProperties` is not a valid JSON Schema", () => {
const { schemaErrors } = compileSchema({ unevaluatedProperties: 999 });
assert.equal(schemaErrors?.length, 1);
assert.equal(schemaErrors[0].data.pointer, "#/unevaluatedProperties");
});
it("should error if `uniqueItems` is not a boolean", () => {
const { schemaErrors } = compileSchema({ uniqueItems: {} });
assert.equal(schemaErrors?.length, 1);
assert.equal(schemaErrors[0].data.pointer, "#/uniqueItems");
});
describe("annotations", () => {
it("should return unknown keywords as annotation", () => {
const { schemaAnnotations } = compileSchema({
properties: {
headline: {
options: {},
type: "string"
}
}
});
assert.equal(schemaAnnotations.length, 1);
assert.equal(schemaAnnotations[0].data.pointer, "#/properties/headline/options");
});
it("should not return unknown keywords starting with 'x-'", () => {
const { schemaAnnotations } = compileSchema({
properties: {
headline: {
"x-options": {},
type: "string"
}
}
});
assert.equal(schemaAnnotations.length, 0);
});
it("should not return valid annotation keywords", () => {
const { schemaAnnotations } = compileSchema({
type: "string",
title: "input",
description: "any string",
default: "hey"
});
assert.equal(schemaAnnotations.length, 0);
});
it("should return removed keywords from old drafts as annotation", () => {
const { schemaAnnotations } = compileSchema({
properties: {
headline: {
additionalItems: true
}
}
});
assert.equal(schemaAnnotations.length, 1);
assert.equal(schemaAnnotations[0].data.pointer, "#/properties/headline/additionalItems");
});
it("should return new keywords in old drafts as annotation", () => {
const { schemaAnnotations } = compileSchema(
{
properties: {
headline: {
prefixItems: []
}
}
},
{ drafts: [draft07] }
);
assert.equal(schemaAnnotations.length, 1);
assert.equal(schemaAnnotations[0].data.pointer, "#/properties/headline/prefixItems");
});
it("should return unsupported formats as annotation", () => {
const { schemaAnnotations } = compileSchema({
type: "array",
prefixItems: [{ format: "email" }, { format: "textarea" }]
});
assert.equal(schemaAnnotations.length, 1);
assert.equal(schemaAnnotations[0].data.pointer, "#/prefixItems/1/format");
});
});
});