diff --git a/frontend/e2e/helpers/form-builder.ts b/frontend/e2e/helpers/form-builder.ts index fcbd4b1..d5af874 100644 --- a/frontend/e2e/helpers/form-builder.ts +++ b/frontend/e2e/helpers/form-builder.ts @@ -266,12 +266,9 @@ export class FormBuilderPage { } async addField(fieldType: string) { - // Each card shows the field type name as visible text - const card = this.sidebar() - .getByText(fieldType, { exact: true }) - .locator(".."); - await card.hover(); - await card.getByRole("button").click(); + await this.sidebar() + .getByRole("button", { name: fieldType, exact: true }) + .click(); } // The canvas shows "Click on fields to add them…" when empty diff --git a/frontend/e2e/specs/add-fields-palette.spec.ts b/frontend/e2e/specs/add-fields-palette.spec.ts new file mode 100644 index 0000000..03c65e5 --- /dev/null +++ b/frontend/e2e/specs/add-fields-palette.spec.ts @@ -0,0 +1,87 @@ +import { test, expect } from "../fixtures/test-data.fixture"; +import { FormBuilderPage } from "../helpers/form-builder"; + +test.describe("Add Fields palette", () => { + test("renders palette items as buttons without live input previews", async ({ + page, + createForm, + }) => { + const formId = await createForm(); + const builder = new FormBuilderPage(page); + await builder.goto(formId); + + const sidebar = page.locator( + '[data-form-builder-component="form-builder-sidebar"]' + ); + + // Palette items are buttons, named after the fieldtype + await expect( + sidebar.getByRole("button", { name: "Data", exact: true }) + ).toBeVisible(); + await expect( + sidebar.getByRole("button", { name: "Email", exact: true }) + ).toBeVisible(); + await expect( + sidebar.getByRole("button", { name: "Phone", exact: true }) + ).toBeVisible(); + + // No autofillable inputs inside palette buttons (regression: previously + // each palette card mounted a live FormControl, which triggered browser + // autofill on type=email / type=tel / type=password). + const emailBtn = sidebar.getByRole("button", { + name: "Email", + exact: true, + }); + await expect(emailBtn.locator("input")).toHaveCount(0); + + const phoneBtn = sidebar.getByRole("button", { + name: "Phone", + exact: true, + }); + await expect(phoneBtn.locator("input")).toHaveCount(0); + }); + + test("search filters palette items", async ({ page, createForm }) => { + const formId = await createForm(); + const builder = new FormBuilderPage(page); + await builder.goto(formId); + + const sidebar = page.locator( + '[data-form-builder-component="form-builder-sidebar"]' + ); + + await expect( + sidebar.getByRole("button", { name: "Data", exact: true }) + ).toBeVisible(); + await expect( + sidebar.getByRole("button", { name: "Phone", exact: true }) + ).toBeVisible(); + + await sidebar.getByPlaceholder("Search Fields").fill("date"); + + // "Date", "Date Time", "Date Range" remain (case-insensitive substring) + await expect( + sidebar.getByRole("button", { name: "Date", exact: true }) + ).toBeVisible(); + // Unrelated types are filtered out + await expect( + sidebar.getByRole("button", { name: "Phone", exact: true }) + ).toHaveCount(0); + await expect( + sidebar.getByRole("button", { name: "Data", exact: true }) + ).toHaveCount(0); + }); + + test("clicking a palette item adds the field to the canvas", async ({ + page, + createForm, + }) => { + const formId = await createForm(); + const builder = new FormBuilderPage(page); + await builder.goto(formId); + + await expect(builder.canvasEmptyState()).toBeVisible(); + await builder.addField("Email"); + await expect(builder.canvasEmptyState()).not.toBeVisible(); + }); +}); diff --git a/frontend/src/components/FormBuilderSidebar.vue b/frontend/src/components/FormBuilderSidebar.vue index 28f6fc9..d0afd6e 100644 --- a/frontend/src/components/FormBuilderSidebar.vue +++ b/frontend/src/components/FormBuilderSidebar.vue @@ -1,56 +1,108 @@ + + diff --git a/frontend/src/components/builder/sidebar/AddFieldsSection.vue b/frontend/src/components/builder/sidebar/AddFieldsSection.vue index 3ae838d..3b0af22 100644 --- a/frontend/src/components/builder/sidebar/AddFieldsSection.vue +++ b/frontend/src/components/builder/sidebar/AddFieldsSection.vue @@ -1,22 +1,14 @@