Spaces:
Sleeping
Sleeping
| import { describe, expect, it } from 'vitest' | |
| import { | |
| normalizeSchema, | |
| inferFieldType, | |
| extractSchemaTags, | |
| schemaType, | |
| } from '@/lib/config-schema-utils' | |
| describe('normalizeSchema', () => { | |
| it('passes through a simple string schema', () => { | |
| const s = { type: 'string' as const } | |
| expect(normalizeSchema(s)).toBe(s) | |
| expect(schemaType(normalizeSchema(s))).toBe('string') | |
| }) | |
| it('preserves number constraints', () => { | |
| const s = { type: 'number' as const, minimum: 0, maximum: 100 } | |
| const result = normalizeSchema(s) | |
| expect(result).toBe(s) | |
| expect(result.minimum).toBe(0) | |
| expect(result.maximum).toBe(100) | |
| }) | |
| it('passes through a boolean schema', () => { | |
| const s = { type: 'boolean' as const } | |
| expect(normalizeSchema(s)).toBe(s) | |
| expect(schemaType(normalizeSchema(s))).toBe('boolean') | |
| }) | |
| it('converts enum variants into enumValues', () => { | |
| const s = { anyOf: [{ const: 'a' }, { const: 'b' }, { const: 'c' }] } | |
| const result = normalizeSchema(s) | |
| expect(result.enum).toEqual(['a', 'b', 'c']) | |
| expect(result.anyOf).toBeUndefined() | |
| }) | |
| it('passes through array with string items', () => { | |
| const s = { type: 'array' as const, items: { type: 'string' as const } } | |
| const result = normalizeSchema(s) | |
| expect(result).toBe(s) | |
| expect(schemaType(result)).toBe('array') | |
| }) | |
| it('passes through object with properties', () => { | |
| const s = { | |
| type: 'object' as const, | |
| properties: { | |
| name: { type: 'string' as const }, | |
| age: { type: 'number' as const }, | |
| }, | |
| } | |
| const result = normalizeSchema(s) | |
| expect(result).toBe(s) | |
| expect(schemaType(result)).toBe('object') | |
| expect(result.properties).toBeDefined() | |
| }) | |
| it('resolves anyOf with null to nullable string', () => { | |
| const s = { | |
| title: 'Optional Name', | |
| anyOf: [{ type: 'string' as const }, { type: 'null' as const }], | |
| } | |
| const result = normalizeSchema(s) | |
| expect(result.nullable).toBe(true) | |
| expect(schemaType(result)).toBe('string') | |
| expect(result.anyOf).toBeUndefined() | |
| expect(result.title).toBe('Optional Name') | |
| }) | |
| it('resolves oneOf with null to nullable type', () => { | |
| const s = { | |
| description: 'Nullable number', | |
| oneOf: [{ type: 'number' as const }, { type: 'null' as const }], | |
| } | |
| const result = normalizeSchema(s) | |
| expect(result.nullable).toBe(true) | |
| expect(schemaType(result)).toBe('number') | |
| }) | |
| it('collapses enum entries with null into nullable enum', () => { | |
| const s = { | |
| anyOf: [{ enum: ['x', 'y', null] }], | |
| } | |
| const result = normalizeSchema(s) | |
| expect(result.enum).toEqual(['x', 'y']) | |
| expect(result.nullable).toBe(true) | |
| }) | |
| it('returns original schema when union cannot be simplified', () => { | |
| const s = { | |
| anyOf: [ | |
| { type: 'string' as const }, | |
| { type: 'number' as const }, | |
| ], | |
| } | |
| const result = normalizeSchema(s) | |
| expect(result).toBe(s) | |
| }) | |
| }) | |
| describe('inferFieldType', () => { | |
| it('infers string from a string value', () => { | |
| expect(inferFieldType('hello')).toBe('string') | |
| }) | |
| it('infers number from a numeric value', () => { | |
| expect(inferFieldType(42)).toBe('number') | |
| }) | |
| it('infers boolean from a boolean value', () => { | |
| expect(inferFieldType(true)).toBe('boolean') | |
| }) | |
| it('infers array from an array value', () => { | |
| expect(inferFieldType([1, 2, 3])).toBe('array') | |
| }) | |
| it('infers object from a plain object', () => { | |
| expect(inferFieldType({ a: 1 })).toBe('object') | |
| }) | |
| it('defaults to string for null', () => { | |
| expect(inferFieldType(null)).toBe('string') | |
| }) | |
| it('defaults to string for undefined', () => { | |
| expect(inferFieldType(undefined)).toBe('string') | |
| }) | |
| }) | |
| describe('extractSchemaTags', () => { | |
| it('extracts x-tags from schema', () => { | |
| const s = { 'x-tags': ['security', 'auth'] } | |
| expect(extractSchemaTags(s)).toEqual(['security', 'auth']) | |
| }) | |
| it('extracts tags field when x-tags is absent', () => { | |
| const s = { tags: ['network'] } | |
| expect(extractSchemaTags(s)).toEqual(['network']) | |
| }) | |
| it('returns empty array for schema without tags', () => { | |
| const s = { type: 'string' as const } | |
| expect(extractSchemaTags(s)).toEqual([]) | |
| }) | |
| it('collects tags from nested properties', () => { | |
| const s = { | |
| type: 'object' as const, | |
| 'x-tags': ['top'], | |
| properties: { | |
| child: { type: 'string' as const, 'x-tags': ['nested'] }, | |
| }, | |
| } | |
| const tags = extractSchemaTags(s) | |
| expect(tags).toContain('top') | |
| expect(tags).toContain('nested') | |
| }) | |
| it('collects tags from array items', () => { | |
| const s = { | |
| type: 'array' as const, | |
| items: { type: 'string' as const, 'x-tags': ['item-tag'] }, | |
| } | |
| expect(extractSchemaTags(s)).toEqual(['item-tag']) | |
| }) | |
| it('lowercases all tags', () => { | |
| const s = { 'x-tags': ['Security', 'AUTH'] } | |
| expect(extractSchemaTags(s)).toEqual(['security', 'auth']) | |
| }) | |
| it('deduplicates tags', () => { | |
| const s = { | |
| type: 'object' as const, | |
| 'x-tags': ['auth'], | |
| properties: { | |
| child: { type: 'string' as const, 'x-tags': ['Auth'] }, | |
| }, | |
| } | |
| expect(extractSchemaTags(s)).toEqual(['auth']) | |
| }) | |
| }) | |
| describe('schemaType', () => { | |
| it('returns undefined for undefined schema', () => { | |
| expect(schemaType(undefined)).toBeUndefined() | |
| }) | |
| it('returns type from simple schema', () => { | |
| expect(schemaType({ type: 'string' })).toBe('string') | |
| }) | |
| it('filters null from type array', () => { | |
| expect(schemaType({ type: ['string', 'null'] })).toBe('string') | |
| }) | |
| it('infers object from properties', () => { | |
| expect(schemaType({ properties: { a: { type: 'string' } } })).toBe('object') | |
| }) | |
| it('infers object from additionalProperties', () => { | |
| expect(schemaType({ additionalProperties: { type: 'string' } })).toBe('object') | |
| }) | |
| }) | |