diff --git a/src/core/components/parameter-row.jsx b/src/core/components/parameter-row.jsx index 65f7da5afe3..fe11db3a06f 100644 --- a/src/core/components/parameter-row.jsx +++ b/src/core/components/parameter-row.jsx @@ -352,6 +352,26 @@ export default class ParameterRow extends Component { : null } + {(() => { + // Use the appropriate constraint function based on OpenAPI version + const isOAS31 = specSelectors.isOAS31 && specSelectors.isOAS31() + let numericConstraint = null + + if (isOAS31 && fn.jsonSchema202012?.stringifyConstraintNumberRange) { + // For OpenAPI 3.1 (JSON Schema 2020-12) + // Transform Immutable schema to plain object for the function + const plainSchema = schema?.toJS ? schema.toJS() : schema + numericConstraint = fn.jsonSchema202012.stringifyConstraintNumberRange(plainSchema) + } else if (fn.stringifyConstraintNumberRange) { + // For OpenAPI 2.0/3.0 (JSON Schema Draft 5) + numericConstraint = fn.stringifyConstraintNumberRange(schema) + } + + return numericConstraint ? ( + Constraints : ${numericConstraint}`}/> + ) : null + })()} + {(isFormData && !isFormDataSupported) &&
Error: your browser does not support FormData
} { diff --git a/src/core/plugins/json-schema-2020-12/fn.js b/src/core/plugins/json-schema-2020-12/fn.js index d07f7acd4e0..7b49d53893f 100644 --- a/src/core/plugins/json-schema-2020-12/fn.js +++ b/src/core/plugins/json-schema-2020-12/fn.js @@ -525,3 +525,5 @@ export const hasSchemaType = (schema, type) => { return hasType(schemaType) } + +export { stringifyConstraintNumberRange } diff --git a/src/core/plugins/json-schema-2020-12/index.js b/src/core/plugins/json-schema-2020-12/index.js index c78d89dc7d2..90c982f736e 100644 --- a/src/core/plugins/json-schema-2020-12/index.js +++ b/src/core/plugins/json-schema-2020-12/index.js @@ -56,6 +56,7 @@ import { getSchemaKeywords, makeGetExtensionKeywords, hasSchemaType, + stringifyConstraintNumberRange, } from "./fn" import { JSONSchemaPathContext, JSONSchemaLevelContext } from "./context" import { @@ -145,6 +146,7 @@ const JSONSchema202012Plugin = ({ getSystem, fn }) => { getSchemaKeywords, getExtensionKeywords: makeGetExtensionKeywords(fnAccessor), hasSchemaType, + stringifyConstraintNumberRange, }, }, } diff --git a/src/core/plugins/json-schema-5/fn.js b/src/core/plugins/json-schema-5/fn.js index 19e61bfac65..7181be65af2 100644 --- a/src/core/plugins/json-schema-5/fn.js +++ b/src/core/plugins/json-schema-5/fn.js @@ -49,3 +49,34 @@ const getType = (schema, processedSchemas = new WeakSet()) => { export const getSchemaObjectTypeLabel = (schema) => getType(immutableToJS(schema)) + +// For OpenAPI 2.0 and 3.0 (JSON Schema Draft 4/5) +// where exclusiveMinimum and exclusiveMaximum are booleans +export const stringifyConstraintNumberRange = (schema) => { + // Handle both plain objects and Immutable Maps + const minimum = schema?.get ? schema.get("minimum") : schema?.minimum + const maximum = schema?.get ? schema.get("maximum") : schema?.maximum + const exclusiveMinimum = schema?.get ? schema.get("exclusiveMinimum") : schema?.exclusiveMinimum + const exclusiveMaximum = schema?.get ? schema.get("exclusiveMaximum") : schema?.exclusiveMaximum + + const hasMinimum = typeof minimum === "number" + const hasMaximum = typeof maximum === "number" + const isMinExclusive = exclusiveMinimum === true + const isMaxExclusive = exclusiveMaximum === true + + if (hasMinimum && hasMaximum) { + const minSymbol = isMinExclusive ? "(" : "[" + const maxSymbol = isMaxExclusive ? ")" : "]" + return `${minSymbol}${minimum}, ${maximum}${maxSymbol}` + } + if (hasMinimum) { + const minSymbol = isMinExclusive ? ">" : "≥" + return `${minSymbol} ${minimum}` + } + if (hasMaximum) { + const maxSymbol = isMaxExclusive ? "<" : "≤" + return `${maxSymbol} ${maximum}` + } + + return null +} diff --git a/src/core/plugins/json-schema-5/index.js b/src/core/plugins/json-schema-5/index.js index 3e1f887767e..c6809f4cf35 100644 --- a/src/core/plugins/json-schema-5/index.js +++ b/src/core/plugins/json-schema-5/index.js @@ -14,7 +14,7 @@ import Schemes from "./components/schemes" import SchemesContainer from "./containers/schemes" import * as JSONSchemaComponents from "./components/json-schema-components" import { ModelExtensions } from "./components/model-extensions" -import { getSchemaObjectTypeLabel, hasSchemaType } from "./fn" +import { getSchemaObjectTypeLabel, hasSchemaType, stringifyConstraintNumberRange } from "./fn" const JSONSchema5Plugin = () => ({ components: { @@ -35,6 +35,7 @@ const JSONSchema5Plugin = () => ({ fn: { hasSchemaType, getSchemaObjectTypeLabel, + stringifyConstraintNumberRange, }, }) diff --git a/test/unit/components/parameter-constraints.spec.js b/test/unit/components/parameter-constraints.spec.js new file mode 100644 index 00000000000..1790f6ac4a1 --- /dev/null +++ b/test/unit/components/parameter-constraints.spec.js @@ -0,0 +1,289 @@ +import React from "react" +import { shallow } from "enzyme" +import { fromJS } from "immutable" +import ParameterRow from "core/components/parameter-row" + +describe("ParameterRow constraints", () => { + const defaultProps = { + onChange: jest.fn(), + param: fromJS({ name: "test", in: "query" }), + rawParam: fromJS({ name: "test", in: "query" }), + getComponent: () => () => null, + fn: {}, + isExecute: false, + onChangeConsumes: jest.fn(), + specSelectors: { + isOAS3: () => false, + isOAS31: () => false, + parameterWithMetaByIdentity: () => fromJS({}), + contentTypeValues: () => fromJS({}), + consumesOptionsFor: () => fromJS([]), + parameterInclusionSettingFor: () => false, + }, + specActions: {}, + pathMethod: ["get", "/test"], + getConfigs: () => ({ showExtensions: false, showCommonExtensions: false }), + specPath: fromJS([]), + oas3Actions: {}, + oas3Selectors: { + activeExamplesMember: () => null, + }, + } + + describe("OpenAPI 2.0/3.0 constraints (JSON Schema Draft 5)", () => { + it("should display minimum constraint", () => { + const schema = fromJS({ + type: "number", + minimum: 1, + }) + const props = { + ...defaultProps, + fn: { + ...defaultProps.fn, + stringifyConstraintNumberRange: jest.fn(() => "≥ 1"), + getSampleSchema: jest.fn(), + getSchemaObjectType: jest.fn(() => "number"), + getSchemaObjectTypeLabel: jest.fn(() => "number"), + }, + param: fromJS({ + name: "test", + in: "query", + schema: schema.toJS(), + }), + } + + const wrapper = shallow() + expect(props.fn.stringifyConstraintNumberRange).toHaveBeenCalledWith(schema) + expect(wrapper.find('Markdown[className="parameter__constraint"]')).toHaveLength(1) + }) + + it("should display maximum constraint", () => { + const schema = fromJS({ + type: "number", + maximum: 100, + }) + const props = { + ...defaultProps, + fn: { + ...defaultProps.fn, + stringifyConstraintNumberRange: jest.fn(() => "≤ 100"), + getSampleSchema: jest.fn(), + getSchemaObjectType: jest.fn(() => "number"), + getSchemaObjectTypeLabel: jest.fn(() => "number"), + }, + param: fromJS({ + name: "test", + in: "query", + schema: schema.toJS(), + }), + } + + const wrapper = shallow() + expect(props.fn.stringifyConstraintNumberRange).toHaveBeenCalledWith(schema) + expect(wrapper.find('Markdown[className="parameter__constraint"]')).toHaveLength(1) + }) + + it("should display range constraint", () => { + const schema = fromJS({ + type: "number", + minimum: 1, + maximum: 100, + }) + const props = { + ...defaultProps, + fn: { + ...defaultProps.fn, + stringifyConstraintNumberRange: jest.fn(() => "[1, 100]"), + getSampleSchema: jest.fn(), + getSchemaObjectType: jest.fn(() => "number"), + getSchemaObjectTypeLabel: jest.fn(() => "number"), + }, + param: fromJS({ + name: "test", + in: "query", + schema: schema.toJS(), + }), + } + + const wrapper = shallow() + expect(props.fn.stringifyConstraintNumberRange).toHaveBeenCalledWith(schema) + expect(wrapper.find('Markdown[className="parameter__constraint"]')).toHaveLength(1) + }) + + it("should display exclusive constraints (boolean style)", () => { + const schema = fromJS({ + type: "number", + minimum: 0, + exclusiveMinimum: true, + maximum: 100, + exclusiveMaximum: true, + }) + const props = { + ...defaultProps, + fn: { + ...defaultProps.fn, + stringifyConstraintNumberRange: jest.fn(() => "(0, 100)"), + getSampleSchema: jest.fn(), + getSchemaObjectType: jest.fn(() => "number"), + getSchemaObjectTypeLabel: jest.fn(() => "number"), + }, + param: fromJS({ + name: "test", + in: "query", + schema: schema.toJS(), + }), + } + + const wrapper = shallow() + expect(props.fn.stringifyConstraintNumberRange).toHaveBeenCalledWith(schema) + expect(wrapper.find('Markdown[className="parameter__constraint"]')).toHaveLength(1) + }) + + it("should not display constraints when none exist", () => { + const schema = fromJS({ + type: "string", + }) + const props = { + ...defaultProps, + fn: { + ...defaultProps.fn, + stringifyConstraintNumberRange: jest.fn(() => null), + getSampleSchema: jest.fn(), + getSchemaObjectType: jest.fn(() => "string"), + getSchemaObjectTypeLabel: jest.fn(() => "string"), + }, + param: fromJS({ + name: "test", + in: "query", + schema: schema.toJS(), + }), + } + + const wrapper = shallow() + expect(props.fn.stringifyConstraintNumberRange).toHaveBeenCalledWith(schema) + expect(wrapper.find('Markdown[className="parameter__constraint"]')).toHaveLength(0) + }) + }) + + describe("OpenAPI 3.1 constraints (JSON Schema 2020-12)", () => { + it("should use jsonSchema202012 function for OAS 3.1", () => { + const schema = fromJS({ + type: "number", + exclusiveMinimum: 0, + exclusiveMaximum: 100, + }) + const props = { + ...defaultProps, + specSelectors: { + ...defaultProps.specSelectors, + isOAS31: () => true, + }, + fn: { + ...defaultProps.fn, + jsonSchema202012: { + stringifyConstraintNumberRange: jest.fn(() => "(0, 100)"), + }, + getSampleSchema: jest.fn(), + getSchemaObjectType: jest.fn(() => "number"), + getSchemaObjectTypeLabel: jest.fn(() => "number"), + }, + param: fromJS({ + name: "test", + in: "query", + schema: schema.toJS(), + }), + } + + const wrapper = shallow() + expect(props.fn.jsonSchema202012.stringifyConstraintNumberRange).toHaveBeenCalledWith(schema.toJS()) + expect(wrapper.find('Markdown[className="parameter__constraint"]')).toHaveLength(1) + }) + + it("should handle immutable to plain object conversion for OAS 3.1", () => { + const schema = fromJS({ + type: "number", + minimum: 1, + maximum: 100, + }) + const props = { + ...defaultProps, + specSelectors: { + ...defaultProps.specSelectors, + isOAS31: () => true, + }, + fn: { + ...defaultProps.fn, + jsonSchema202012: { + stringifyConstraintNumberRange: jest.fn(() => "[1, 100]"), + }, + getSampleSchema: jest.fn(), + getSchemaObjectType: jest.fn(() => "number"), + getSchemaObjectTypeLabel: jest.fn(() => "number"), + }, + param: fromJS({ + name: "test", + in: "query", + schema: schema.toJS(), + }), + } + + const wrapper = shallow() + // Verify the schema was converted to plain object + const passedSchema = props.fn.jsonSchema202012.stringifyConstraintNumberRange.mock.calls[0][0] + expect(passedSchema.toJS).toBeUndefined() // Should be plain object, not Immutable + expect(passedSchema.minimum).toBe(1) + expect(passedSchema.maximum).toBe(100) + }) + }) + + describe("fallback behavior", () => { + it("should not crash when constraint functions are not available", () => { + const schema = fromJS({ + type: "number", + minimum: 1, + }) + const props = { + ...defaultProps, + fn: { + ...defaultProps.fn, + getSampleSchema: jest.fn(), + getSchemaObjectType: jest.fn(() => "number"), + getSchemaObjectTypeLabel: jest.fn(() => "number"), + // No stringifyConstraintNumberRange function + }, + param: fromJS({ + name: "test", + in: "query", + schema: schema.toJS(), + }), + } + + expect(() => { + const wrapper = shallow() + expect(wrapper.find('Markdown[className="parameter__constraint"]')).toHaveLength(0) + }).not.toThrow() + }) + + it("should handle null schema gracefully", () => { + const props = { + ...defaultProps, + fn: { + ...defaultProps.fn, + stringifyConstraintNumberRange: jest.fn(() => null), + getSampleSchema: jest.fn(), + getSchemaObjectType: jest.fn(() => null), + getSchemaObjectTypeLabel: jest.fn(() => "unknown"), + }, + param: fromJS({ + name: "test", + in: "query", + }), + } + + expect(() => { + const wrapper = shallow() + expect(wrapper.find('Markdown[className="parameter__constraint"]')).toHaveLength(0) + }).not.toThrow() + }) + }) +}) \ No newline at end of file diff --git a/test/unit/components/parameter-row.jsx b/test/unit/components/parameter-row.jsx index 862a055c4de..2a505878b51 100644 --- a/test/unit/components/parameter-row.jsx +++ b/test/unit/components/parameter-row.jsx @@ -364,3 +364,118 @@ describe("bug #5573: zero default and example values", function () { expect(props.onChange).toHaveBeenCalledWith(paramValue, "0", false) }) }) + +describe("parameter constraints display", () => { + const createProps = ({ param, isOAS3 }) => { + const getSystem = () => ({ + getComponent: () => "div", + specSelectors: { + parameterWithMetaByIdentity: () => param, + isOAS3: () => isOAS3, + isSwagger2: () => !isOAS3, + }, + fn: { + memoizedSampleFromSchema, + memoizedCreateXMLExample, + getSchemaObjectTypeLabel, + getSchemaObjectType, + getJsonSampleSchema: makeGetJsonSampleSchema(getSystem), + getYamlSampleSchema: makeGetYamlSampleSchema(getSystem), + getXmlSampleSchema: makeGetXmlSampleSchema(getSystem), + getSampleSchema: makeGetSampleSchema(getSystem), + mergeJsonSchema, + }, + oas3Selectors: { activeExamplesMember: () => {} }, + getConfigs: () => ({}), + }) + + return { + ...getSystem(), + param, + rawParam: param, + pathMethod: [], + } + } + + it("should display minimum constraint", () => { + const param = fromJS({ + name: "id", + in: "path", + required: true, + schema: { + type: "integer", + minimum: 1 + } + }) + + const props = createProps({ param, isOAS3: true }) + const wrapper = render() + + // Check if constraint text is rendered somewhere in the component + expect(wrapper.html()).toContain("≥ 1") + }) + + it("should display maximum constraint", () => { + const param = fromJS({ + name: "limit", + in: "query", + schema: { + type: "integer", + maximum: 100 + } + }) + + const props = createProps({ param, isOAS3: true }) + const wrapper = render() + + expect(wrapper.html()).toContain("≤ 100") + }) + + it("should display exclusive minimum constraint", () => { + const param = fromJS({ + name: "price", + in: "query", + schema: { + type: "number", + exclusiveMinimum: 0 + } + }) + + const props = createProps({ param, isOAS3: true }) + const wrapper = render() + + expect(wrapper.html()).toContain("> 0") + }) + + it("should display range constraints", () => { + const param = fromJS({ + name: "range", + in: "query", + schema: { + type: "integer", + minimum: 1, + maximum: 100 + } + }) + + const props = createProps({ param, isOAS3: true }) + const wrapper = render() + + expect(wrapper.html()).toContain("[1, 100]") + }) + + it("should not display constraints when none are present", () => { + const param = fromJS({ + name: "name", + in: "query", + schema: { + type: "string" + } + }) + + const props = createProps({ param, isOAS3: true }) + const wrapper = render() + + expect(wrapper.html()).not.toContain("Constraints") + }) +}) diff --git a/test/unit/core/plugins/constraint-functions.spec.js b/test/unit/core/plugins/constraint-functions.spec.js new file mode 100644 index 00000000000..19f10a0bfd7 --- /dev/null +++ b/test/unit/core/plugins/constraint-functions.spec.js @@ -0,0 +1,181 @@ +import { fromJS } from "immutable" +import { stringifyConstraintNumberRange as stringifyConstraintNumberRangeOAS31 } from "core/plugins/json-schema-2020-12/fn" +import { stringifyConstraintNumberRange as stringifyConstraintNumberRangeDraft5 } from "core/plugins/json-schema-5/fn" + +describe("stringifyConstraintNumberRange", () => { + describe("JSON Schema 2020-12 (OpenAPI 3.1)", () => { + it("should format minimum constraint", () => { + const schema = { minimum: 1 } + expect(stringifyConstraintNumberRangeOAS31(schema)).toBe("≥ 1") + }) + + it("should format maximum constraint", () => { + const schema = { maximum: 100 } + expect(stringifyConstraintNumberRangeOAS31(schema)).toBe("≤ 100") + }) + + it("should format exclusive minimum constraint", () => { + const schema = { exclusiveMinimum: 0 } + expect(stringifyConstraintNumberRangeOAS31(schema)).toBe("> 0") + }) + + it("should format exclusive maximum constraint", () => { + const schema = { exclusiveMaximum: 100 } + expect(stringifyConstraintNumberRangeOAS31(schema)).toBe("< 100") + }) + + it("should format range constraint with inclusive bounds", () => { + const schema = { minimum: 1, maximum: 100 } + expect(stringifyConstraintNumberRangeOAS31(schema)).toBe("[1, 100]") + }) + + it("should format range constraint with exclusive bounds", () => { + const schema = { exclusiveMinimum: 0, exclusiveMaximum: 100 } + expect(stringifyConstraintNumberRangeOAS31(schema)).toBe("(0, 100)") + }) + + it("should format mixed range constraint (exclusive min, inclusive max)", () => { + const schema = { exclusiveMinimum: 0, maximum: 100 } + expect(stringifyConstraintNumberRangeOAS31(schema)).toBe("(0, 100]") + }) + + it("should format mixed range constraint (inclusive min, exclusive max)", () => { + const schema = { minimum: 1, exclusiveMaximum: 100 } + expect(stringifyConstraintNumberRangeOAS31(schema)).toBe("[1, 100)") + }) + + it("should prefer exclusiveMinimum over minimum when both present", () => { + const schema = { minimum: 1, exclusiveMinimum: 2 } + expect(stringifyConstraintNumberRangeOAS31(schema)).toBe("> 2") + }) + + it("should prefer exclusiveMaximum over maximum when both present", () => { + const schema = { maximum: 100, exclusiveMaximum: 99 } + expect(stringifyConstraintNumberRangeOAS31(schema)).toBe("< 99") + }) + + it("should return null when no constraints present", () => { + const schema = { type: "number" } + expect(stringifyConstraintNumberRangeOAS31(schema)).toBe(null) + }) + + it("should return null when schema is null or undefined", () => { + expect(stringifyConstraintNumberRangeOAS31(null)).toBe(null) + expect(stringifyConstraintNumberRangeOAS31(undefined)).toBe(null) + }) + + it("should handle non-numeric constraint values", () => { + const schema = { minimum: "not a number", maximum: null } + expect(stringifyConstraintNumberRangeOAS31(schema)).toBe(null) + }) + }) + + describe("JSON Schema Draft 5 (OpenAPI 2.0/3.0)", () => { + it("should format minimum constraint", () => { + const schema = fromJS({ minimum: 1 }) + expect(stringifyConstraintNumberRangeDraft5(schema)).toBe("≥ 1") + }) + + it("should format maximum constraint", () => { + const schema = fromJS({ maximum: 100 }) + expect(stringifyConstraintNumberRangeDraft5(schema)).toBe("≤ 100") + }) + + it("should format exclusive minimum constraint (boolean style)", () => { + const schema = fromJS({ minimum: 0, exclusiveMinimum: true }) + expect(stringifyConstraintNumberRangeDraft5(schema)).toBe("> 0") + }) + + it("should format exclusive maximum constraint (boolean style)", () => { + const schema = fromJS({ maximum: 100, exclusiveMaximum: true }) + expect(stringifyConstraintNumberRangeDraft5(schema)).toBe("< 100") + }) + + it("should format range constraint with inclusive bounds", () => { + const schema = fromJS({ minimum: 1, maximum: 100 }) + expect(stringifyConstraintNumberRangeDraft5(schema)).toBe("[1, 100]") + }) + + it("should format range constraint with exclusive bounds (boolean style)", () => { + const schema = fromJS({ minimum: 0, exclusiveMinimum: true, maximum: 100, exclusiveMaximum: true }) + expect(stringifyConstraintNumberRangeDraft5(schema)).toBe("(0, 100)") + }) + + it("should format mixed range constraint (exclusive min, inclusive max)", () => { + const schema = fromJS({ minimum: 0, exclusiveMinimum: true, maximum: 100 }) + expect(stringifyConstraintNumberRangeDraft5(schema)).toBe("(0, 100]") + }) + + it("should format mixed range constraint (inclusive min, exclusive max)", () => { + const schema = fromJS({ minimum: 1, maximum: 100, exclusiveMaximum: true }) + expect(stringifyConstraintNumberRangeDraft5(schema)).toBe("[1, 100)") + }) + + it("should handle plain objects (not Immutable)", () => { + const schema = { minimum: 1, maximum: 100 } + expect(stringifyConstraintNumberRangeDraft5(schema)).toBe("[1, 100]") + }) + + it("should ignore boolean exclusiveMinimum when false", () => { + const schema = fromJS({ minimum: 1, exclusiveMinimum: false }) + expect(stringifyConstraintNumberRangeDraft5(schema)).toBe("≥ 1") + }) + + it("should ignore boolean exclusiveMaximum when false", () => { + const schema = fromJS({ maximum: 100, exclusiveMaximum: false }) + expect(stringifyConstraintNumberRangeDraft5(schema)).toBe("≤ 100") + }) + + it("should return null when no constraints present", () => { + const schema = fromJS({ type: "number" }) + expect(stringifyConstraintNumberRangeDraft5(schema)).toBe(null) + }) + + it("should return null when schema is null or undefined", () => { + expect(stringifyConstraintNumberRangeDraft5(null)).toBe(null) + expect(stringifyConstraintNumberRangeDraft5(undefined)).toBe(null) + }) + + it("should handle constraints without minimum/maximum when exclusive flags are present", () => { + const schema = fromJS({ exclusiveMinimum: true, exclusiveMaximum: true }) + expect(stringifyConstraintNumberRangeDraft5(schema)).toBe(null) + }) + + it("should handle mixed Immutable and plain object access patterns", () => { + // Test with an object that has both .get method and direct property access + const mockSchema = { + get: jest.fn((key) => { + const values = { minimum: 1, maximum: 100 } + return values[key] + }), + minimum: 1, + maximum: 100, + } + + expect(stringifyConstraintNumberRangeDraft5(mockSchema)).toBe("[1, 100]") + expect(mockSchema.get).toHaveBeenCalledWith("minimum") + expect(mockSchema.get).toHaveBeenCalledWith("maximum") + expect(mockSchema.get).toHaveBeenCalledWith("exclusiveMinimum") + expect(mockSchema.get).toHaveBeenCalledWith("exclusiveMaximum") + }) + }) + + describe("edge cases", () => { + it("should handle zero values correctly", () => { + expect(stringifyConstraintNumberRangeOAS31({ minimum: 0 })).toBe("≥ 0") + expect(stringifyConstraintNumberRangeOAS31({ maximum: 0 })).toBe("≤ 0") + expect(stringifyConstraintNumberRangeOAS31({ exclusiveMinimum: 0 })).toBe("> 0") + expect(stringifyConstraintNumberRangeOAS31({ exclusiveMaximum: 0 })).toBe("< 0") + }) + + it("should handle negative values correctly", () => { + expect(stringifyConstraintNumberRangeOAS31({ minimum: -10, maximum: -1 })).toBe("[-10, -1]") + expect(stringifyConstraintNumberRangeDraft5(fromJS({ minimum: -10, maximum: -1 }))).toBe("[-10, -1]") + }) + + it("should handle decimal values correctly", () => { + expect(stringifyConstraintNumberRangeOAS31({ minimum: 0.1, maximum: 99.9 })).toBe("[0.1, 99.9]") + expect(stringifyConstraintNumberRangeDraft5(fromJS({ minimum: 0.1, maximum: 99.9 }))).toBe("[0.1, 99.9]") + }) + }) +}) \ No newline at end of file