From 5625784829397d3acbf1b50bc4105f21542e0f3b Mon Sep 17 00:00:00 2001 From: Rishabh Rathod Date: Sat, 25 Jun 2022 11:00:54 +0530 Subject: [PATCH] fix: reset meta to default value (#14468) * fix: [WIP] reset meta to default value * refactor * fix reset child widget and type in metaReducer * Fix type and refactor test * fix multiselect click * Add jest test for reset widget action * Add cypress test * Add comments * Add more cases as per comment * remove `only` from test case * Add default value case of array with values * MultiSelect spec fix * fix currencyInput reset * refactor test code suggested in comments * fix type * fix more type * fix cypress test Co-authored-by: Aishwarya UR --- .../cypress/fixtures/multiSelectDsl.json | 712 ++++++++++-------- .../Widgets/AllInputWidgets_spec.js | 24 +- .../Widgets/MultiSelect_spec copy.js | 118 --- .../Widgets/MultiSelect_spec2.js | 232 ++++++ app/client/cypress/locators/WidgetLocators.ts | 20 + .../cypress/support/Objects/CommonLocators.ts | 4 +- .../cypress/support/Pages/AggregateHelper.ts | 42 +- .../cypress/support/Pages/DeployModeHelper.ts | 4 +- app/client/src/actions/metaActions.ts | 10 +- .../entityReducers/metaReducer/index.ts | 35 +- .../entityReducers/metaReducer/test.ts | 66 +- .../ActionExecution/ResetWidgetActionSaga.ts | 14 +- app/client/src/sagas/EvaluationsSaga.ts | 2 +- app/client/src/sagas/WidgetOperationSagas.tsx | 15 +- app/client/src/sagas/WidgetOperationUtils.ts | 57 +- app/client/src/sagas/WidgetSelectionSagas.ts | 4 +- .../CurrencyInputWidget/widget/index.tsx | 2 +- .../MultiSelectWidgetV2/widget/index.tsx | 1 - 18 files changed, 877 insertions(+), 485 deletions(-) delete mode 100644 app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Widgets/MultiSelect_spec copy.js create mode 100644 app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Widgets/MultiSelect_spec2.js create mode 100644 app/client/cypress/locators/WidgetLocators.ts diff --git a/app/client/cypress/fixtures/multiSelectDsl.json b/app/client/cypress/fixtures/multiSelectDsl.json index 598b0027f6..507368c3e4 100644 --- a/app/client/cypress/fixtures/multiSelectDsl.json +++ b/app/client/cypress/fixtures/multiSelectDsl.json @@ -1,312 +1,432 @@ { - "dsl": { - "widgetName": "MainContainer", - "backgroundColor": "none", - "rightColumn": 966, - "snapColumns": 64, - "detachFromLayout": true, - "widgetId": "0", +"dsl": { + "widgetName": "MainContainer", + "backgroundColor": "none", + "rightColumn": 966, + "snapColumns": 64, + "detachFromLayout": true, + "widgetId": "0", + "topRow": 0, + "bottomRow": 5016, + "containerStyle": "none", + "snapRows": 125, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": true, + "version": 59, + "minHeight": 360, + "parentColumnSpace": 1, + "dynamicBindingPathList": [], + "leftColumn": 0, + "children": [ + { + "labelTextSize": "0.875rem", + "boxShadow": "none", + "backgroundColor": "#FFFFFF", + "widgetName": "Container3", + "rightColumn": 60, + "orientation": "VERTICAL", + "snapColumns": 16, + "widgetId": "jaftzrmtin", + "containerStyle": "card", "topRow": 0, - "bottomRow": 5016, - "containerStyle": "none", - "snapRows": 125, - "parentRowSpace": 1, - "type": "CANVAS_WIDGET", - "canExtend": true, - "version": 29, - "minHeight": 360, - "parentColumnSpace": 1, + "bottomRow": 80, + "parentRowSpace": 38, + "isVisible": true, + "type": "CONTAINER_WIDGET", + "version": 1, + "isLoading": false, + "parentColumnSpace": 75.25, "dynamicBindingPathList": [], "leftColumn": 0, + "borderRadius": "0px", "children": [ { - "backgroundColor": "#FFFFFF", - "widgetName": "Container3", - "rightColumn": 60, - "orientation": "VERTICAL", - "snapColumns": 16, - "widgetId": "jaftzrmtin", - "containerStyle": "card", + "boxShadow": "none", + "widgetName": "7hf8kkvvgv", + "topRow": 0, + "bottomRow": 790, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": false, + "minHeight": 800, + "parentColumnSpace": 1, + "dynamicTriggerPathList": [], + "leftColumn": 0, + "dynamicBindingPathList": [], + "children": [ + { + "labelTextSize": "0.875rem", + "boxShadow": "none", + "widgetName": "Text1", + "rightColumn": 10, + "dynamicPropertyPathList": [], + "widgetId": "4d8d2eh4xg", "topRow": 0, - "bottomRow": 80, + "bottomRow": 3, "parentRowSpace": 38, "isVisible": true, - "type": "CONTAINER_WIDGET", - "version": 1, + "type": "TEXT_WIDGET", + "parentId": "hjiybwqair", "isLoading": false, - "parentColumnSpace": 75.25, + "parentColumnSpace": 71.75, + "overflow": "SCROLL", + "fontFamily": "System Default", "dynamicBindingPathList": [], + "leftColumn": 1, + "borderRadius": "0px", + "text": "Test text", + "textStyle": "HEADING" + }, + { + "labelTextSize": "0.875rem", + "isRequired": false, + "boxShadow": "none", + "widgetName": "Input1", + "rightColumn": 20, + "widgetId": "i9cuq42zmc", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "topRow": 4, + "bottomRow": 8, + "parentRowSpace": 38, + "isVisible": true, + "label": "", + "type": "INPUT_WIDGET_V2", + "version": 1, + "parentId": "e3tq9qwta6", + "isLoading": false, + "parentColumnSpace": 71.75, + "resetOnSubmit": false, "leftColumn": 0, - "children": [ - { - "backgroundColor": "transparent", - "widgetName": "7hf8kkvvgv", - "rightColumn": 4816, - "orientation": "VERTICAL", - "snapColumns": 16, - "detachFromLayout": true, - "widgetId": "e3tq9qwta6", - "containerStyle": "none", - "topRow": 0, - "bottomRow": 2128, - "parentRowSpace": 1, - "isVisible": true, - "type": "CANVAS_WIDGET", - "canExtend": false, - "version": 1, - "isLoading": false, - "minHeight": 800, - "parentColumnSpace": 1, - "dynamicTriggerPathList": [], - "leftColumn": 0, - "dynamicBindingPathList": [], - "children": [ - { - "widgetName": "Text1", - "rightColumn": 10, - "widgetId": "4d8d2eh4xg", - "dynamicPropertyPathList": [], - "topRow": 0, - "bottomRow": 3, - "parentRowSpace": 38, - "isVisible": true, - "type": "TEXT_WIDGET", - "dynamicBindingPathList": [], - "shouldScroll": true, - "parentId": "hjiybwqair", - "isLoading": false, - "parentColumnSpace": 71.75, - "leftColumn": 1, - "text": "Test text", - "textStyle": "HEADING" - }, - { - "isRequired": false, - "widgetName": "Input1", - "rightColumn": 20, - "widgetId": "i9cuq42zmc", - "topRow": 4, - "bottomRow": 8, - "parentRowSpace": 38, - "isVisible": true, - "label": "", - "type": "INPUT_WIDGET_V2", - "version": 1, - "parentId": "e3tq9qwta6", - "isLoading": false, - "parentColumnSpace": 71.75, - "resetOnSubmit": false, - "leftColumn": 0, - "dynamicBindingPathList": [], - "inputType": "TEXT", - "isDisabled": false - }, - { - "isRequired": false, - "widgetName": "Dropdown1", - "rightColumn": 60, - "isFilterable": true, - "widgetId": "nl5sy9cuaa", - "topRow": 4, - "bottomRow": 8, - "parentRowSpace": 38, - "isVisible": true, - "label": "", - "type": "SELECT_WIDGET", - "version": 1, - "parentId": "e3tq9qwta6", - "isLoading": false, - "parentColumnSpace": 71.75, - "leftColumn": 40, - "dynamicBindingPathList": [], - "options": "", - "isDisabled": false - }, - { - "widgetName": "Button1", - "rightColumn": 12, - "isDefaultClickDisabled": true, - "widgetId": "gn6ug210ef", - "buttonStyle": "PRIMARY_BUTTON", - "topRow": 16, - "bottomRow": 20, - "parentRowSpace": 38, - "isVisible": true, - "type": "BUTTON_WIDGET", - "version": 1, - "parentId": "e3tq9qwta6", - "isLoading": false, - "parentColumnSpace": 71.75, - "leftColumn": 4, - "dynamicBindingPathList": [], - "text": "Submit", - "isDisabled": false - }, - { - "isRequired": false, - "widgetName": "Checkbox1", - "rightColumn": 52, - "widgetId": "szjhneuog5", - "topRow": 16, - "bottomRow": 20, - "parentRowSpace": 38, - "isVisible": true, - "label": "Label", - "type": "CHECKBOX_WIDGET", - "version": 1, - "parentId": "e3tq9qwta6", - "isLoading": false, - "parentColumnSpace": 71.75, - "leftColumn": 40, - "dynamicBindingPathList": [], - "defaultCheckedState": true, - "isDisabled": false - }, - { - "widgetName": "Switch1", - "rightColumn": 52, - "widgetId": "szjhneuog9", - "topRow": 72, - "bottomRow": 76, - "parentRowSpace": 38, - "isVisible": true, - "label": "Switch", - "type": "SWITCH_WIDGET", - "defaultSwitchState": true, - "version": 1, - "parentId": "e3tq9qwta6", - "isLoading": false, - "parentColumnSpace": 71.75, - "leftColumn": 40, - "dynamicBindingPathList": [], - "isDisabled": false - }, - { - "isRequired": false, - "widgetName": "RadioGroup1", - "rightColumn": 12, - "widgetId": "nb2usgp3hv", - "topRow": 28, - "bottomRow": 36, - "parentRowSpace": 38, - "isVisible": true, - "label": "", - "type": "RADIO_GROUP_WIDGET", - "version": 1, - "parentId": "e3tq9qwta6", - "isLoading": false, - "defaultOptionValue": "1", - "parentColumnSpace": 71.75, - "leftColumn": 0, - "dynamicBindingPathList": [], - "options": [ - { - "label": "Male", - "value": "M" - }, - { - "label": "Female", - "value": "F" - } - ], - "isDisabled": false - }, - { - "widgetName": "DatePicker1", - "defaultDate": "2020-06-03T12:05:44.699+05:30", - "rightColumn": 60, - "dateFormat": "DD/MM/YYYY", - "widgetId": "kyrvcdcm4e", - "topRow": 28, - "bottomRow": 32, - "parentRowSpace": 38, - "isVisible": true, - "datePickerType": "DATE_PICKER", - "label": "", - "type": "DATE_PICKER_WIDGET", - "version": 1, - "parentId": "e3tq9qwta6", - "isLoading": false, - "parentColumnSpace": 71.75, - "dynamicTriggerPathList": [ - { - "key": "onDateSelected" - } - ], - "leftColumn": 40, - "dynamicBindingPathList": [], - "isDisabled": false, - "onDateSelected": "{{showModal()}}" - }, - { - "isRequired": false, - "widgetName": "FilePicker1", - "rightColumn": 56, - "isDefaultClickDisabled": true, - "widgetId": "ca22py6vlv", - "topRow": 44, - "bottomRow": 48, - "parentRowSpace": 38, - "isVisible": true, - "label": "Select Files", - "allowedFileTypes": [], - "type": "FILE_PICKER_WIDGET", - "version": 1, - "parentId": "e3tq9qwta6", - "isLoading": false, - "parentColumnSpace": 67.1171875, - "leftColumn": 40, - "dynamicBindingPathList": [], - "files": [], - "isDisabled": false - }, - { - "widgetName": "RichTextEditor1", - "rightColumn": 32, - "isDefaultClickDisabled": true, - "widgetId": "2uvezzlkn5", - "topRow": 44, - "bottomRow": 64, - "parentRowSpace": 38, - "isVisible": true, - "type": "RICH_TEXT_EDITOR_WIDGET", - "version": 1, - "parentId": "e3tq9qwta6", - "isLoading": false, - "parentColumnSpace": 67.1171875, - "leftColumn": 0, - "dynamicBindingPathList": [], - "defaultText": "", - "inputType": "html", - "isDisabled": false - }, - { - "isRequired": false, - "widgetName": "MultiSelect2", - "rightColumn": 62, - "widgetId": "p6qkmj8uo1", - "topRow": 49, - "bottomRow": 60, - "parentRowSpace": 10, - "isVisible": true, - "label": "", - "type": "MULTI_SELECT_WIDGET_V2", - "version": 1, - "parentId": "e3tq9qwta6", - "isLoading": false, - "defaultOptionValue": [], - "parentColumnSpace": 13.662109375, - "dynamicTriggerPathList": [], - "leftColumn": 37, - "dynamicBindingPathList": [], - "options": "", - "placeholderText": "select option(s)", - "isDisabled": false - } - ] - } - ] + "dynamicBindingPathList": [{ "key": "accentColor" }], + "borderRadius": "0px", + "inputType": "TEXT", + "isDisabled": false + }, + { + "labelTextSize": "0.875rem", + "isRequired": false, + "boxShadow": "none", + "widgetName": "Dropdown1", + "rightColumn": 60, + "isFilterable": true, + "widgetId": "nl5sy9cuaa", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "topRow": 4, + "bottomRow": 8, + "parentRowSpace": 38, + "isVisible": true, + "label": "", + "type": "SELECT_WIDGET", + "version": 1, + "parentId": "e3tq9qwta6", + "isLoading": false, + "parentColumnSpace": 71.75, + "leftColumn": 40, + "dynamicBindingPathList": [{ "key": "accentColor" }], + "borderRadius": "0px", + "options": "", + "isDisabled": false + }, + { + "labelTextSize": "0.875rem", + "boxShadow": "none", + "widgetName": "Button1", + "rightColumn": 12, + "isDefaultClickDisabled": true, + "buttonColor": "#03B365", + "widgetId": "gn6ug210ef", + "topRow": 16, + "bottomRow": 20, + "parentRowSpace": 38, + "isVisible": true, + "type": "BUTTON_WIDGET", + "version": 1, + "recaptchaType": "V3", + "parentId": "e3tq9qwta6", + "isLoading": false, + "parentColumnSpace": 71.75, + "leftColumn": 4, + "dynamicBindingPathList": [], + "borderRadius": "0px", + "buttonVariant": "PRIMARY", + "text": "Submit", + "isDisabled": false + }, + { + "boxShadow": "none", + "widgetName": "Checkbox1", + "topRow": 16, + "bottomRow": 20, + "parentRowSpace": 38, + "type": "CHECKBOX_WIDGET", + "alignWidget": "LEFT", + "parentColumnSpace": 71.75, + "leftColumn": 40, + "dynamicBindingPathList": [], + "labelPosition": "Right", + "isDisabled": false, + "labelTextSize": "0.875rem", + "isRequired": false, + "rightColumn": 52, + "widgetId": "szjhneuog5", + "accentColor": "#03B365", + "isVisible": true, + "label": "Label", + "version": 1, + "parentId": "e3tq9qwta6", + "isLoading": false, + "borderRadius": "0px", + "defaultCheckedState": true + }, + { + "labelTextSize": "0.875rem", + "boxShadow": "none", + "widgetName": "Switch1", + "rightColumn": 52, + "widgetId": "szjhneuog9", + "accentColor": "#03B365", + "topRow": 73, + "bottomRow": 77, + "parentRowSpace": 38, + "isVisible": true, + "label": "Switch", + "type": "SWITCH_WIDGET", + "defaultSwitchState": true, + "version": 1, + "parentId": "e3tq9qwta6", + "alignWidget": "LEFT", + "isLoading": false, + "parentColumnSpace": 71.75, + "leftColumn": 40, + "dynamicBindingPathList": [], + "borderRadius": "0px", + "labelPosition": "Right", + "isDisabled": false + }, + { + "labelTextSize": "0.875rem", + "isRequired": false, + "boxShadow": "none", + "widgetName": "RadioGroup1", + "rightColumn": 12, + "widgetId": "nb2usgp3hv", + "topRow": 28, + "bottomRow": 36, + "parentRowSpace": 38, + "isVisible": true, + "label": "", + "type": "RADIO_GROUP_WIDGET", + "version": 1, + "parentId": "e3tq9qwta6", + "isLoading": false, + "defaultOptionValue": "1", + "parentColumnSpace": 71.75, + "leftColumn": 0, + "dynamicBindingPathList": [], + "borderRadius": "0px", + "options": [ + { "label": "Male", "value": "M" }, + { "label": "Female", "value": "F" } + ], + "isDisabled": false, + "alignment": "left" + }, + { + "boxShadow": "none", + "widgetName": "DatePicker1", + "dateFormat": "DD/MM/YYYY", + "topRow": 28, + "bottomRow": 32, + "parentRowSpace": 38, + "type": "DATE_PICKER_WIDGET", + "parentColumnSpace": 71.75, + "dynamicTriggerPathList": [ + { "key": "onDateSelected" } + ], + "leftColumn": 40, + "dynamicBindingPathList": [], + "isDisabled": false, + "onDateSelected": "{{showModal()}}", + "labelTextSize": "0.875rem", + "defaultDate": "2020-06-03T12:05:44.699+05:30", + "rightColumn": 60, + "widgetId": "kyrvcdcm4e", + "isVisible": true, + "datePickerType": "DATE_PICKER", + "label": "", + "version": 1, + "parentId": "e3tq9qwta6", + "isLoading": false, + "borderRadius": "0px" + }, + { + "labelTextSize": "0.875rem", + "isRequired": false, + "boxShadow": "none", + "widgetName": "FilePicker1", + "rightColumn": 56, + "isDefaultClickDisabled": true, + "widgetId": "ca22py6vlv", + "topRow": 44, + "bottomRow": 48, + "parentRowSpace": 38, + "isVisible": true, + "label": "Select Files", + "allowedFileTypes": [], + "type": "FILE_PICKER_WIDGET", + "version": 1, + "parentId": "e3tq9qwta6", + "isLoading": false, + "parentColumnSpace": 67.1171875, + "leftColumn": 40, + "dynamicBindingPathList": [], + "borderRadius": "0px", + "files": [], + "isDisabled": false + }, + { + "labelTextSize": "0.875rem", + "boxShadow": "none", + "widgetName": "RichTextEditor1", + "rightColumn": 32, + "isDefaultClickDisabled": true, + "widgetId": "2uvezzlkn5", + "topRow": 44, + "bottomRow": 64, + "parentRowSpace": 38, + "isVisible": true, + "type": "RICH_TEXT_EDITOR_WIDGET", + "version": 1, + "parentId": "e3tq9qwta6", + "isLoading": false, + "parentColumnSpace": 67.1171875, + "leftColumn": 0, + "dynamicBindingPathList": [], + "borderRadius": "0px", + "defaultText": "", + "inputType": "html", + "isDisabled": false + }, + { + "boxShadow": "none", + "widgetName": "MultiSelect2", + "topRow": 49, + "bottomRow": 60, + "parentRowSpace": 10, + "type": "MULTI_SELECT_WIDGET_V2", + "defaultOptionValue": "", + "parentColumnSpace": 13.662109375, + "dynamicTriggerPathList": [], + "leftColumn": 37, + "dynamicBindingPathList": [{ "key": "accentColor" }], + "options": "", + "placeholderText": "", + "isDisabled": false, + "labelTextSize": "0.875rem", + "isRequired": false, + "rightColumn": 62, + "widgetId": "p6qkmj8uo1", + "accentColor": "{{appsmith.theme.colors.primaryColor}}", + "isVisible": true, + "label": "", + "version": 1, + "parentId": "e3tq9qwta6", + "isLoading": false, + "borderRadius": "0px" + }, + { + "boxShadow": "none", + "widgetName": "Button2", + "onClick": "{{resetWidget('MultiSelect2')}}", + "buttonColor": "{{appsmith.theme.colors.primaryColor}}", + "dynamicPropertyPathList": [{ "key": "onClick" }], + "displayName": "Button", + "iconSVG": "/static/media/icon.cca02633.svg", + "topRow": 68, + "bottomRow": 72, + "parentRowSpace": 10, + "type": "BUTTON_WIDGET", + "hideCard": false, + "animateLoading": true, + "parentColumnSpace": 18.49609375, + "dynamicTriggerPathList": [{ "key": "onClick" }], + "leftColumn": 41, + "dynamicBindingPathList": [ + { "key": "buttonColor" }, + { "key": "borderRadius" } + ], + "text": "Reset MultiSelect", + "isDisabled": false, + "key": "sv7prcomh7", + "isDeprecated": false, + "rightColumn": 58, + "isDefaultClickDisabled": true, + "widgetId": "tzstqq5xjt", + "isVisible": true, + "recaptchaType": "V3", + "version": 1, + "parentId": "e3tq9qwta6", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "buttonVariant": "PRIMARY", + "placement": "CENTER" + }, + { + "widgetName": "Text2", + "displayName": "Text", + "iconSVG": "/static/media/icon.97c59b52.svg", + "topRow": 60, + "bottomRow": 68, + "parentRowSpace": 10, + "type": "TEXT_WIDGET", + "hideCard": false, + "animateLoading": true, + "overflow": "NONE", + "fontFamily": "{{appsmith.theme.fontFamily.appFont}}", + "parentColumnSpace": 18.49609375, + "dynamicTriggerPathList": [], + "leftColumn": 37, + "dynamicBindingPathList": [ + { "key": "fontFamily" }, + { "key": "borderRadius" }, + { "key": "text" } + ], + "shouldTruncate": false, + "truncateButtonColor": "#FFC13D", + "text": "{{MultiSelect2.selectedOptionValues.toString()}}", + "key": "a4y7w4uxvg", + "isDeprecated": false, + "rightColumn": 62, + "textAlign": "LEFT", + "widgetId": "6mabocqffh", + "isVisible": true, + "fontStyle": "BOLD", + "textColor": "#231F20", + "version": 1, + "parentId": "e3tq9qwta6", + "renderMode": "CANVAS", + "isLoading": false, + "borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}", + "fontSize": "1rem" + } + ], + "labelTextSize": "0.875rem", + "backgroundColor": "transparent", + "rightColumn": 4816, + "orientation": "VERTICAL", + "snapColumns": 16, + "detachFromLayout": true, + "widgetId": "e3tq9qwta6", + "containerStyle": "none", + "isVisible": true, + "version": 1, + "isLoading": false, + "borderRadius": "0px" } ] + } + ] } } \ No newline at end of file diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Widgets/AllInputWidgets_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Widgets/AllInputWidgets_spec.js index 6f7841a7cd..dedf4dded1 100644 --- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Widgets/AllInputWidgets_spec.js +++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Widgets/AllInputWidgets_spec.js @@ -1,24 +1,12 @@ const explorer = require("../../../../locators/explorerlocators.json"); const testdata = require("../../../../fixtures/testdata.json"); const apiwidget = require("../../../../locators/apiWidgetslocator.json"); -import apiEditor from "../../../../locators/ApiEditor"; - -const WIDGET = { - INPUT_WIDGET_V2: "inputwidgetv2", - TEXT: "textwidget", - PHONE_INPUT_WIDGET: "phoneinputwidget", - CURRENCY_INPUT_WIDGET: "currencyinputwidget", - BUTTON_WIDGET: "buttonwidget", -}; - -const PROPERTY_SELECTOR = { - onClick: ".t--property-control-onclick", - onSubmit: ".t--property-control-onsubmit", - text: ".t--property-control-text", -}; - -const getWidgetSelector = (widget) => `.t--widget-${widget}`; -const getWidgetInputSelector = (widget) => `.t--widget-${widget} input`; +import { + WIDGET, + PROPERTY_SELECTOR, + getWidgetSelector, + getWidgetInputSelector, +} from "../../../../locators/WidgetLocators"; const widgetsToTest = { [WIDGET.INPUT_WIDGET_V2]: { diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Widgets/MultiSelect_spec copy.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Widgets/MultiSelect_spec copy.js deleted file mode 100644 index ad7b5f6cd0..0000000000 --- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Widgets/MultiSelect_spec copy.js +++ /dev/null @@ -1,118 +0,0 @@ -const commonlocators = require("../../../../locators/commonlocators.json"); -const formWidgetsPage = require("../../../../locators/FormWidgets.json"); -const widgetLocators = require("../../../../locators/Widgets.json"); -const publish = require("../../../../locators/publishWidgetspage.json"); -const dsl = require("../../../../fixtures/multiSelectDsl.json"); -const pages = require("../../../../locators/Pages.json"); -const data = require("../../../../fixtures/example.json"); - -describe("MultiSelect Widget Functionality", function() { - before(() => { - cy.addDsl(dsl); - }); - it("Selects value with invalid default value", () => { - cy.openPropertyPane("multiselectwidgetv2"); - cy.testJsontext("options", JSON.stringify(data.input)); - cy.testJsontext("defaultvalue", "{{ undefined }}"); - cy.get(formWidgetsPage.multiselectwidgetv2) - .find(".rc-select-selection-search-input") - .first() - .focus({ force: true }) - .type("{uparrow}", { force: true }); - cy.get(".multi-select-dropdown") - .contains("Option 3") - .click({ force: true }); - cy.wait(2000); - //Validating option inside multiselect widget - cy.get(".rc-select-selection-item-content") - .first() - .should("have.text", "Option 3"); - }); - - it("Dropdown Functionality To Check Allow select all option", function() { - // select all option is not enable - cy.get(formWidgetsPage.multiselectwidgetv2) - .find(".rc-select-selection-item-content") - .first() - .should("not.have.text", "Select all"); - // enable select all option from property pane - cy.openPropertyPane("multiselectwidgetv2"); - cy.togglebar(commonlocators.allowSelectAllCheckbox); - - // press select all option - cy.get(formWidgetsPage.multiselectwidgetv2) - .find(".rc-select-selection-search-input") - .first() - .focus({ force: true }) - .type("{uparrow}", { force: true }); - cy.get(".multi-select-dropdown") - .contains("Select all") - .click({ force: true }); - cy.wait(2000); - //Validating option inside multiselect widget - cy.get(".rc-select-selection-item-content") - .eq(0) - .should("have.text", "Option 1"); - cy.get(".rc-select-selection-item-content") - .eq(1) - .should("have.text", "Option 2"); - }); - - it("Check isDirty meta property", function() { - cy.openPropertyPane("textwidget"); - cy.updateCodeInput(".t--property-control-text", `{{MultiSelect2.isDirty}}`); - // Init isDirty by changing defaultOptionValue - cy.openPropertyPane("multiselectwidgetv2"); - cy.updateCodeInput( - ".t--property-control-defaultvalue", - '[\n {\n "label": "Option 1",\n "value": "1"\n }\n]', - ); - cy.get(".t--widget-textwidget").should("contain", "false"); - // Interact with UI - cy.get(".rc-select-selector").click({ force: true }); - cy.dropdownMultiSelectDynamic("Option 2"); - // Check if isDirty is set to true - cy.get(".t--widget-textwidget").should("contain", "true"); - // Reset isDirty by changing defaultOptionValue - cy.updateCodeInput( - ".t--property-control-defaultvalue", - '[\n {\n "label": "Option 2",\n "value": "2"\n }\n]', - ); - // Check if isDirty is set to false - cy.get(".t--widget-textwidget").should("contain", "false"); - }); - it("Selects value with enter in default value", () => { - cy.updateCodeInput( - ".t--property-control-defaultvalue", - '[\n {\n "label": "Option 3",\n "value": "3"\n }\n]', - ); - cy.get(formWidgetsPage.multiselectwidgetv2) - .find(".rc-select-selection-item-content") - .first() - .should("have.text", "Option 3"); - }); - it("Dropdown Functionality To Validate Options", function() { - cy.get(".rc-select-selector").click({ force: true }); - cy.dropdownMultiSelectDynamic("Option 2"); - }); - it("Dropdown Functionality To Unchecked Visible Widget", function() { - cy.togglebarDisable(commonlocators.visibleCheckbox); - cy.PublishtheApp(); - cy.get(publish.multiselectwidgetv2 + " " + ".rc-select-selector").should( - "not.exist", - ); - cy.get(publish.backToEditor).click(); - }); - it("Dropdown Functionality To Check Visible Widget", function() { - cy.openPropertyPane("multiselectwidgetv2"); - cy.togglebar(commonlocators.visibleCheckbox); - cy.PublishtheApp(); - cy.get(publish.multiselectwidgetv2 + " " + ".rc-select-selector").should( - "be.visible", - ); - cy.get(publish.backToEditor).click(); - }); -}); -afterEach(() => { - // put your clean up code if any -}); diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Widgets/MultiSelect_spec2.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Widgets/MultiSelect_spec2.js new file mode 100644 index 0000000000..f756d20822 --- /dev/null +++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Widgets/MultiSelect_spec2.js @@ -0,0 +1,232 @@ +/// + +const commonlocators = require("../../../../locators/commonlocators.json"); +const formWidgetsPage = require("../../../../locators/FormWidgets.json"); +const publish = require("../../../../locators/publishWidgetspage.json"); +const dsl = require("../../../../fixtures/multiSelectDsl.json"); +import data from "../../../../fixtures/example.json"; +import { + PROPERTY_SELECTOR, + WIDGET, + getWidgetSelector, +} from "../../../../locators/WidgetLocators"; +import { ObjectsRegistry } from "../../../../support/Objects/Registry"; + +const agHelper = ObjectsRegistry.AggregateHelper, + jsEditor = ObjectsRegistry.JSEditor; + +describe("MultiSelect Widget Functionality", function() { + before(() => { + cy.addDsl(dsl); + }); + + it("1. Selects value with invalid default value", () => { + cy.openPropertyPane("multiselectwidgetv2"); + cy.testJsontext("options", JSON.stringify(data.input)); + cy.testJsontext("defaultvalue", "{{ undefined }}"); + cy.get(formWidgetsPage.multiselectwidgetv2) + .find(".rc-select-selection-search-input") + .first() + .focus({ force: true }) + .type("{uparrow}", { force: true }); + + cy.dropdownMultiSelectDynamic("Option 3"); + + cy.wait(2000); + //Validating option inside multiselect widget + cy.get(".rc-select-selection-item-content") + .first() + .should("have.text", "Option 3"); + }); + + it("2. Selects value with enter in default value", () => { + cy.testJsontext( + "defaultvalue", + '[\n {\n "label": "Option 3",\n "value": "3"\n }\n]', + ); + cy.get(formWidgetsPage.multiselectwidgetv2) + .find(".rc-select-selection-item-content") + .first() + .should("have.text", "Option 3"); + }); + + it("3. Dropdown Functionality To Validate Options", function() { + cy.get(".rc-select-selector").click({ force: true }); + cy.dropdownMultiSelectDynamic("Option 2"); + }); + + it("4. Dropdown Functionality To Check Allow select all option", function() { + // select all option is not enable + cy.get(formWidgetsPage.multiselectwidgetv2) + .find(".rc-select-selection-item-content") + .first() + .should("not.have.text", "Select all"); + // enable select all option from property pane + cy.openPropertyPane("multiselectwidgetv2"); + cy.togglebar(commonlocators.allowSelectAllCheckbox); + + // press select all option + cy.get(formWidgetsPage.multiselectwidgetv2) + .find(".rc-select-selection-search-input") + .first() + .focus({ force: true }) + .type("{uparrow}", { force: true }); + + cy.dropdownMultiSelectDynamic("Select all"); + + cy.wait(3000); + //Validating option inside multiselect widget + cy.get(".rc-select-selection-item-content") + .eq(0) + .should("have.text", "Option 1"); + cy.get(".rc-select-selection-item-content") + .eq(1) + .should("have.text", "Option 2"); + }); + + it("5. Check isDirty meta property", function() { + cy.openPropertyPane(WIDGET.TEXT); + cy.updateCodeInput(PROPERTY_SELECTOR.text, `{{MultiSelect2.isDirty}}`); + // Init isDirty by changing defaultOptionValue + cy.openPropertyPane("multiselectwidgetv2"); + cy.updateCodeInput( + PROPERTY_SELECTOR.defaultValue, + '[\n {\n "label": "Option 1",\n "value": "1"\n }\n]', + ); + cy.get(getWidgetSelector(WIDGET.TEXT)) + .eq(0) + .should("contain", "false"); + // Interact with UI + cy.get(".rc-select-selector").click({ force: true }); + cy.dropdownMultiSelectDynamic("Option 2"); + // Check if isDirty is set to true + cy.get(getWidgetSelector(WIDGET.TEXT)) + .eq(0) + .should("contain", "true"); + // Reset isDirty by changing defaultOptionValue + cy.updateCodeInput( + PROPERTY_SELECTOR.defaultValue, + '[\n {\n "label": "Option 2",\n "value": "2"\n }\n]', + ); + // Check if isDirty is set to false + cy.get(getWidgetSelector(WIDGET.TEXT)) + .eq(0) + .should("contain", "false"); + }); + + const resetTestCases = [ + { + options: [ + { label: "RED", value: "RED" }, + { label: "GREEN", value: "GREEN" }, + { label: "YELLOW", value: "YELLOW" }, + ], + defaultValue: [{ label: "RED", value: "RED" }], + optionsToSelect: ["GREEN", "YELLOW"], + optionsToDeselect: ["RED"], + }, + { + options: [ + { label: "1", value: "1" }, + { label: "2", value: "2" }, + { label: "3", value: "3" }, + ], + defaultValue: ["1", "2", "3", "4"], + optionsToSelect: [], + optionsToDeselect: ["1"], + }, + { + options: [ + { label: "1", value: "1" }, + { label: "2", value: "2" }, + { label: "3", value: "3" }, + ], + defaultValue: [], + optionsToSelect: [], + optionsToDeselect: [], + }, + { + options: [ + { label: "1", value: "1" }, + { label: "2", value: "2" }, + { label: "3", value: "3" }, + ], + defaultValue: [{ label: "4", value: "4" }], + optionsToSelect: [], + optionsToDeselect: [], + }, + ]; + + it("6. Verify MultiSelect resets to default value", function() { + resetTestCases.forEach((testCase) => { + const { + defaultValue, + options, + optionsToDeselect, + optionsToSelect, + } = testCase; + + cy.openPropertyPane("multiselectwidgetv2"); + // set options + jsEditor.EnterJSContext("Options", JSON.stringify(options)); + cy.get("body").type("{esc}"); + // set default value + jsEditor.EnterJSContext( + "Default Value", + JSON.stringify(defaultValue, null, 2), + ); + // select other options + agHelper.SelectFromMultiSelect(optionsToSelect); + agHelper.RemoveMultiSelectItems(optionsToDeselect); + + // reset multiselect + cy.get( + `${getWidgetSelector("buttonwidget")}:contains('Reset MultiSelect')`, + ).click(); + + // verify value is equal to default value + const defaultValuesStringifiedArray = defaultValue + .map((opt) => (opt?.value !== undefined ? opt.value : opt)) + .toString(); + cy.get(getWidgetSelector("textwidget")) + .eq(1) + .should("have.text", defaultValuesStringifiedArray); + }); + }); + + it("7. Verify MultiSelect deselection behavior", function() { + cy.openPropertyPane("multiselectwidgetv2"); + // set options + jsEditor.EnterJSContext( + "Options", + JSON.stringify([{ label: "RED", value: "RED" }]), + ); + cy.get("body").type("{esc}"); + jsEditor.EnterJSContext("Default Value", '["RED"]'); + agHelper.RemoveMultiSelectItems(["RED"]); + + // verify value is equal to default value + cy.get(getWidgetSelector("textwidget")) + .eq(1) + .should("have.text", ""); + }); + + it("8. Dropdown Functionality To Unchecked Visible Widget", function() { + cy.togglebarDisable(commonlocators.visibleCheckbox); + cy.PublishtheApp(); + cy.get(publish.multiselectwidgetv2 + " " + ".rc-select-selector").should( + "not.exist", + ); + cy.get(publish.backToEditor).click(); + }); + + it("9. Dropdown Functionality To Check Visible Widget", function() { + cy.openPropertyPane("multiselectwidgetv2"); + cy.togglebar(commonlocators.visibleCheckbox); + cy.PublishtheApp(); + cy.get(publish.multiselectwidgetv2 + " " + ".rc-select-selector").should( + "be.visible", + ); + cy.get(publish.backToEditor).click(); + }); +}); diff --git a/app/client/cypress/locators/WidgetLocators.ts b/app/client/cypress/locators/WidgetLocators.ts new file mode 100644 index 0000000000..41d30f21c1 --- /dev/null +++ b/app/client/cypress/locators/WidgetLocators.ts @@ -0,0 +1,20 @@ +export const WIDGET = { + INPUT_WIDGET_V2: "inputwidgetv2", + TEXT: "textwidget", + PHONE_INPUT_WIDGET: "phoneinputwidget", + CURRENCY_INPUT_WIDGET: "currencyinputwidget", + BUTTON_WIDGET: "buttonwidget", +} as const; + +export const PROPERTY_SELECTOR = { + onClick: ".t--property-control-onclick", + onSubmit: ".t--property-control-onsubmit", + text: ".t--property-control-text", + defaultValue: ".t--property-control-defaultvalue", +}; +type ValueOf = T[keyof T]; + +export const getWidgetSelector = (widget: ValueOf) => + `.t--widget-${widget}`; +export const getWidgetInputSelector = (widget: ValueOf) => + `.t--widget-${widget} input`; diff --git a/app/client/cypress/support/Objects/CommonLocators.ts b/app/client/cypress/support/Objects/CommonLocators.ts index 67fba96064..8feb3a8f69 100644 --- a/app/client/cypress/support/Objects/CommonLocators.ts +++ b/app/client/cypress/support/Objects/CommonLocators.ts @@ -45,8 +45,8 @@ export class CommonLocators { _jsToggle = (controlToToggle: string) => ".t--property-control-" + controlToToggle + " .t--js-toggle" _spanButton = (btnVisibleText: string) => "//span[text()='" + btnVisibleText + "']/parent::button" _selectPropDropdown = (ddName: string) => "//div[contains(@class, 't--property-control-" + ddName + "')]//button[contains(@class, 't--open-dropdown-Select-Action')]" - _dropDownValue = (ddOption: string) => ".single-select:contains('" + ddOption + "')" - _selectOptionValue = (ddOption: string) => ".menu-item-link:contains('" + ddOption + "')" + _dropDownValue = (dropdownOption: string) => ".single-select:contains('" + dropdownOption + "')" + _selectOptionValue = (dropdownOption: string) => ".menu-item-link:contains('" + dropdownOption + "')" _selectedDropdownValue = "//button[contains(@class, 'select-button')]/span[@class='bp3-button-text']" _actionTextArea = (actionName: string) => "//label[text()='" + actionName + "']/following-sibling::div//div[contains(@class, 'CodeMirror')]//textarea" _existingDefaultTextInput = ".t--property-control-defaulttext .CodeMirror-code" diff --git a/app/client/cypress/support/Pages/AggregateHelper.ts b/app/client/cypress/support/Pages/AggregateHelper.ts index 9fe8781497..b8fe4a543d 100644 --- a/app/client/cypress/support/Pages/AggregateHelper.ts +++ b/app/client/cypress/support/Pages/AggregateHelper.ts @@ -47,7 +47,6 @@ export class AggregateHelper { dsl: string, elementToCheckPresenceaftDslLoad: string | "" = "", ) { - let currentURL; let pageid: string; let layoutId; cy.url().then((url) => { @@ -221,15 +220,15 @@ export class AggregateHelper { ); } - public SelectPropertiesDropDown(endpoint: string, ddOption: string) { + public SelectPropertiesDropDown(endpoint: string, dropdownOption: string) { cy.xpath(this.locator._selectPropDropdown(endpoint)) .first() .scrollIntoView() .click(); - cy.get(this.locator._dropDownValue(ddOption)).click(); + cy.get(this.locator._dropDownValue(dropdownOption)).click(); } - public SelectDropDown(ddOption: string, endpoint: string = "selectwidget") { + public SelectDropDown(dropdownOption: string, endpoint = "selectwidget") { const mode = window.localStorage.getItem("inDeployedMode"); if (mode == "false") { cy.xpath(this.locator._selectWidgetDropdown(endpoint)) @@ -243,17 +242,22 @@ export class AggregateHelper { .click(); } if (endpoint == "selectwidget") - cy.get(this.locator._selectOptionValue(ddOption)).click({ force: true }); - else cy.get(this.locator._dropDownValue(ddOption)).click({ force: true }); + cy.get(this.locator._selectOptionValue(dropdownOption)).click({ + force: true, + }); + else + cy.get(this.locator._dropDownValue(dropdownOption)).click({ + force: true, + }); this.Sleep(); //for selected value to reflect! } public SelectFromDropDown( - ddOption: string, + dropdownOption: string, insideParent = "", index = 0, - endpoint: string = "dropdownwidget", + endpoint = "dropdownwidget", ) { const mode = window.localStorage.getItem("inDeployedMode"); //cy.log("mode frm deployed is:" + mode) @@ -269,14 +273,14 @@ export class AggregateHelper { .eq(index) .scrollIntoView() .click(); - cy.get(this.locator._dropDownValue(ddOption)).click({ force: true }); + cy.get(this.locator._dropDownValue(dropdownOption)).click({ force: true }); this.Sleep(); //for selected value to reflect! } - public SelectDropdownList(ddName: string, ddOption: string) { + public SelectDropdownList(ddName: string, dropdownOption: string) { this.GetNClick(this.locator._existingFieldTextByName(ddName)); cy.get(this.locator._dropdownText) - .contains(ddOption) + .contains(dropdownOption) .click(); } @@ -284,12 +288,24 @@ export class AggregateHelper { options: string[], index = 0, check = true, - endpoint: string = "multiselectwidgetv2", + endpoint = "multiselectwidgetv2", ) { cy.get(this.locator._widgetInDeployed(endpoint) + " div.rc-select-selector") .eq(index) .scrollIntoView() - .click(); + .then(($element: any) => { + // here, we try to click on downArrow in dropdown of multiSelect. + // the position is calculated from top left of the element + const dropdownCenterPosition = +$element.height / 2; + const dropdownArrowApproxPosition = +$element.width - 10; + cy.get($element).click( + dropdownArrowApproxPosition, + dropdownCenterPosition, + { + force: true, + }, + ); + }); if (check) { options.forEach(($each) => { diff --git a/app/client/cypress/support/Pages/DeployModeHelper.ts b/app/client/cypress/support/Pages/DeployModeHelper.ts index 73d302ea8d..1a3d225984 100644 --- a/app/client/cypress/support/Pages/DeployModeHelper.ts +++ b/app/client/cypress/support/Pages/DeployModeHelper.ts @@ -83,12 +83,12 @@ export class DeployMode { .wait(500); } - public SelectJsonFormDropDown(ddOption: string, index = 0) { + public SelectJsonFormDropDown(dropdownOption: string, index = 0) { cy.get(this._jsonSelectDropdown) .eq(index) .scrollIntoView() .click(); - cy.get(this.locator._selectOptionValue(ddOption)).click({ force: true }); + cy.get(this.locator._selectOptionValue(dropdownOption)).click({ force: true }); this.agHelper.Sleep(); //for selected value to reflect! } } diff --git a/app/client/src/actions/metaActions.ts b/app/client/src/actions/metaActions.ts index 50618dbb9a..8b936898a6 100644 --- a/app/client/src/actions/metaActions.ts +++ b/app/client/src/actions/metaActions.ts @@ -4,6 +4,7 @@ import { } from "@appsmith/constants/ReduxActionConstants"; import { BatchAction, batchAction } from "actions/batchActions"; import { EvalMetaUpdates } from "workers/DataTreeEvaluator/types"; +import { DataTreeWidget } from "../entities/DataTree/dataTreeFactory"; export interface UpdateWidgetMetaPropertyPayload { widgetId: string; @@ -26,13 +27,20 @@ export const updateWidgetMetaPropAndEval = ( }); }; +export type ResetWidgetMetaPayload = { + widgetId: string; + evaluatedWidget: DataTreeWidget; +}; + export const resetWidgetMetaProperty = ( widgetId: string, -): BatchAction<{ widgetId: string }> => { + evaluatedWidget: DataTreeWidget, +): BatchAction => { return batchAction({ type: ReduxActionTypes.RESET_WIDGET_META, payload: { widgetId, + evaluatedWidget, }, postEvalActions: [{ type: ReduxActionTypes.RESET_WIDGET_META_EVALUATED }], }); diff --git a/app/client/src/reducers/entityReducers/metaReducer/index.ts b/app/client/src/reducers/entityReducers/metaReducer/index.ts index f4da82a8a1..37cf295a48 100644 --- a/app/client/src/reducers/entityReducers/metaReducer/index.ts +++ b/app/client/src/reducers/entityReducers/metaReducer/index.ts @@ -1,6 +1,9 @@ import { set } from "lodash"; import { createReducer } from "utils/AppsmithUtils"; -import { UpdateWidgetMetaPropertyPayload } from "actions/metaActions"; +import { + UpdateWidgetMetaPropertyPayload, + ResetWidgetMetaPayload, +} from "actions/metaActions"; import { ReduxActionTypes, @@ -9,8 +12,10 @@ import { } from "@appsmith/constants/ReduxActionConstants"; import produce from "immer"; import { EvalMetaUpdates } from "workers/DataTreeEvaluator/types"; +import { klona } from "klona"; -export type MetaState = Record>; +export type WidgetMetaState = Record; +export type MetaState = Record; export const initialState: MetaState = {}; @@ -93,11 +98,31 @@ export const metaReducer = createReducer(initialState, { }, [ReduxActionTypes.RESET_WIDGET_META]: ( state: MetaState, - action: ReduxAction<{ widgetId: string }>, + action: ReduxAction, ) => { - const widgetId = action.payload.widgetId; + const { evaluatedWidget, widgetId } = action.payload; + if (widgetId in state) { - return { ...state, [widgetId]: {} }; + // only reset widgets whose meta properties were changed. + // reset widget: sets the meta values to current default values of widget + const resetMetaObj: WidgetMetaState = {}; + + // evaluatedWidget is widget data inside dataTree, this will have latest default values of widget + if (evaluatedWidget) { + const { propertyOverrideDependency } = evaluatedWidget; + // propertyOverrideDependency has defaultProperty name for each meta property of widget + Object.entries(propertyOverrideDependency).map( + ([propertyName, dependency]) => { + const defaultPropertyValue = + dependency.DEFAULT && evaluatedWidget[dependency.DEFAULT]; + if (defaultPropertyValue !== undefined) { + // cloning data to avoid mutation + resetMetaObj[propertyName] = klona(defaultPropertyValue); + } + }, + ); + } + return { ...state, [widgetId]: resetMetaObj }; } return state; }, diff --git a/app/client/src/reducers/entityReducers/metaReducer/test.ts b/app/client/src/reducers/entityReducers/metaReducer/test.ts index 38d1b7b43a..aabaaa7c8a 100644 --- a/app/client/src/reducers/entityReducers/metaReducer/test.ts +++ b/app/client/src/reducers/entityReducers/metaReducer/test.ts @@ -5,7 +5,7 @@ import { ReduxActionTypes, } from "@appsmith/constants/ReduxActionConstants"; -let previousState = initialState; +let currentMetaState = initialState; const inputWidget = { widgetId: "incwlne", @@ -21,13 +21,13 @@ const noAction = (): ReduxAction => { }; test("should return the initial state", () => { - expect(metaReducer(undefined, noAction())).toEqual(previousState); + expect(metaReducer(undefined, noAction())).toEqual(currentMetaState); }); test("Add a widget meta values", () => { - previousState = initialState; + currentMetaState = initialState; expect( - metaReducer(previousState, { + metaReducer(currentMetaState, { type: ReduxActionTypes.SET_META_PROP, payload: { widgetId: inputWidget.widgetId, @@ -51,28 +51,70 @@ test("Update widget meta state using evalMetaUpdates", () => { value: ["YELLOW"], }, ]; - const newMetaReducerState = metaReducer( - previousState, + currentMetaState = metaReducer( + currentMetaState, updateMetaState(evalMetaUpdates), ); - expect(newMetaReducerState).toEqual({ + expect(currentMetaState).toEqual({ incwlne: { text: "test123", selectedValues: ["YELLOW"], }, }); - previousState = newMetaReducerState; }); -test("Reset widget", () => { - expect( - metaReducer(previousState, { +describe("Reset widget meta action", () => { + test("Reset widget with only widgetId", () => { + currentMetaState = metaReducer(currentMetaState, { type: ReduxActionTypes.RESET_WIDGET_META, payload: { widgetId: inputWidget.widgetId, }, + }); + expect(currentMetaState).toEqual({ + incwlne: {}, + }); + }); + + currentMetaState = initialState; + expect( + metaReducer(currentMetaState, { + type: ReduxActionTypes.SET_META_PROP, + payload: { + widgetId: inputWidget.widgetId, + propertyName: inputWidget.propertyName, + propertyValue: inputWidget.propertyValue, + }, }), ).toEqual({ - incwlne: {}, + incwlne: { + selectedValues: ["GREEN", "BLUE", "YELLOW"], + }, + }); + + test("Reset widget with evaluated values", () => { + expect( + metaReducer(currentMetaState, { + type: ReduxActionTypes.RESET_WIDGET_META, + payload: { + widgetId: inputWidget.widgetId, + evaluatedWidget: { + defaultSelectedValues: ["GREEN"], + selectedValues: ["GREEN", "BLUE", "YELLOW"], + widgetId: inputWidget.widgetId, + propertyOverrideDependency: { + selectedValues: { + DEFAULT: "defaultSelectedValues", + META: "meta.selectedValues", + }, + }, + }, + }, + }), + ).toEqual({ + incwlne: { + selectedValues: ["GREEN"], + }, + }); }); }); diff --git a/app/client/src/sagas/ActionExecution/ResetWidgetActionSaga.ts b/app/client/src/sagas/ActionExecution/ResetWidgetActionSaga.ts index 88918194c1..c0933502fb 100644 --- a/app/client/src/sagas/ActionExecution/ResetWidgetActionSaga.ts +++ b/app/client/src/sagas/ActionExecution/ResetWidgetActionSaga.ts @@ -16,6 +16,9 @@ import { import { getType, Types } from "utils/TypeHelpers"; import { FlattenedWidgetProps } from "widgets/constants"; import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants"; +import { getDataTree } from "selectors/dataTreeSelectors"; +import { DataTree } from "entities/DataTree/dataTreeFactory"; +import { isWidget } from "workers/evaluationUtils"; export default function* resetWidgetActionSaga( payload: ResetWidgetDescription["payload"], @@ -29,6 +32,7 @@ export default function* resetWidgetActionSaga( getType(widgetName), ); } + const dataTree: DataTree = yield select(getDataTree); const widget: FlattenedWidgetProps | undefined = yield select( getWidgetByName, @@ -37,10 +41,12 @@ export default function* resetWidgetActionSaga( if (!widget) { throw new TriggerFailureError(`Widget ${payload.widgetName} not found`); } - - yield put(resetWidgetMetaProperty(widget.widgetId)); - if (payload.resetChildren) { - yield put(resetChildrenMetaProperty(widget.widgetId)); + const evaluatedEntity = dataTree[widget.widgetName]; + if (isWidget(evaluatedEntity)) { + yield put(resetWidgetMetaProperty(widget.widgetId, evaluatedEntity)); + if (payload.resetChildren) { + yield put(resetChildrenMetaProperty(widget.widgetId)); + } } yield take(ReduxActionTypes.RESET_WIDGET_META_EVALUATED); diff --git a/app/client/src/sagas/EvaluationsSaga.ts b/app/client/src/sagas/EvaluationsSaga.ts index 3e26038b7d..43da8dadbd 100644 --- a/app/client/src/sagas/EvaluationsSaga.ts +++ b/app/client/src/sagas/EvaluationsSaga.ts @@ -173,7 +173,7 @@ function* evaluateTreeSaga( if (evalMetaUpdates.length) { yield put(updateMetaState(evalMetaUpdates)); } - log.debug({ evalMetaUpdates }); + log.debug({ evalMetaUpdatesLength: evalMetaUpdates.length }); const updatedDataTree: DataTree = yield select(getDataTree); log.debug({ jsUpdates: jsUpdates }); diff --git a/app/client/src/sagas/WidgetOperationSagas.tsx b/app/client/src/sagas/WidgetOperationSagas.tsx index 74e502c3e0..ac4ec33227 100644 --- a/app/client/src/sagas/WidgetOperationSagas.tsx +++ b/app/client/src/sagas/WidgetOperationSagas.tsx @@ -701,15 +701,20 @@ const unsetPropertyPath = (obj: Record, path: string) => { }; function* resetChildrenMetaSaga(action: ReduxAction<{ widgetId: string }>) { - const parentWidgetId = action.payload.widgetId; + const { widgetId: parentWidgetId } = action.payload; const canvasWidgets: CanvasWidgetsReduxState = yield select(getWidgets); - const childrenIds: string[] = getWidgetChildren( + const evaluatedDataTree: DataTree = yield select(getDataTree); + const childrenList = getWidgetChildren( canvasWidgets, parentWidgetId, + evaluatedDataTree, ); - for (const childIndex in childrenIds) { - const childId = childrenIds[childIndex]; - yield put(resetWidgetMetaProperty(childId)); + + for (const childIndex in childrenList) { + const { evaluatedWidget: childWidget, id: childId } = childrenList[ + childIndex + ]; + yield put(resetWidgetMetaProperty(childId, childWidget)); } } diff --git a/app/client/src/sagas/WidgetOperationUtils.ts b/app/client/src/sagas/WidgetOperationUtils.ts index e1a4dd8cbd..1a278d87ac 100644 --- a/app/client/src/sagas/WidgetOperationUtils.ts +++ b/app/client/src/sagas/WidgetOperationUtils.ts @@ -51,6 +51,8 @@ import { import { getWidgetSpacesSelectorForContainer } from "selectors/editorSelectors"; import { reflow } from "reflow"; import { getBottomRowAfterReflow } from "utils/reflowHookUtils"; +import { DataTreeWidget } from "entities/DataTree/dataTreeFactory"; +import { isWidget } from "../workers/evaluationUtils"; export interface CopiedWidgetGroup { widgetId: string; @@ -270,8 +272,7 @@ export const handleSpecificCasesWhilePasting = ( return widgets; }; - -export function getWidgetChildren( +export function getWidgetChildrenIds( canvasWidgets: CanvasWidgetsReduxState, widgetId: string, ): any { @@ -289,7 +290,7 @@ export function getWidgetChildren( if (children.hasOwnProperty(childIndex)) { const child = children[childIndex]; childrenIds.push(child); - const grandChildren = getWidgetChildren(canvasWidgets, child); + const grandChildren = getWidgetChildrenIds(canvasWidgets, child); if (grandChildren.length) { childrenIds.push(...grandChildren); } @@ -299,6 +300,54 @@ export function getWidgetChildren( return childrenIds; } +export type ChildrenWidgetMap = { id: string; evaluatedWidget: DataTreeWidget }; +/** + * getWidgetChildren: It gets all the child widgets of given widget's id with evaluated values + * + */ +export function getWidgetChildren( + canvasWidgets: CanvasWidgetsReduxState, + widgetId: string, + evaluatedDataTree: DataTree, +): ChildrenWidgetMap[] { + const childrenList: ChildrenWidgetMap[] = []; + const widget = _.get(canvasWidgets, widgetId); + // When a form widget tries to resetChildrenMetaProperties + // But one or more of its container like children + // have just been deleted, widget can be undefined + if (widget === undefined) { + return []; + } + + const { children = [] } = widget; + if (children && children.length) { + for (const childIndex in children) { + if (children.hasOwnProperty(childIndex)) { + const childWidgetId = children[childIndex]; + + const childCanvasWidget = _.get(canvasWidgets, childWidgetId); + const childWidgetName = childCanvasWidget.widgetName; + const childWidget = evaluatedDataTree[childWidgetName]; + if (isWidget(childWidget)) { + childrenList.push({ + id: childWidgetId, + evaluatedWidget: childWidget, + }); + const grandChildren = getWidgetChildren( + canvasWidgets, + childWidgetId, + evaluatedDataTree, + ); + if (grandChildren.length) { + childrenList.push(...grandChildren); + } + } + } + } + } + return childrenList; +} + export const getParentWidgetIdForPasting = function*( widgets: CanvasWidgetsReduxState, selectedWidget: FlattenedWidgetProps | undefined, @@ -387,7 +436,7 @@ export const getSelectedWidgetIfPastingIntoListWidget = function( selectedWidget.children && selectedWidget?.type === "LIST_WIDGET" ) { - const childrenIds: string[] = getWidgetChildren( + const childrenIds: string[] = getWidgetChildrenIds( canvasWidgets, selectedWidget.children[0], ); diff --git a/app/client/src/sagas/WidgetSelectionSagas.ts b/app/client/src/sagas/WidgetSelectionSagas.ts index d764439cc5..d176580e78 100644 --- a/app/client/src/sagas/WidgetSelectionSagas.ts +++ b/app/client/src/sagas/WidgetSelectionSagas.ts @@ -29,7 +29,7 @@ import { CanvasWidgetsReduxState, FlattenedWidgetProps, } from "reducers/entityReducers/canvasWidgetsReducer"; -import { getWidgetChildren } from "./WidgetOperationUtils"; +import { getWidgetChildrenIds } from "./WidgetOperationUtils"; import { AppState } from "reducers"; import { checkIsDropTarget } from "components/designSystems/appsmith/PositionedContainer"; import WidgetFactory from "utils/WidgetFactory"; @@ -140,7 +140,7 @@ function* getAllSelectableChildren() { : false; if (selectGrandChildren) { allChildren = yield call( - getWidgetChildren, + getWidgetChildrenIds, canvasWidgets, lastSelectedWidget, ); diff --git a/app/client/src/widgets/CurrencyInputWidget/widget/index.tsx b/app/client/src/widgets/CurrencyInputWidget/widget/index.tsx index fb13de0eec..d536a8148d 100644 --- a/app/client/src/widgets/CurrencyInputWidget/widget/index.tsx +++ b/app/client/src/widgets/CurrencyInputWidget/widget/index.tsx @@ -233,7 +233,7 @@ class CurrencyInputWidget extends BaseInputWidget< try { const formattedValue = formatCurrencyNumber( this.props.decimals, - String(this.props.value), + this.props.text, ); this.props.updateWidgetMetaProperty("text", formattedValue); } catch (e) { diff --git a/app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx b/app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx index 6bf9013209..a2fe36eaa6 100644 --- a/app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx +++ b/app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx @@ -531,7 +531,6 @@ class MultiSelectWidget extends BaseWidget< static getDefaultPropertiesMap(): Record { return { selectedOptions: "defaultOptionValue", - filterText: "", }; }