fix: remove parent list widget from child widget level data (#20963)

## Description

Avoid cyclic dependency in child widget when using level data to
reference Parent List widget

Fixes #20793 

## Type of change
- Bug fix (non-breaking change which fixes an issue)



## How Has This Been Tested?

- Cypress

### Test Plan
> https://github.com/appsmithorg/TestSmith/issues/2187

### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)


## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag


### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
This commit is contained in:
Tolulope Adetula 2023-03-02 15:49:14 +00:00 committed by GitHub
parent a27c52a7e4
commit 72738b95e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 439 additions and 68 deletions

View File

@ -1,49 +0,0 @@
const dsl = require("../../../../../fixtures/Listv2/copy_paste_listv2_dsl.json");
const widgetSelector = (name) => `[data-widgetname-cy="${name}"]`;
describe(" Nested List Widgets ", function() {
const modifierKey = Cypress.platform === "darwin" ? "meta" : "ctrl";
before(() => {
cy.addDsl(dsl);
});
it("a. Pasting - should show toast when nesting is greater than 3", function() {
cy.openPropertyPaneByWidgetName("List1", "listwidgetv2");
// Copy List1
cy.get(".t--copy-widget").click({ force: true });
cy.wait(500);
//Paste inside List 1
cy.get(`${widgetSelector("List1")} [type="CONTAINER_WIDGET"]`)
.first()
.click({ force: true })
.type(`{${modifierKey}}{v}`);
cy.wait(500);
//Copy List 2 and Paste inside list 2
cy.openPropertyPaneByWidgetName("List2", "listwidgetv2");
cy.get(".t--copy-widget").click({ force: true });
cy.wait(500);
// Paste inside list 2
cy.get(`${widgetSelector("List2")} [type="CONTAINER_WIDGET"]`)
.first()
.click({ force: true })
.type(`{${modifierKey}}{v}`);
cy.wait(500);
//Now Both List1 and List2 are n-2 levels
//Copy List2 and Past in List 1
cy.openPropertyPaneByWidgetName("List2", "listwidgetv2");
cy.get(".t--copy-widget").click({ force: true });
cy.wait(500);
cy.get(`${widgetSelector("List1Copy")} [type="CONTAINER_WIDGET"]`)
.first()
.click({ force: true })
.type(`{${modifierKey}}{v}`);
cy.wait(500);
cy.validateToastMessage("Cannot have more than 3 levels of nesting");
cy.get(`${widgetSelector("List2Copy1")}`).should("not.exist");
});
});

View File

@ -0,0 +1,128 @@
const dsl = require("../../../../../fixtures/Listv2/copy_paste_listv2_dsl.json");
const widgetSelector = (name) => `[data-widgetname-cy="${name}"]`;
function checkAutosuggestion(label, type) {
cy.get(".CodeMirror-hints")
.contains(label)
.then(($el) => {
const after = getComputedStyle($el[0], "::after");
const afterContent = after.getPropertyValue("content");
expect(afterContent).eq(`"${type}"`);
});
}
describe(" Nested List Widgets ", function() {
const modifierKey = Cypress.platform === "darwin" ? "meta" : "ctrl";
before(() => {
cy.addDsl(dsl);
});
it("a. Pasting - should show toast when nesting is greater than 3", function() {
cy.openPropertyPaneByWidgetName("List1", "listwidgetv2");
// Copy List1
cy.get(".t--copy-widget").click({ force: true });
cy.wait(500);
//Paste inside List 1
cy.get(`${widgetSelector("List1")} [type="CONTAINER_WIDGET"]`)
.first()
.click({ force: true })
.type(`{${modifierKey}}{v}`);
cy.wait(500);
//Copy List 2 and Paste inside list 2
cy.openPropertyPaneByWidgetName("List2", "listwidgetv2");
cy.get(".t--copy-widget").click({ force: true });
cy.wait(500);
// Paste inside list 2
cy.get(`${widgetSelector("List2")} [type="CONTAINER_WIDGET"]`)
.first()
.click({ force: true })
.type(`{${modifierKey}}{v}`);
cy.wait(500);
//Now Both List1 and List2 are n-2 levels
//Copy List2 and Past in List 1
cy.openPropertyPaneByWidgetName("List2", "listwidgetv2");
cy.get(".t--copy-widget").click({ force: true });
cy.wait(500);
cy.get(`${widgetSelector("List1Copy")} [type="CONTAINER_WIDGET"]`)
.first()
.click({ force: true })
.type(`{${modifierKey}}{v}`);
cy.wait(500);
cy.validateToastMessage("Cannot have more than 3 levels of nesting");
cy.get(`${widgetSelector("List2Copy1")}`).should("not.exist");
});
it("b. No cyclic dependency when using levelData in a child widget", () => {
cy.dragAndDropToWidgetBySelector(
"textwidget",
'[data-widgetname-cy="List1"] [type="CONTAINER_WIDGET"]',
{
x: 150,
y: 50,
},
);
cy.openPropertyPane("textwidget");
cy.updateCodeInput(".t--property-control-text", `{{currentItem.name}}`);
cy.dragAndDropToWidgetBySelector(
"textwidget",
'[data-widgetname-cy="List1Copy"]',
{
x: 150,
y: 100,
},
);
cy.testJsontextclear("text");
cy.get(".t--property-control-text .CodeMirror textarea").type(
"{{level_1.currentView.",
{
force: true,
},
);
checkAutosuggestion("Text1", "Object");
checkAutosuggestion("List1Copy", "Object");
cy.testJsontextclear("text");
cy.get(".t--property-control-text .CodeMirror textarea").type(
"{{level_1.currentView.List1Copy.",
{
force: true,
},
);
checkAutosuggestion("backgroundColor", "String");
checkAutosuggestion("itemSpacing", "Number");
checkAutosuggestion("isVisible", "Boolean");
checkAutosuggestion("listData", "Array");
checkAutosuggestion("pageNo", "Number");
checkAutosuggestion("pageSize", "Number");
cy.get(".CodeMirror-hints").each(($el) => {
cy.wrap($el).should("not.have.text", "currentViewItems");
});
cy.get(".CodeMirror-hints").each(($el) => {
cy.wrap($el).should("not.have.text", "selectedItemView");
});
cy.get(".CodeMirror-hints").each(($el) => {
cy.wrap($el).should("not.have.text", "triggeredItemView");
});
cy.get(".CodeMirror-hints")
.contains("pageNo")
.first()
.click({ force: true });
cy.get(`${widgetSelector("Text2")} .bp3-ui-text span`).should(
"have.text",
"1",
);
});
});

View File

@ -93,7 +93,15 @@ describe("List widget v2 - Basic Child Widget Interaction", () => {
cy.PublishtheApp();
cy.wait(3000);
cy.waitUntil(() =>
cy
.get(
`${widgetSelector("List1")} ${containerWidgetSelector} ${
publishLocators.selectwidget
}`,
)
.should("have.length", 3),
);
// open the select widget
cy.get(publishLocators.selectwidget)
@ -122,7 +130,15 @@ describe("List widget v2 - Basic Child Widget Interaction", () => {
cy.PublishtheApp();
cy.wait(3000);
cy.waitUntil(() =>
cy
.get(
`${widgetSelector("List1")} ${containerWidgetSelector} ${
publishLocators.checkboxGroupWidget
}`,
)
.should("have.length", 3),
);
// select green
cy.get(publishLocators.checkboxGroupWidget)
@ -157,7 +173,15 @@ describe("List widget v2 - Basic Child Widget Interaction", () => {
cy.PublishtheApp();
cy.wait(3000);
cy.waitUntil(() =>
cy
.get(
`${widgetSelector("List1")} ${containerWidgetSelector} ${
publishLocators.switchwidget
}`,
)
.should("have.length", 3),
);
// Verify checked
cy.get(publishLocators.switchwidget)
@ -189,7 +213,15 @@ describe("List widget v2 - Basic Child Widget Interaction", () => {
cy.PublishtheApp();
cy.wait(3000);
cy.waitUntil(() =>
cy
.get(
`${widgetSelector("List1")} ${containerWidgetSelector} ${
publishLocators.radioWidget
}`,
)
.should("have.length", 3),
);
// Check radio with value=1 is selected
checkSelectedRadioValue(publishLocators.radioWidget, "Y");

View File

@ -99,7 +99,17 @@ describe("List widget v2 - meta hydration tests", () => {
cy.get(commonlocators.listPaginateNextButton).click({
force: true,
});
cy.wait(2000);
cy.wait(200);
cy.waitUntil(() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .t--widget-selectwidget button`,
)
.should("have.length", 3),
);
// SecondPage
// First Row
@ -122,7 +132,30 @@ describe("List widget v2 - meta hydration tests", () => {
cy.get(commonlocators.listPaginatePrevButton).click({
force: true,
});
cy.wait(3000);
cy.wait(300);
cy.waitUntil(() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .t--widget-selectwidget button`,
)
.should("have.length", 3),
);
cy.waitUntil(() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .t--widget-selectwidget button span.bp3-button-text`,
)
.first()
.invoke("text")
.then(($selectedValue) => {
expect($selectedValue).to.eq("Green");
}),
);
//Validate values in FirstPage
// First Row
@ -146,7 +179,30 @@ describe("List widget v2 - meta hydration tests", () => {
cy.get(commonlocators.listPaginateNextButton).click({
force: true,
});
cy.wait(3000);
cy.wait(300);
cy.waitUntil(() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .t--widget-selectwidget button`,
)
.should("have.length", 3),
);
cy.waitUntil(() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .t--widget-selectwidget button span.bp3-button-text`,
)
.first()
.invoke("text")
.then(($selectedValue) => {
expect($selectedValue).to.eq("Blue");
}),
);
//Validate values in SecondPage
// First Row
@ -194,7 +250,16 @@ describe("List widget v2 - meta hydration tests", () => {
cy.get(commonlocators.listPaginateNextButton).click({
force: true,
});
cy.wait(2000);
cy.wait(300);
cy.waitUntil(() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .t--widget-selectwidget button`,
)
.should("have.length", 3),
);
// SecondPage
// First Row
@ -216,10 +281,34 @@ describe("List widget v2 - meta hydration tests", () => {
cy.get(commonlocators.listPaginatePrevButton).click({
force: true,
});
cy.wait(3000);
//Validate values in FirstPage
// First Row
cy.wait(300);
cy.waitUntil(() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .t--widget-selectwidget button`,
)
.should("have.length", 3),
);
cy.waitUntil(() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .t--widget-selectwidget button span.bp3-button-text`,
)
.first()
.invoke("text")
.then(($selectedValue) => {
expect($selectedValue).to.eq("Green");
}),
);
cy.get(`${widgetSelector("List1")}`).scrollIntoView();
verifyValueOfWidget("selectwidget", "Green", 0);
@ -240,10 +329,34 @@ describe("List widget v2 - meta hydration tests", () => {
cy.get(commonlocators.listPaginateNextButton).click({
force: true,
});
cy.wait(3000);
//Validate values in SecondPage
// First Row
cy.wait(300);
cy.waitUntil(() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .t--widget-selectwidget button`,
)
.should("have.length", 3),
);
cy.waitUntil(() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .t--widget-selectwidget button span.bp3-button-text`,
)
.first()
.invoke("text")
.then(($selectedValue) => {
expect($selectedValue).to.eq("Blue");
}),
);
cy.get(`${widgetSelector("List1")}`).scrollIntoView();
verifyValueOfWidget("selectwidget", "Blue", 0);

View File

@ -176,7 +176,17 @@ describe("List widget v2 - meta hydration tests", () => {
cy.get(commonlocators.listPaginateNextButton).click({
force: true,
});
cy.wait(2000);
cy.wait(200);
cy.waitUntil(() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .t--widget-selectwidget button`,
)
.should("have.length", 3),
);
// SecondPage
// First Row
@ -202,7 +212,34 @@ describe("List widget v2 - meta hydration tests", () => {
//Validate values in FirstPage
// First Row
cy.wait(10000);
cy.wait(300);
cy.waitUntil(() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .t--widget-selectwidget button`,
)
.should("have.length", 3),
);
cy.waitUntil(
() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .t--widget-selectwidget button span.bp3-button-text`,
)
.first()
.invoke("text")
.then(($selectedValue) => {
expect($selectedValue).to.eq("Green");
}),
{
timeout: 10000,
},
);
cy.get(`${widgetSelector("List1")}`).scrollIntoView();
verifyValueOfWidget("selectwidget", "Green", 0);
verifyValueOfWidget("inputwidgetv2", "First", 0);
@ -222,10 +259,37 @@ describe("List widget v2 - meta hydration tests", () => {
cy.get(commonlocators.listPaginateNextButton).click({
force: true,
});
cy.wait(300);
//Validate values in SecondPage
// First Row
cy.wait(10000);
cy.waitUntil(() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .t--widget-selectwidget button`,
)
.should("have.length", 3),
);
cy.waitUntil(
() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .t--widget-selectwidget button span.bp3-button-text`,
)
.first()
.invoke("text")
.then(($selectedValue) => {
expect($selectedValue).to.eq("Blue");
}),
{
timeout: 10000,
},
);
cy.get(`${widgetSelector("List1")}`).scrollIntoView();
verifyValueOfWidget("selectwidget", "Blue", 0);
verifyValueOfWidget("inputwidgetv2", "Fourth", 0);
@ -268,7 +332,17 @@ describe("List widget v2 - meta hydration tests", () => {
cy.get(commonlocators.listPaginateNextButton).click({
force: true,
});
cy.wait(2000);
cy.wait(200);
cy.waitUntil(() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .t--widget-selectwidget button`,
)
.should("have.length", 3),
);
// SecondPage
// First Row
@ -293,7 +367,34 @@ describe("List widget v2 - meta hydration tests", () => {
//Validate values in FirstPage
// First Row
cy.wait(10000);
cy.wait(300);
cy.waitUntil(() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .t--widget-selectwidget button`,
)
.should("have.length", 3),
);
cy.waitUntil(
() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .t--widget-selectwidget button span.bp3-button-text`,
)
.first()
.invoke("text")
.then(($selectedValue) => {
expect($selectedValue).to.eq("Green");
}),
{
timeout: 10000,
},
);
cy.get(`${widgetSelector("List1")}`).scrollIntoView();
verifyValueOfWidget("selectwidget", "Green", 0);
verifyValueOfWidget("inputwidgetv2", "First", 0);
@ -316,7 +417,34 @@ describe("List widget v2 - meta hydration tests", () => {
//Validate values in SecondPage
// First Row
cy.wait(10000);
cy.wait(300);
cy.waitUntil(() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .t--widget-selectwidget button`,
)
.should("have.length", 3),
);
cy.waitUntil(
() =>
cy
.get(
`${widgetSelector(
"List1",
)} ${containerWidgetSelector} .t--widget-selectwidget button span.bp3-button-text`,
)
.first()
.invoke("text")
.then(($selectedValue) => {
expect($selectedValue).to.eq("Blue");
}),
{
timeout: 10000,
},
);
cy.get(`${widgetSelector("List1")}`).scrollIntoView();
verifyValueOfWidget("selectwidget", "Blue", 0);
verifyValueOfWidget("inputwidgetv2", "Fourth", 0);

View File

@ -785,6 +785,25 @@ Cypress.Commands.add(
},
);
Cypress.Commands.add(
"dragAndDropToWidgetBySelector",
(widgetType, destinationSelector, { x, y }) => {
const selector = `.t--widget-card-draggable-${widgetType}`;
cy.wait(800);
cy.get(selector)
.scrollIntoView()
.trigger("dragstart", { force: true })
.trigger("mousemove", x, y, { force: true });
cy.get(destinationSelector)
.first()
.scrollIntoView()
.scrollTo("top", { ensureScrollable: false })
.trigger("mousemove", x, y, { eventConstructor: "MouseEvent" })
.trigger("mousemove", x, y, { eventConstructor: "MouseEvent" })
.trigger("mouseup", x, y, { eventConstructor: "MouseEvent" });
},
);
Cypress.Commands.add("changeButtonColor", (buttonColor) => {
cy.get(widgetsPage.buttonColor)
.click({ force: true })

View File

@ -727,7 +727,7 @@ describe("#generate", () => {
},
List6: {
entityDefinition:
"backgroundColor: List6.backgroundColor,isVisible: List6.isVisible,itemSpacing: List6.itemSpacing,selectedItem: List6.selectedItem,selectedItemView: List6.selectedItemView,triggeredItem: List6.triggeredItem,triggeredItemView: List6.triggeredItemView,listData: List6.listData,pageNo: List6.pageNo,pageSize: List6.pageSize",
"backgroundColor: List6.backgroundColor,isVisible: List6.isVisible,itemSpacing: List6.itemSpacing,selectedItem: List6.selectedItem,triggeredItem: List6.triggeredItem,listData: List6.listData,pageNo: List6.pageNo,pageSize: List6.pageSize",
rowIndex: 0,
metaWidgetId: "fs2d2lqjgd",
metaWidgetName: "List6",
@ -927,7 +927,7 @@ describe("#generate", () => {
};
const expectedDataBinding =
"{{\n {\n \n Image1: { image: Image1.image,isVisible: Image1.isVisible }\n ,\n Text1: { isVisible: Text1.isVisible,text: Text1.text }\n ,\n Text2: { isVisible: Text2.isVisible,text: Text2.text }\n ,\n List6: { backgroundColor: List6.backgroundColor,isVisible: List6.isVisible,itemSpacing: List6.itemSpacing,selectedItem: List6.selectedItem,selectedItemView: List6.selectedItemView,triggeredItem: List6.triggeredItem,triggeredItemView: List6.triggeredItemView,listData: List6.listData,pageNo: List6.pageNo,pageSize: List6.pageSize }\n \n }\n }}";
"{{\n {\n \n Image1: { image: Image1.image,isVisible: Image1.isVisible }\n ,\n Text1: { isVisible: Text1.isVisible,text: Text1.text }\n ,\n Text2: { isVisible: Text2.isVisible,text: Text2.text }\n ,\n List6: { backgroundColor: List6.backgroundColor,isVisible: List6.isVisible,itemSpacing: List6.itemSpacing,selectedItem: List6.selectedItem,triggeredItem: List6.triggeredItem,listData: List6.listData,pageNo: List6.pageNo,pageSize: List6.pageSize }\n \n }\n }}";
const count = Object.keys(metaWidgets).length;
expect(count).toEqual(18);

View File

@ -181,7 +181,7 @@ enum MODIFICATION_TYPE {
const ROOT_CONTAINER_PARENT_KEY = "__$ROOT_CONTAINER_PARENT$__";
const ROOT_ROW_KEY = "__$ROOT_KEY$__";
const BLACKLISTED_ENTITY_DEFINITION: Record<string, string[] | undefined> = {
LIST_WIDGET_V2: ["currentItemsView"],
LIST_WIDGET_V2: ["currentItemsView", "selectedItemView", "triggeredItemView"],
};
/**
* LEVEL_PATH_REGEX gives out following matches: