Skip to content

Commit

Permalink
Merge branch 'release' of https://github.com/appsmithorg/appsmith int…
Browse files Browse the repository at this point in the history
…o feat/update-query-binding-for-building-block-dnd
  • Loading branch information
jacquesikot committed Jun 24, 2024
2 parents 8f8e643 + 99c51a9 commit 562ad23
Show file tree
Hide file tree
Showing 58 changed files with 889 additions and 158 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/build-client-server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ jobs:
secrets: inherit
with:
pr: ${{fromJson(needs.file-check.outputs.pr)}}
matrix: ${{needs.file-check.outputs.matrix_count}}

ci-test-limited-existing-docker-image:
needs: [file-check]
Expand All @@ -143,7 +142,6 @@ jobs:
with:
pr: ${{fromJson(needs.file-check.outputs.pr)}}
previous-workflow-run-id: ${{ fromJson(needs.file-check.outputs.runId) }}
matrix: ${{ needs.file-check.outputs.matrix_count }}

ci-test-limited-result:
needs: [file-check, ci-test-limited]
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci-test-custom-script.yml
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ jobs:
working-directory: "."
run: |
mkdir -p ~/dockerlogs
docker logs appsmith 2>&1 > ~/dockerlogs/dockerlogs-${{ matrix.job }}.txt
docker logs appsmith &> ~/dockerlogs/dockerlogs-${{ matrix.job }}.txt
# Upload docker logs
- name: Upload failed test list artifact
Expand Down
167 changes: 167 additions & 0 deletions app/client/cypress/e2e/Regression/ClientSide/Anvil/AnvilModal_spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import {
agHelper,
anvilLayout,
locators,
propPane,
} from "../../../../support/Objects/ObjectsCore";
import { ANVIL_EDITOR_TEST } from "../../../../support/Constants";
import { anvilLocators } from "../../../../support/Pages/Anvil/Locators";
import EditorNavigation, {
EntityType,
} from "../../../../support/Pages/EditorNavigation";

