From 54a9226de3a310a116a8ba420256a13c4712e24c Mon Sep 17 00:00:00 2001 From: Nathan Farmer Date: Thu, 7 Mar 2024 23:03:04 -0500 Subject: [PATCH] Add new tests and get all passing --- src/antd/InputNumber.tsx | 13 +- .../NumericControls/NumericControl.test.tsx | 21 ++ .../NumericControls/NumericControl.tsx | 2 +- .../NumericSliderControl.test.tsx | 15 +- .../NumericControls/NumericSliderControl.tsx | 2 +- src/testSchemas/numberSchema.ts | 218 ------------------ .../numericSchema/numericSliderSchema.ts | 4 +- tsconfig.cjs.json | 4 +- tsconfig.esm.json | 3 +- tsconfig.production.json | 6 - 10 files changed, 53 insertions(+), 235 deletions(-) delete mode 100644 src/testSchemas/numberSchema.ts diff --git a/src/antd/InputNumber.tsx b/src/antd/InputNumber.tsx index bf6d80f..531ac13 100644 --- a/src/antd/InputNumber.tsx +++ b/src/antd/InputNumber.tsx @@ -18,15 +18,17 @@ export const InputNumber = (props: InputNumberProps): InputNumber => { (typeof numberType === "string" && numberType === "integer") || (Array.isArray(numberType) && numberType.includes("integer")) ) { - props.handleChange(props.path, value !== null ? coerceToInteger(value) : value) + props.handleChange(props.path, coerceToInteger(value)) } else { - props.handleChange(props.path, value !== null ? coerceToNumber(value) : value) + props.handleChange(props.path, coerceToNumber(value)) } + } else { + props.handleChange(props.path, value) } } - const min = schema.properties?.minimum as number | undefined - const max = schema.properties?.maximum as number | undefined + const min = schema.minimum + const max = schema.maximum const defaultValue = typeof schema?.default === "number" ? schema.default : undefined @@ -38,7 +40,8 @@ export const InputNumber = (props: InputNumberProps): InputNumber => { const addonBefore = props.uischema.options?.addonBefore as string | undefined const isPercentage = addonAfter?.trim() === "%" - const style = { marginLeft: 0, width: "100%" } + const marginLeft = min !== undefined && max !== undefined ? 16 : 0 + const style = { marginLeft: marginLeft, width: "100%" } const formatter = ((value?: number) => { if (typeof value !== "undefined") { if (isPercentage) { diff --git a/src/controls/NumericControls/NumericControl.test.tsx b/src/controls/NumericControls/NumericControl.test.tsx index 98c9d2f..1e98595 100644 --- a/src/controls/NumericControls/NumericControl.test.tsx +++ b/src/controls/NumericControls/NumericControl.test.tsx @@ -9,6 +9,8 @@ import { numericWeightSchema, numericUISchema, numericUISchemaWithRule, + numericPriceSchema, + numericUSDUISchema, } from "../../testSchemas/numericSchema/numericSchema" @@ -113,4 +115,23 @@ describe("NumericControl", () => { expect(data).toEqual({ numericValue: 123 }) }) }) + + it ("shows error message onBlur when field is required and empty", async () => { + render({ + schema: numericTheNumberSchema, + uischema: numericUISchema, + }) + const input = screen.getByRole("spinbutton") + await userEvent.clear(input) + await userEvent.tab() + expect(await screen.findByText("The Number is required")).not.toBeNull() + }) + + it ("shows units next to text input if set in UI schema", async () => { + render({ + schema: numericPriceSchema, + uischema: numericUSDUISchema, + }) + expect(await screen.findByText("$")).not.toBeNull() + }) }) \ No newline at end of file diff --git a/src/controls/NumericControls/NumericControl.tsx b/src/controls/NumericControls/NumericControl.tsx index dfc7f8a..d322e53 100644 --- a/src/controls/NumericControls/NumericControl.tsx +++ b/src/controls/NumericControls/NumericControl.tsx @@ -10,7 +10,7 @@ export const NumericControl = (props: ControlProps & RendererProps) => { const initialValue = typeof props.schema.default === "number" ? props.schema.default : undefined const rules: Rule[] = [ - { message: props.required ? `${props.label} is required` : "" }, + { required: true, message: `${props.label} is required` }, ] return ( diff --git a/src/controls/NumericControls/NumericSliderControl.test.tsx b/src/controls/NumericControls/NumericSliderControl.test.tsx index a23a0ab..7eb59a7 100644 --- a/src/controls/NumericControls/NumericSliderControl.test.tsx +++ b/src/controls/NumericControls/NumericSliderControl.test.tsx @@ -5,8 +5,9 @@ import { render } from "../../common/test-render" import { JSONSchema } from "json-schema-to-ts" import { numericSliderBasisPointsSchema, - numericSliderFinalGradeSchema, numericSliderUISchema, + numericSliderFinalGradeSchema, + numericSliderPercentageUISchema, numericSliderUISchemaWithRule, } from "../../testSchemas/numericSchema/numericSliderSchema" @@ -82,4 +83,16 @@ describe("NumericSliderControl", () => { expect(data).toEqual({ numericRangeValue: 42.00 }) }) }) + + it ("shows units in tooltip if set in UI schema", async () => { + render({ + schema: numericSliderFinalGradeSchema, + uischema: numericSliderPercentageUISchema, + }) + const slider = screen.getByRole("slider") + expect(screen.queryByText("50%")).toBeNull() + await userEvent.hover(slider) + + expect(screen.queryByText("50%")).not.toBeNull() + }) }) \ No newline at end of file diff --git a/src/controls/NumericControls/NumericSliderControl.tsx b/src/controls/NumericControls/NumericSliderControl.tsx index 2f14efa..bebdc15 100644 --- a/src/controls/NumericControls/NumericSliderControl.tsx +++ b/src/controls/NumericControls/NumericSliderControl.tsx @@ -11,7 +11,7 @@ export const NumericSliderControl = (props: ControlProps & RendererProps) => { const initialValue = typeof props.schema.default === "number" ? props.schema.default : undefined const rules: Rule[] = [ - { message: props.required ? `${props.label} is required` : "" }, + { required: true, message: `${props.label} is required` }, ] return ( diff --git a/src/testSchemas/numberSchema.ts b/src/testSchemas/numberSchema.ts deleted file mode 100644 index 11ce28d..0000000 --- a/src/testSchemas/numberSchema.ts +++ /dev/null @@ -1,218 +0,0 @@ -import { RuleEffect } from "@jsonforms/core" -import { JSONSchema } from "json-schema-to-ts" -import { UISchema } from "../ui-schema" - -export const numberMagnitudeSchema = { - type: "object", - properties: { - magnitude: { - title: "Magnitude", - type: "number", - }, - }, - required: ["magnitude"], -} satisfies JSONSchema - -export const numberTheNumberSchema = { - type: "number", - properties: { - theNumber: { - title: "The Number", - type: "number", - default: 42.42, - }, - }, - required: ["theNumber"], -} satisfies JSONSchema - -export const numberWeightSchema = { - type: "object", - properties: { - weight: { - title: "Weight", - type: "number", - }, - }, -} satisfies JSONSchema - -export const numberPriceSchema = { - type: "object", - properties: { - price: { - title: "Price", - type: "number", - }, - }, - required: ["price"], -} satisfies JSONSchema - -export const numberBasisPointsSchema = { - type: "object", - properties: { - basisPoints: { - title: "Basis Points", - type: "number", - minimum: 0, - maximum: 10000, - multipleOf: 1, - }, - }, -} satisfies JSONSchema - -export const numberTemperatureSchema = { - type: "number", - title: "Today's Temperature", - minimum: -50, - maximum: 150, - default: 70, - multipleOf: 1, -} satisfies JSONSchema - -export const numberHumiditySchema = { - type: "number", - title: "Humidity", - minimum: 0.0, - maximum: 1.0, -} satisfies JSONSchema - -export const numberRelativeChangeSchema = { - type: "number", - title: "Relative Change", - minimum: -1.0, - maximum: 10.0, - default: 0.0, - multipleOf: 0.01, -} satisfies JSONSchema - -export const numberFinalGradeSchema = { - type: "number", - title: "Final Grade", - minimum: 0.0, - maximum: 1.0, - default: 0.5, -} satisfies JSONSchema - - -export const numberDonateNowSchema = { - type: "object", - properties: { - donateNow: { - type: "number", - title: "Donate Now", - minimum: 5.00, - maximum: 1000.00, - default: 20.00, - multipleOf: 5.00, - } - }, - required: ["donateNow"], -} satisfies JSONSchema - - -export const numberMagnitudeUISchema = { - type: "VerticalLayout", - elements: [ - { - type: "Control", - scope: "#/properties/magnitude", - }, - ], -} satisfies UISchema - -export const numberPriceUISchema = { - type: "VerticalLayout", - elements: [ - { - type: "Control", - scope: "#/properties/price", - options: { - addonBefore: "$", - } - }, - ], -} satisfies UISchema - -export const numberTheNumberUISchema = { - type: "VerticalLayout", - elements: [ - { - type: "Control", - scope: "#/properties/theNumber", - }, - ], -} satisfies UISchema - - -export const numberWeightUISchema = { - type: "VerticalLayout", - elements: [ - { - type: "Control", - scope: "#/properties/weight", - }, - ], -} satisfies UISchema - -export const numberBasisPointsUISchema = { - type: "VerticalLayout", - elements: [ - { - type: "Control", - scope: "#/properties/basisPoints", - }, - ], -} satisfies UISchema - - -export const numberPercentageUISchema = { - type: "VerticalLayout", - elements: [ - { - type: "Control", - scope: "#", - options: { - addonAfter: "%", - } - }, - ], -} satisfies UISchema - -export const numberTemperatureUISchema = { - type: "VerticalLayout", - elements: [ - { - type: "Control", - scope: "#", - options: { - addonAfter: "°F", - } - }, - ], -} satisfies UISchema - -export const numberDonateNowUISchema = { - type: "VerticalLayout", - elements: [ - { - type: "Control", - scope: "#/properties/donateNow", - options: { - addonBefore: "$", - } - }, - ], -} satisfies UISchema - -export const numberUISchemaWithRule = { - type: "VerticalLayout", - elements: [ - { - type: "Control", - scope: "#", - rule: { - effect: RuleEffect.HIDE, - condition: {}, - }, - }, - ], -} satisfies UISchema \ No newline at end of file diff --git a/src/testSchemas/numericSchema/numericSliderSchema.ts b/src/testSchemas/numericSchema/numericSliderSchema.ts index 0a9e79d..40cf5f9 100644 --- a/src/testSchemas/numericSchema/numericSliderSchema.ts +++ b/src/testSchemas/numericSchema/numericSliderSchema.ts @@ -25,6 +25,7 @@ export const numericSliderTemperatureSchema = { minimum: -50, maximum: 150, multipleOf: 1, + default: 70, }, }, required: ["numericRangeValue"], @@ -67,6 +68,7 @@ export const numericSliderFinalGradeSchema = { type: "number", minimum: 0.0, maximum: 1.0, + multipleOf: 0.01, default: 0.5, }, }, @@ -82,8 +84,8 @@ export const numericSliderDonateNowSchema = { title: "Donate Now", minimum: 5.00, maximum: 1000.00, - default: 20.00, multipleOf: 5.00, + default: 20.00, } }, required: ["numericRangeValue"], diff --git a/tsconfig.cjs.json b/tsconfig.cjs.json index c08aab8..11f6a11 100644 --- a/tsconfig.cjs.json +++ b/tsconfig.cjs.json @@ -3,7 +3,9 @@ "compilerOptions": { "lib": [ "ES6", - "DOM" + "ES2020", + "DOM", + "DOM.Iterable", ], "target": "ES6", "module": "CommonJS", diff --git a/tsconfig.esm.json b/tsconfig.esm.json index ee1babe..e75f7e6 100644 --- a/tsconfig.esm.json +++ b/tsconfig.esm.json @@ -3,7 +3,8 @@ "compilerOptions": { "lib": [ "ES2022", - "DOM" + "DOM", + "DOM.Iterable", ], "target": "ES2022", "module": "NodeNext", diff --git a/tsconfig.production.json b/tsconfig.production.json index 687039a..1eb9271 100644 --- a/tsconfig.production.json +++ b/tsconfig.production.json @@ -12,13 +12,7 @@ "declarationMap": true, "allowSyntheticDefaultImports": true, - "target": "ES2020", "useDefineForClassFields": true, - "lib": [ - "ES2020", - "DOM", - "DOM.Iterable" - ], "module": "ESNext", "skipLibCheck": true, "esModuleInterop": true,