1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-06 00:07:44 +01:00
unleash.unleash/src/lib/openapi/meta-schema-rules.test.ts

139 lines
4.3 KiB
TypeScript
Raw Normal View History

import Ajv, { Schema } from 'ajv';
import { schemas } from '.';
const ajv = new Ajv();
type SchemaNames = keyof typeof schemas;
type Rule = {
name: string;
match?: (
schemaName: string,
schema: typeof schemas[SchemaNames],
) => boolean;
metaSchema: Schema;
knownExceptions?: string[];
};
/**
* These rules are applied to all schemas in the spec.
*
* The rules usually start as a meta schema, which is a schema that describes
* the shape of the OpenAPI schemas. Usually they look like this:
*
* <code>
* const metaSchema: Schema = {
* type: 'object',
* properties: {
* // what we want to specify about the schema
* }
* }
* </code>
*/
const metaRules: Rule[] = [
{
name: 'should have a type',
metaSchema: {
type: 'object',
properties: {
type: { type: 'string', enum: ['object', 'array', 'boolean'] },
},
required: ['type'],
},
knownExceptions: ['dateSchema'],
},
{
name: 'should have an $id with the expected format',
metaSchema: {
type: 'object',
properties: {
$id: {
type: 'string',
pattern: '^#/components/schemas/[a-z][a-zA-Z]+$',
},
},
required: ['$id'],
},
},
{
name: 'should have properties with descriptions',
match: (_, schema) =>
// only match schemas that have a properties field
'properties' in schema,
metaSchema: {
type: 'object',
// properties of the meta schema
properties: {
// the schema should have a field called properties
properties: {
type: 'object', // properties of the schema should be an object
additionalProperties: {
// with the following shape
anyOf: [
{
type: 'object',
properties: {
description: { type: 'string' },
},
required: ['description'],
},
{
type: 'object',
properties: {
$ref: { type: 'string' },
},
required: ['$ref'],
},
],
},
},
},
},
knownExceptions: [],
},
{
name: 'should either have oneOf or properties, instead extract them in commonProps',
match: (_, schema) =>
// only match schemas that have a properties field
'properties' in schema && 'oneOf' in schema,
metaSchema: {
type: 'object',
additionalProperties: false, // this is a shortcut to say: it should fail
},
knownExceptions: [],
},
{
name: 'should have a description',
metaSchema: {
type: 'object',
properties: {
description: { type: 'string' },
},
required: ['description'],
},
knownExceptions: [],
},
];
describe.each(metaRules)('OpenAPI schemas $name', (rule) => {
const validateMetaSchema = ajv.compile(rule.metaSchema);
// test all schemas against the rule
Object.entries(schemas).forEach(([schemaName, schema]) => {
if (!rule.match || rule.match(schemaName, schema)) {
it(`${schemaName}`, () => {
validateMetaSchema(schema);
// note: whenever you resolve an exception please remove it from the list
if (rule.knownExceptions?.includes(schemaName)) {
console.warn(
`${schemaName} is a known exception to rule "${rule.name}" that should be fixed`,
);
expect(validateMetaSchema.errors).not.toBeNull();
} else {
expect(validateMetaSchema.errors).toBeNull();
}
});
}
});
});