fix: edge case to ignore parsing very large numbers (#37104)
## Description <ins>Problem</ins> The defaultOptionValueValidation function in select.ts is not properly handling different input values, resulting in inconsistent behavior. <ins>Root cause</ins> This function does not account for edge cases where the input value is a very large number and is resulting in a rounded off number, leading to incorrect validation results. <ins>Solution</ins> This PR changes the behavior to parsing only when required. Fixes #27881 _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.JSONForm" ### 🔍 Cypress test results <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/11517642696> > Commit: d31373a95fbf67429be8ce6a8717d74c3827098c > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=11517642696&attempt=1" target="_blank">Cypress dashboard</a>. > Tags: `@tag.JSONForm` > Spec: > <hr>Fri, 25 Oct 2024 12:16:10 UTC <!-- end of auto-generated comment: Cypress test results --> ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [x] No <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Enhanced type safety for various functions, improving overall reliability. - Streamlined validation logic for option values, allowing for more robust input handling. - **Bug Fixes** - Improved test coverage for `defaultOptionValueValidation`, ensuring accurate handling of both truthy and falsy values. - **Documentation** - Added comments indicating areas for future improvements in the codebase. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
5bca179116
commit
5e46804698
|
|
@ -226,9 +226,7 @@ export const normalizeArrayValue = (data: any[]) => {
|
|||
return data[0];
|
||||
};
|
||||
|
||||
// TODO: Fix this the next time the file is edited
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export const fieldTypeFor = (value: any): FieldType => {
|
||||
export const fieldTypeFor = (value: unknown): FieldType => {
|
||||
const dataType = dataTypeFor(value);
|
||||
const potentialFieldType = DATA_TYPE_POTENTIAL_FIELD[dataType];
|
||||
const subDataType = subDataTypeFor(value);
|
||||
|
|
|
|||
|
|
@ -4,98 +4,120 @@ import type { JSONFormWidgetProps } from "../..";
|
|||
import { defaultOptionValueValidation } from "./select";
|
||||
|
||||
describe(".defaultOptionValueValidation", () => {
|
||||
it("return undefined when input is undefined", () => {
|
||||
const input = undefined;
|
||||
const expectedOutput = {
|
||||
isValid: true,
|
||||
parsed: undefined,
|
||||
messages: [{ name: "", message: "" }],
|
||||
};
|
||||
describe("handling falsey values", () => {
|
||||
it("return undefined when input is undefined", () => {
|
||||
const input = undefined;
|
||||
const expectedOutput = {
|
||||
isValid: true,
|
||||
parsed: undefined,
|
||||
messages: [{ name: "", message: "" }],
|
||||
};
|
||||
|
||||
const response = defaultOptionValueValidation(
|
||||
input,
|
||||
{} as JSONFormWidgetProps,
|
||||
_,
|
||||
);
|
||||
const response = defaultOptionValueValidation(
|
||||
input,
|
||||
{} as JSONFormWidgetProps,
|
||||
_,
|
||||
);
|
||||
|
||||
expect(response).toEqual(expectedOutput);
|
||||
expect(response).toEqual(expectedOutput);
|
||||
});
|
||||
|
||||
it("return null when input is null", () => {
|
||||
const input = null;
|
||||
const expectedOutput = {
|
||||
isValid: true,
|
||||
parsed: null,
|
||||
messages: [{ name: "", message: "" }],
|
||||
};
|
||||
|
||||
const response = defaultOptionValueValidation(
|
||||
input,
|
||||
{} as JSONFormWidgetProps,
|
||||
_,
|
||||
);
|
||||
|
||||
expect(response).toEqual(expectedOutput);
|
||||
});
|
||||
|
||||
it("return empty string with empty string", () => {
|
||||
const input = "";
|
||||
const expectedOutput = {
|
||||
isValid: true,
|
||||
parsed: "",
|
||||
messages: [{ name: "", message: "" }],
|
||||
};
|
||||
|
||||
const response = defaultOptionValueValidation(
|
||||
input,
|
||||
{} as JSONFormWidgetProps,
|
||||
_,
|
||||
);
|
||||
|
||||
expect(response).toEqual(expectedOutput);
|
||||
});
|
||||
});
|
||||
|
||||
it("return null when input is null", () => {
|
||||
const input = null;
|
||||
const expectedOutput = {
|
||||
isValid: true,
|
||||
parsed: null,
|
||||
messages: [{ name: "", message: "" }],
|
||||
};
|
||||
describe("handling truthy values", () => {
|
||||
it("return value with string", () => {
|
||||
const input = "green";
|
||||
const expectedOutput = {
|
||||
isValid: true,
|
||||
parsed: "green",
|
||||
messages: [{ name: "", message: "" }],
|
||||
};
|
||||
|
||||
const response = defaultOptionValueValidation(
|
||||
input,
|
||||
{} as JSONFormWidgetProps,
|
||||
_,
|
||||
);
|
||||
const response = defaultOptionValueValidation(
|
||||
input,
|
||||
{} as JSONFormWidgetProps,
|
||||
_,
|
||||
);
|
||||
|
||||
expect(response).toEqual(expectedOutput);
|
||||
});
|
||||
expect(response).toEqual(expectedOutput);
|
||||
});
|
||||
|
||||
it("return empty string with empty string", () => {
|
||||
const input = "";
|
||||
const expectedOutput = {
|
||||
isValid: true,
|
||||
parsed: "",
|
||||
messages: [{ name: "", message: "" }],
|
||||
};
|
||||
|
||||
const response = defaultOptionValueValidation(
|
||||
input,
|
||||
{} as JSONFormWidgetProps,
|
||||
_,
|
||||
);
|
||||
|
||||
expect(response).toEqual(expectedOutput);
|
||||
});
|
||||
|
||||
it("return value with string", () => {
|
||||
const input = "green";
|
||||
const expectedOutput = {
|
||||
isValid: true,
|
||||
parsed: "green",
|
||||
messages: [{ name: "", message: "" }],
|
||||
};
|
||||
|
||||
const response = defaultOptionValueValidation(
|
||||
input,
|
||||
{} as JSONFormWidgetProps,
|
||||
_,
|
||||
);
|
||||
|
||||
expect(response).toEqual(expectedOutput);
|
||||
});
|
||||
|
||||
it("return value with stringified json", () => {
|
||||
const input = `
|
||||
it("return value with stringified json", () => {
|
||||
const input = `
|
||||
{
|
||||
"label": "green",
|
||||
"value": "green"
|
||||
}
|
||||
`;
|
||||
|
||||
const expectedOutput = {
|
||||
isValid: true,
|
||||
parsed: {
|
||||
label: "green",
|
||||
value: "green",
|
||||
},
|
||||
messages: [{ name: "", message: "" }],
|
||||
};
|
||||
const expectedOutput = {
|
||||
isValid: true,
|
||||
parsed: {
|
||||
label: "green",
|
||||
value: "green",
|
||||
},
|
||||
messages: [{ name: "", message: "" }],
|
||||
};
|
||||
|
||||
const response = defaultOptionValueValidation(
|
||||
input,
|
||||
{} as JSONFormWidgetProps,
|
||||
_,
|
||||
);
|
||||
const response = defaultOptionValueValidation(
|
||||
input,
|
||||
{} as JSONFormWidgetProps,
|
||||
_,
|
||||
);
|
||||
|
||||
expect(response).toEqual(expectedOutput);
|
||||
expect(response).toEqual(expectedOutput);
|
||||
});
|
||||
|
||||
it("Edge Case: For very long numbers passed as string, don't parse it as number", () => {
|
||||
const input =
|
||||
"123456789012345678901234567890123456789012345678901234567890";
|
||||
const expectedOutput = {
|
||||
isValid: true,
|
||||
parsed: "123456789012345678901234567890123456789012345678901234567890",
|
||||
messages: [{ name: "", message: "" }],
|
||||
};
|
||||
|
||||
const response = defaultOptionValueValidation(
|
||||
input,
|
||||
{} as JSONFormWidgetProps,
|
||||
_,
|
||||
);
|
||||
|
||||
expect(response).toEqual(expectedOutput);
|
||||
});
|
||||
});
|
||||
|
||||
it("should return isValid false with invalid values", () => {
|
||||
|
|
|
|||
|
|
@ -7,21 +7,13 @@ import type { ValidationResponse } from "constants/WidgetValidation";
|
|||
import { ValidationTypes } from "constants/WidgetValidation";
|
||||
import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory";
|
||||
import { AutocompleteDataType } from "utils/autocomplete/AutocompleteDataType";
|
||||
import type { LoDashStatic } from "lodash";
|
||||
|
||||
export function defaultOptionValueValidation(
|
||||
inputValue: unknown,
|
||||
value: unknown,
|
||||
props: JSONFormWidgetProps,
|
||||
// TODO: Fix this the next time the file is edited
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
_: any,
|
||||
_: LoDashStatic,
|
||||
): ValidationResponse {
|
||||
const DEFAULT_ERROR_MESSAGE = {
|
||||
name: "TypeError",
|
||||
message:
|
||||
'value should match: string | { "label": "label1", "value": "value1" }',
|
||||
};
|
||||
let value = inputValue;
|
||||
|
||||
const hasLabelValueProperties = (
|
||||
// TODO: Fix this the next time the file is edited
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
|
@ -38,22 +30,7 @@ export function defaultOptionValueValidation(
|
|||
|
||||
// If input value is empty string then we can fairly assume that the input
|
||||
// was cleared out and can be treated as undefined.
|
||||
if (inputValue === undefined || inputValue === null || inputValue === "") {
|
||||
return {
|
||||
isValid: true,
|
||||
parsed: inputValue,
|
||||
messages: [{ name: "", message: "" }],
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof inputValue === "string") {
|
||||
try {
|
||||
value = JSON.parse(inputValue);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
if (_.isString(value) || _.isFinite(value)) {
|
||||
// When value is "", "green", 444
|
||||
if (value === undefined || value === null || value === "") {
|
||||
return {
|
||||
isValid: true,
|
||||
parsed: value,
|
||||
|
|
@ -61,8 +38,22 @@ export function defaultOptionValueValidation(
|
|||
};
|
||||
}
|
||||
|
||||
if (hasLabelValueProperties(value)) {
|
||||
// When value is {label: "green", value: "green"}
|
||||
if (typeof value === "string") {
|
||||
try {
|
||||
const parsedValue = JSON.parse(value);
|
||||
|
||||
if (_.isObject(parsedValue)) {
|
||||
value = parsedValue;
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
if (
|
||||
_.isString(value) ||
|
||||
_.isFinite(value) ||
|
||||
hasLabelValueProperties(value)
|
||||
) {
|
||||
// When value is "", "green", 444
|
||||
return {
|
||||
isValid: true,
|
||||
parsed: value,
|
||||
|
|
@ -73,7 +64,13 @@ export function defaultOptionValueValidation(
|
|||
return {
|
||||
isValid: false,
|
||||
parsed: {},
|
||||
messages: [DEFAULT_ERROR_MESSAGE],
|
||||
messages: [
|
||||
{
|
||||
name: "TypeError",
|
||||
message:
|
||||
'value should match: string | { "label": "label1", "value": "value1" }',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user