describe(
`${ANVIL_EDITOR_TEST}: Anvil tests for Modals`,
{ tags: ["@tag.Anvil"] },
() => {
before(() => {
// Cleanup the canvas before each test
agHelper.SelectAllWidgets();
agHelper.PressDelete();
});
it("1. Verify opening a modal by clicking on a button", () => {
// drop a modal widget
anvilLayout.dnd.DragDropNewAnvilWidgetNVerify(
anvilLocators.WDSMODAL,
10,
10,
{
skipWidgetSearch: true,
dropTargetDetails: {
dropModal: true,
},
},
);
// press escape and close modal
agHelper.PressEscape();
// add a button
anvilLayout.dnd.DragDropNewAnvilWidgetNVerify(
anvilLocators.WDSBUTTON,
10,
10,
{
skipWidgetSearch: true,
},
);
propPane.EnterJSContext("onClick", "{{showModal(Modal1.name);}}");
agHelper.GetNClick(locators._enterPreviewMode);
agHelper.GetNClick(anvilLocators.anvilWidgetNameSelector("Button1"));
agHelper.AssertElementExist(
anvilLocators.anvilWidgetNameSelector("Modal1"),
);
});
it("2. Verify closing a modal using the close icon button", () => {
agHelper.GetNClick(
anvilLocators.anvilModalCloseIconButtonSelector("Modal1"),
);
agHelper.AssertElementAbsence(
anvilLocators.anvilWidgetNameSelector("Modal1"),
);
});
it("3. Verify closing a modal by clicking outside the modal area", () => {
// open modal
agHelper.GetNClick(anvilLocators.anvilWidgetNameSelector("Button1"));
agHelper.AssertElementExist(
anvilLocators.anvilWidgetNameSelector("Modal1"),
);
// click on overlay top position
agHelper.GetNClick(
anvilLocators.anvilModalOverlay,
0,
false,
500,
false,
false,
"top",
);
agHelper.AssertElementAbsence(
anvilLocators.anvilWidgetNameSelector("Modal1"),
);
});
it("4. Verify closing a modal using the ESC key", () => {
// open modal
agHelper.GetNClick(anvilLocators.anvilWidgetNameSelector("Button1"));
agHelper.AssertElementExist(
anvilLocators.anvilWidgetNameSelector("Modal1"),
);
// press escape
agHelper.PressEscape();
agHelper.AssertElementAbsence(
anvilLocators.anvilWidgetNameSelector("Modal1"),
);
agHelper.GetNClick(locators._exitPreviewMode);
});
it("5. verify onClose function of Modal", () => {
EditorNavigation.SelectEntityByName("Modal1", EntityType.Widget);
propPane.EnterJSContext("onClose", "{{showAlert('onCloseTest');}}");
agHelper.GetNClick(locators._enterPreviewMode);
//close modal via footer close button
agHelper.GetNClick(
anvilLocators.anvilModalFooterCloseButtonSelector("Modal1"),
);
//verify alert
agHelper.ValidateToastMessage("onCloseTest");
agHelper.GetNClick(locators._exitPreviewMode);
});
it("6. Verify onSubmit function on Modal", () => {
EditorNavigation.SelectEntityByName("Modal1", EntityType.Widget);
propPane.EnterJSContext("onSubmit", "{{showAlert('onSubmitTest');}}");
agHelper.GetNClick(locators._enterPreviewMode);
//close modal via submit button
agHelper.GetNClick(
anvilLocators.anvilModalFooterSubmitButtonSelector("Modal1"),
);
//verify alert
agHelper.ValidateToastMessage("onSubmitTest");
agHelper.GetNClick(locators._exitPreviewMode);
});
it("7. Verify DnD on Modal", () => {
EditorNavigation.SelectEntityByName("Modal1", EntityType.Widget);
// add a widget to modal
anvilLayout.dnd.DragDropNewAnvilWidgetNVerify(
anvilLocators.WDSBUTTON,
10,
10,
{
skipWidgetSearch: true,
dropTargetDetails: {
name: "Modal1",
},
},
);
// verify newly added button
agHelper.AssertElementExist(
anvilLocators.anvilWidgetNameSelector("Button2"),
);
});
it("8. Verify different modal sizes", () => {
// select all widgets and delete
agHelper.PressEscape();
agHelper.SelectAllWidgets();
agHelper.PressDelete();
// add a modal widget
anvilLayout.dnd.DragDropNewAnvilWidgetNVerify(
anvilLocators.WDSMODAL,
10,
10,
{
skipWidgetSearch: true,
dropTargetDetails: {
dropModal: true,
},
},
);
agHelper
.GetElement(anvilLocators.anvilWidgetNameSelector("Modal1"))
.matchImageSnapshot("anvilModalMediumSize");
propPane.SelectPropertiesDropDown("size", "Small");
agHelper
.GetElement(anvilLocators.anvilWidgetNameSelector("Modal1"))
.matchImageSnapshot("anvilModalSmallSize");
propPane.SelectPropertiesDropDown("size", "Large");
agHelper
.GetElement(anvilLocators.anvilWidgetNameSelector("Modal1"))
.matchImageSnapshot("anvilModalLargeSize");
});
},
);
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ describe(
agHelper.AddDsl("onPageLoadActionsDsl");
EditorNavigation.SelectEntityByName("Page1", EntityType.Page);
cy.url().then((url) => {
const pageid = url.split("/")[5]?.split("-").pop();
const pageid = agHelper.extractPageIdFromUrl(url);
expect(pageid).to.not.be.null;
cy.log(pageid + "page id");
cy.request("GET", "api/v1/pages/" + pageid).then((response) => {
const respBody = JSON.stringify(response.body);
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 19 additions & 2 deletions app/client/cypress/support/Pages/AggregateHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,15 +133,32 @@ export class AggregateHelper {
});
}

public extractPageIdFromUrl(url: string): null | string {
const parts = url.split("/");

if (parts[3] !== "app") {
// Not a app URL.
return null;
}

// Extract the page ID, either as an ObjectID or as a UUID.
return (
parts[5]?.match(
/[0-9a-f]{24}$|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,
)?.[0] ?? null
);
}

public AddDsl(
dslFile: string,
elementToCheckPresenceaftDslLoad: string | "" = "", // reloadWithoutCache = true,
) {
let pageid: string, layoutId;
let layoutId;
let appId: string | null;
cy.fixture(dslFile).then((val) => {
cy.url().then((url) => {
pageid = url.split("/")[5]?.split("-").pop() as string;
const pageid = this.extractPageIdFromUrl(url);
expect(pageid).to.not.be.null;
//Fetch the layout id
cy.request("GET", "api/v1/pages/" + pageid).then((response: any) => {
const respBody = JSON.stringify(response.body);
Expand Down
11 changes: 9 additions & 2 deletions app/client/cypress/support/Pages/Anvil/AnvilDnDHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { anvilLocators } from "./Locators";
interface DropTargetDetails {
id?: string;
name?: string;
dropModal?: boolean;
}

interface DragDropWidgetOptions {
Expand All @@ -26,11 +27,14 @@ export class AnvilDnDHelper {
dropTarget?: DropTargetDetails,
) => {
if (dropTarget) {
if (dropTarget.dropModal) {
return anvilLocators.anvilDetachedWidgetsDropArena;
}
if (dropTarget.id) {
return `#${dropTarget.id}`;
}
if (dropTarget.name) {
return `${getWidgetSelector(dropTarget.name.toLowerCase() as any)} ${
return `${anvilLocators.anvilWidgetNameSelector(dropTarget.name)} ${
anvilLocators.anvilDnDListener
}`;
}
Expand Down Expand Up @@ -64,7 +68,10 @@ export class AnvilDnDHelper {
eventConstructor: "MouseEvent",
force: true,
});
cy.get(this.locator._anvilDnDHighlight);
if (!options.dropTargetDetails?.dropModal) {
// no need to show highlight for modal drop
cy.get(this.locator._anvilDnDHighlight);
}
cy.get(dropAreaSelector).first().trigger("mouseup", xPos, yPos, {
eventConstructor: "MouseEvent",
force: true,
Expand Down
5 changes: 5 additions & 0 deletions app/client/cypress/support/Pages/Anvil/AnvilLayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ export class AnvilLayout {
const widgetSelector = anvilLocators.anvilWidgetNameSelector(widgetName);
cy.get(widgetSelector).should("not.exist");
}

public verifyAnvilModalIsClosed(widgetName: string) {
this.verifyWidgetDoesNotExist(widgetName);
}

public verifyParentChildRelationship(parentName: string, childName: string) {
const parentWidgetSelector =
anvilLocators.anvilWidgetNameSelector(parentName);
Expand Down
17 changes: 17 additions & 0 deletions app/client/cypress/support/Pages/Anvil/Locators/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,25 @@ const anvilWidgetBasedSelectors = {
anvilWidgetNameSelector: (widgetName: string) => {
return `[${AnvilDataAttributes.WIDGET_NAME}="${widgetName}"]`;
},
anvilModalOverlay: 'div[data-floating-ui-portal] > div[data-status="open"]',
anvilSelectedWidget: `${anvilWidgetSelector}[data-selected=true]`,
anvilWidgetTypeSelector: (widgetType: string) => {
return `.t--widget-${widgetType}`;
},
};

const anvilModalWidgetSelectors = {
anvilModalCloseIconButtonSelector: (widgetName: string) => {
return `${anvilWidgetBasedSelectors.anvilWidgetNameSelector(widgetName)} > div > div > button[data-icon-button]`;
},
anvilModalFooterCloseButtonSelector: (widgetName: string) => {
return `${anvilWidgetBasedSelectors.anvilWidgetNameSelector(widgetName)} > div > div:last-child > button[data-button]:first-child`;
},
anvilModalFooterSubmitButtonSelector: (widgetName: string) => {
return `${anvilWidgetBasedSelectors.anvilWidgetNameSelector(widgetName)} > div > div:last-child > button[data-button]:last-child`;
},
};

// sections and zones based selectors
const anvilSectionAndZonesBasedSelectors = {
anvilZoneDistributionValue: "[data-testid=t--anvil-zone-distribution-value]",
Expand All @@ -29,6 +42,8 @@ const anvilSectionAndZonesBasedSelectors = {
// dnd based selectors
const anvilDnDBasedSelectors = {
anvilDnDListener: "[data-type=anvil-dnd-listener]",
anvilDetachedWidgetsDropArena:
"[data-testid=t--anvil-detached-widgets-drop-arena]",
mainCanvasSelector: `#${getAnvilCanvasId(MAIN_CONTAINER_WIDGET_ID)}`,
};

Expand All @@ -39,12 +54,14 @@ const anvilWidgetsLocators = {
WDSINPUT: "wdsinputwidget",
WDSSWITCH: "wdsswitchwidget",
WDSCHECKBOX: "wdscheckboxwidget",
WDSMODAL: "wdsmodalwidget",
SECTION: "sectionwidget",
ZONE: "zonewidget",
};

export const anvilLocators = {
...anvilWidgetBasedSelectors,
...anvilModalWidgetSelectors,
...anvilWidgetsLocators,
...anvilSectionAndZonesBasedSelectors,
...anvilDnDBasedSelectors,
Expand Down
3 changes: 2 additions & 1 deletion app/client/cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,8 @@ Cypress.Commands.add("addDsl", (dsl) => {
if (RapidMode.config.enabled && RapidMode.config.usesDSL) {
pageid = RapidMode.config.pageID;
} else {
pageid = url.split("/")[5]?.split("-").pop();
pageid = agHelper.extractPageIdFromUrl(url);
expect(pageid).to.not.be.null;
}

//Fetch the layout id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import clsx from "clsx";
export const Modal = (props: ModalProps) => {
const {
children,
dataAttributes = {},
overlayClassName,
size = "medium",
triggerRef,
...rest
} = props;
Expand All @@ -17,7 +17,7 @@ export const Modal = (props: ModalProps) => {
// don't forget to change the transition-duration CSS as well
<Popover duration={200} modal triggerRef={triggerRef} {...rest}>
<PopoverModalContent
data-size={size}
{...dataAttributes}
overlayClassName={clsx(styles.overlay, overlayClassName)}
>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type {
PopoverProps,
} from "@design-system/headless";
import type { ReactNode } from "react";
import type { SIZES } from "../../../shared";

export interface ModalProps
extends Pick<
Expand All @@ -16,10 +15,7 @@ export interface ModalProps
| "dismissClickOutside"
>,
Pick<PopoverModalContentProps, "overlayClassName"> {
/** Size of the Modal
* @default medium
*/
size?: keyof typeof SIZES;
dataAttributes?: Record<string, string>;
/** The children of the component. */
children: ReactNode;
}
Expand Down
Loading

0 comments on commit 562ad23

Please sign in to comment.