From 2d645b7e8d960f2e3709df695b64eaaf8dcdb94e Mon Sep 17 00:00:00 2001 From: Vicky Bansal <67091118+vicky-primathon@users.noreply.github.com> Date: Thu, 30 Dec 2021 14:08:40 +0530 Subject: [PATCH] fix: disable submit button when date is out of bounds (#9552) * disable submit button when date is out of bounds * Remove comment from derived.js function as comments are not allowed for parsing * Fix table client side search cypress test * validate date again min/max irrespective of isRequired property --- .../Binding/Table_ClientSide_Search_spec.js | 3 +- .../DatePickerWidget2/widget/derived.js | 15 ++++ .../DatePickerWidget2/widget/derived.test.js | 83 +++++++++++++++++++ .../DatePickerWidget2/widget/index.tsx | 3 +- .../widget/parseDerivedProperties.ts | 36 ++++++++ 5 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 app/client/src/widgets/DatePickerWidget2/widget/derived.js create mode 100644 app/client/src/widgets/DatePickerWidget2/widget/derived.test.js create mode 100644 app/client/src/widgets/DatePickerWidget2/widget/parseDerivedProperties.ts diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Binding/Table_ClientSide_Search_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Binding/Table_ClientSide_Search_spec.js index 7d8b576746..3b899b814f 100644 --- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Binding/Table_ClientSide_Search_spec.js +++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Binding/Table_ClientSide_Search_spec.js @@ -6,8 +6,9 @@ describe("Test Create Api and Bind to Table widget", function() { }); it("Validate onSearchTextChanged function is called when configured for search text", function() { + cy.wait(5000); // input text in search bar - cy.get(".t--widget-tablewidget .t--search-input") + cy.get(".t--widget-tablewidget .t--search-input input") .first() .type("2"); cy.wait(5000); diff --git a/app/client/src/widgets/DatePickerWidget2/widget/derived.js b/app/client/src/widgets/DatePickerWidget2/widget/derived.js new file mode 100644 index 0000000000..cc379204f7 --- /dev/null +++ b/app/client/src/widgets/DatePickerWidget2/widget/derived.js @@ -0,0 +1,15 @@ +/* eslint-disable @typescript-eslint/no-unused-vars*/ +export default { + isValidDate: (props, moment, _) => { + const minDate = new Date(props.minDate); + const maxDate = new Date(props.maxDate); + const selectedDate = + props.selectedDate !== "" + ? moment(new Date(props.selectedDate)) + : props.selectedDate; + return !!selectedDate + ? selectedDate.isBetween(minDate, maxDate) + : !props.isRequired; + }, + // +}; diff --git a/app/client/src/widgets/DatePickerWidget2/widget/derived.test.js b/app/client/src/widgets/DatePickerWidget2/widget/derived.test.js new file mode 100644 index 0000000000..d8a1d13f72 --- /dev/null +++ b/app/client/src/widgets/DatePickerWidget2/widget/derived.test.js @@ -0,0 +1,83 @@ +import derivedProperty from "./derived"; +import moment from "moment"; +import _ from "lodash"; + +describe("Validates Derived Properties", () => { + it("selectedDate is between min and max dates", () => { + const { isValidDate } = derivedProperty; + const input = { + isRequired: true, + maxDate: "2121-12-31T18:29:00.000Z", + minDate: "1920-12-31T18:30:00.000Z", + selectedDate: "2021-12-01T05:49:24.753Z", + }; + + let result = isValidDate(input, moment, _); + expect(result).toStrictEqual(true); + }); + + it("selectedDate is out of bounds", () => { + const { isValidDate } = derivedProperty; + const input = { + isRequired: true, + maxDate: "2021-12-31T18:29:00.000Z", + minDate: "1920-12-31T18:30:00.000Z", + selectedDate: "2022-12-01T05:49:24.753Z", + }; + + let result = isValidDate(input, moment, _); + expect(result).toStrictEqual(false); + }); + + it("isRequired is enabled and date is not selected", () => { + const { isValidDate } = derivedProperty; + const input = { + isRequired: true, + maxDate: "2121-12-31T18:29:00.000Z", + minDate: "1920-12-31T18:30:00.000Z", + selectedDate: "", + }; + + let result = isValidDate(input, moment, _); + expect(result).toStrictEqual(false); + }); + + it("isRequired is disabled and date is selected", () => { + const { isValidDate } = derivedProperty; + const input = { + isRequired: false, + maxDate: "2121-12-31T18:29:00.000Z", + minDate: "1920-12-31T18:30:00.000Z", + selectedDate: "2021-12-01T05:49:24.753Z", + }; + + let result = isValidDate(input, moment, _); + expect(result).toStrictEqual(true); + }); + + it("isRequired is disabled and date is not selected", () => { + const { isValidDate } = derivedProperty; + const input = { + isRequired: false, + maxDate: "2121-12-31T18:29:00.000Z", + minDate: "1920-12-31T18:30:00.000Z", + selectedDate: "", + }; + + let result = isValidDate(input, moment, _); + expect(result).toStrictEqual(true); + }); + + it("isRequired is disabled and date is not between min and max", () => { + const { isValidDate } = derivedProperty; + const input = { + isRequired: false, + maxDate: "2121-12-31T18:29:00.000Z", + minDate: "1920-12-31T18:30:00.000Z", + selectedDate: "2122-12-31T18:29:00.000Z", + }; + + let result = isValidDate(input, moment, _); + expect(result).toStrictEqual(false); + }); +}); diff --git a/app/client/src/widgets/DatePickerWidget2/widget/index.tsx b/app/client/src/widgets/DatePickerWidget2/widget/index.tsx index e18d04ac43..83652f2435 100644 --- a/app/client/src/widgets/DatePickerWidget2/widget/index.tsx +++ b/app/client/src/widgets/DatePickerWidget2/widget/index.tsx @@ -9,6 +9,7 @@ import { DerivedPropertiesMap } from "utils/WidgetFactory"; import { AutocompleteDataType } from "utils/autocomplete/TernServer"; import moment from "moment"; +import derivedProperties from "./parseDerivedProperties"; import { DatePickerType, TimePrecision } from "../constants"; function allowedRange(value: any) { @@ -294,7 +295,7 @@ class DatePickerWidget extends BaseWidget { static getDerivedPropertiesMap(): DerivedPropertiesMap { return { - isValid: `{{ this.isRequired ? !!this.selectedDate : true }}`, + isValid: `{{(()=>{${derivedProperties.isValidDate}})()}}`, selectedDate: `{{ this.value ? moment(this.value).toISOString() : "" }}`, formattedDate: `{{ this.value ? moment(this.value).format(this.dateFormat) : "" }}`, }; diff --git a/app/client/src/widgets/DatePickerWidget2/widget/parseDerivedProperties.ts b/app/client/src/widgets/DatePickerWidget2/widget/parseDerivedProperties.ts new file mode 100644 index 0000000000..4ea7d1a9ca --- /dev/null +++ b/app/client/src/widgets/DatePickerWidget2/widget/parseDerivedProperties.ts @@ -0,0 +1,36 @@ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +//@ts-ignore +import widgetPropertyFns from "!!raw-loader!./derived.js"; + +// TODO(abhinav): +// Add unit test cases +// Handle edge cases +// Error out on wrong values +const derivedProperties: any = {}; +// const regex = /(\w+):\s?\(props\)\s?=>\s?{([\w\W]*?)},/gim; +const regex = /(\w+):\s?\(props, moment, _\)\s?=>\s?{([\w\W\n]*?)},\n?\s+?\/\//gim; + +let m; + +while ((m = regex.exec(widgetPropertyFns)) !== null) { + // This is necessary to avoid infinite loops with zero-width matches + if (m.index === regex.lastIndex) { + regex.lastIndex++; + } + + let key = ""; + // The result can be accessed through the `m`-variable. + m.forEach((match, groupIndex) => { + if (groupIndex === 1) { + key = match; + } + if (groupIndex === 2) { + derivedProperties[key] = match + .trim() + .replace(/\n/g, "") + .replace(/props\./g, "this."); + } + }); +} + +export default derivedProperties;