import { SchemaValidationError } from '../../errors/SchemaValidationError'; import { JsonValidationService } from '../../JsonValidationService'; // eslint-disable-next-line @typescript-eslint/ban-types function expectToThrowErrorMatchingTypeAndMessage(received: Function, errorType: Function, message: string) { let error: null | Error = null; try { received(); } catch (e: any) { error = e; } expect(error).toBeDefined(); expect(error?.message).toEqual(message); expect(error).toBeInstanceOf(errorType); } describe('DxComponentInputSchema', () => { let jsonValidationService: JsonValidationService; beforeAll(() => { jsonValidationService = new JsonValidationService(); }); it('should allow empty object', () => { expect(() => jsonValidationService.validateContentSchema({})).not.toThrowError(); }); it('should require "required" if properties is specified', () => { expectToThrowErrorMatchingTypeAndMessage( () => jsonValidationService.validateContentSchema({ properties: { foo: { type: 'string', }, }, }), SchemaValidationError, 'failed validation: The required property `required` is missing at `#`', ); }); it('should pass if required and properties are specified', () => { expect(() => jsonValidationService.validateContentSchema({ required: ['foo'], properties: { foo: { type: 'string', }, }, }), ).not.toThrowError(); }); it('should error if type is not "object"', () => { expectToThrowErrorMatchingTypeAndMessage( () => jsonValidationService.validateContentSchema({ type: 'string', }), SchemaValidationError, 'failed validation: Expected value at `#/type` to be `object`, but value given is `string`', ); }); it('should allow a nested type to be "FormattedText"', () => { expect(() => jsonValidationService.validateContentSchema({ type: 'object', properties: { foo: { type: 'FormattedText', }, }, required: ['foo'], }), ).not.toThrowError(); }); it('should error on unknown keywords', () => { expectToThrowErrorMatchingTypeAndMessage( () => jsonValidationService.validateContentSchema({ type: 'object', foo: 'bar', }), SchemaValidationError, 'failed validation: Additional property `foo` in `#` is not allowed', ); }); it('should allow previewPlaceholder to be a string', () => { expect(() => jsonValidationService.validateContentSchema({ type: 'object', previewPlaceholder: 'foo', }), ).not.toThrowError(); }); it('should allow previewPlaceholder to be a boolean', () => { expect(() => jsonValidationService.validateContentSchema({ type: 'object', previewPlaceholder: true, }), ).not.toThrowError(); }); it('should allow a nested property to be an array of of objects which have a property of type to be "FormattedText" that is required', () => { expect(() => jsonValidationService.validateContentSchema({ type: 'object', properties: { foo: { type: 'array', items: { type: 'object', properties: { bar: { type: 'FormattedText', }, }, required: ['bar'], }, }, }, required: ['foo'], }), ).not.toThrowError(); }); it('should error if any nested object does not have a required property', () => { expectToThrowErrorMatchingTypeAndMessage( () => jsonValidationService.validateContentSchema({ type: 'object', properties: { foo: { type: 'array', items: { type: 'object', properties: { bar: { type: 'FormattedText', }, }, }, }, }, required: ['foo'], }), SchemaValidationError, 'failed validation: Object at `#/properties/foo/items` does not match any schema', ); }); it('should succeed if required is on every nested object', () => { expect(() => jsonValidationService.validateContentSchema({ type: 'object', properties: { foo: { type: 'array', items: { type: 'object', properties: { bar: { type: 'FormattedText', }, }, required: ['bar'], }, }, }, required: ['foo'], }), ).not.toThrowError(); }); describe('ui:metadata', () => { describe('enumWidget', () => { it.each(['radio', 'dropdown'])('should allow %s as a value', (v) => { expect(() => jsonValidationService.validateContentSchema({ type: 'object', required: [], properties: { myProp: { enum: ['one', 'two', 'three'], 'ui:metadata': { enumWidget: v, }, }, }, }), ).not.toThrow(); }); }); }); describe('translatable', () => { it('should allow translatable property to be true', () => { expect(() => jsonValidationService.validateContentSchema({ type: 'object', properties: { myProp: { type: 'string', translatable: true, }, }, required: ['myProp'], }), ).not.toThrow(); }); it('should allow translatable property to be false', () => { expect(() => jsonValidationService.validateContentSchema({ type: 'object', properties: { myProp: { type: 'string', translatable: false, }, }, required: ['myProp'], }), ).not.toThrow(); }); it('should allow translatable property in nested objects', () => { expect(() => jsonValidationService.validateContentSchema({ type: 'object', properties: { myProp: { type: 'object', properties: { nestedProp: { type: 'string', translatable: true, }, }, required: ['nestedProp'], }, }, required: ['myProp'], }), ).not.toThrow(); }); it('should allow translatable property in array items', () => { expect(() => jsonValidationService.validateContentSchema({ type: 'object', properties: { myProp: { type: 'array', items: { type: 'object', properties: { itemProp: { type: 'string', translatable: true, }, }, required: ['itemProp'], }, }, }, required: ['myProp'], }), ).not.toThrow(); }); it('should error if translatable is not a boolean', () => { expectToThrowErrorMatchingTypeAndMessage( () => jsonValidationService.validateContentSchema({ type: 'object', properties: { myProp: { type: 'string', translatable: 'true', }, }, required: ['myProp'], }), SchemaValidationError, 'failed validation: Expected `true` (string) in `#/properties/myProp/translatable` to be of type `boolean`', ); }); }); });