diff --git a/app/client/src/widgets/JSONFormWidget/fields/SelectField.test.tsx b/app/client/src/widgets/JSONFormWidget/fields/SelectField.test.tsx
index 7f87b5030d..6d49c89022 100644
--- a/app/client/src/widgets/JSONFormWidget/fields/SelectField.test.tsx
+++ b/app/client/src/widgets/JSONFormWidget/fields/SelectField.test.tsx
@@ -1,5 +1,11 @@
+import { act, render } from "@testing-library/react";
+import { RenderModes } from "constants/WidgetConstants";
+import React from "react";
+import { FormProvider, useForm } from "react-hook-form";
+import { DataType, FieldType, type Schema } from "../constants";
+import FormContext from "../FormContext";
import type { SelectFieldProps } from "./SelectField";
-import { isValid } from "./SelectField";
+import SelectField, { isValid } from "./SelectField";
describe(".isValid", () => {
it("returns true when isRequired is false", () => {
@@ -70,3 +76,219 @@ describe(".isValid", () => {
});
});
});
+
+describe("ResizeObserver", () => {
+ const MockFormWrapper = ({ children }: { children: React.ReactNode }) => {
+ const methods = useForm();
+
+ return (
+
+
+ {children}
+
+
+ );
+ };
+ const defaultProps: SelectFieldProps = {
+ name: "testSelect",
+ fieldClassName: "test-select",
+ propertyPath: "testSelect",
+ schemaItem: {
+ fieldType: FieldType.SELECT,
+ isRequired: false,
+ isVisible: true,
+ isDisabled: false,
+ accessor: "testSelect",
+ identifier: "testSelect",
+ originalIdentifier: "testSelect",
+ position: 0,
+ label: "Test Select",
+ options: [
+ { label: "Option 1", value: "1" },
+ { label: "Option 2", value: "2" },
+ ],
+ children: {} as Schema, // Assuming an empty Schema object or placeholder
+ dataType: DataType.STRING,
+ isCustomField: false,
+ sourceData: null, // Assuming sourceData as null or other default
+ isFilterable: false,
+ filterText: "",
+ serverSideFiltering: false,
+ },
+ };
+ let resizeObserver: ResizeObserverMock;
+
+ beforeAll(() => {
+ (
+ global as unknown as { ResizeObserver: typeof ResizeObserverMock }
+ ).ResizeObserver = ResizeObserverMock;
+ });
+
+ afterAll(() => {
+ delete (global as unknown as { ResizeObserver?: typeof ResizeObserverMock })
+ .ResizeObserver;
+ });
+
+ beforeEach(() => {
+ // Capture the ResizeObserver instance
+ resizeObserver = null!;
+ (
+ global as unknown as { ResizeObserver: typeof ResizeObserverMock }
+ ).ResizeObserver = class extends ResizeObserverMock {
+ constructor(callback: ResizeObserverCallback) {
+ super(callback);
+ resizeObserver = this as ResizeObserverMock;
+ }
+ };
+ });
+
+ it("should setup ResizeObserver on mount", () => {
+ const mockObserver = jest.fn();
+
+ window.ResizeObserver = jest.fn().mockImplementation(() => ({
+ observe: mockObserver,
+ disconnect: jest.fn(),
+ unobserve: jest.fn(),
+ }));
+ render(
+
+
+ ,
+ );
+
+ expect(mockObserver).toHaveBeenCalled();
+ });
+
+ it("should cleanup ResizeObserver on unmount", () => {
+ const { unmount } = render(
+
+
+ ,
+ );
+
+ const disconnectSpy = jest.spyOn(resizeObserver, "disconnect");
+
+ // Unmount component
+ unmount();
+
+ // Verify cleanup
+ expect(disconnectSpy).toHaveBeenCalled();
+ });
+
+ it("initializes with correct width", () => {
+ // Mock offsetWidth
+ const mockOffsetWidth = 200;
+
+ jest
+ .spyOn(HTMLElement.prototype, "offsetWidth", "get")
+ .mockImplementation(() => mockOffsetWidth);
+
+ const { getByTestId } = render(
+
+
+ ,
+ );
+ const content = getByTestId("select-container");
+
+ expect(content.offsetWidth).toBe(mockOffsetWidth);
+ });
+
+ it("updates width when select component is resized", async () => {
+ const widths = [200, 300, 400, 250];
+
+ jest
+ .spyOn(HTMLElement.prototype, "offsetWidth", "get")
+ .mockImplementation(() => widths[0]);
+
+ const { getByTestId } = render(
+
+
+ ,
+ );
+ let triggerElement = getByTestId("select-container");
+
+ widths.forEach((width, index) => {
+ let newWidth = widths[index + 1];
+
+ if (index === widths.length - 1) {
+ newWidth = widths[0];
+ }
+
+ // Verify initial width
+ expect(triggerElement.offsetWidth).toBe(width);
+
+ // Update mock width
+ jest
+ .spyOn(HTMLElement.prototype, "offsetWidth", "get")
+ .mockImplementation(() => newWidth);
+
+ // Trigger resize
+ act(() => {
+ resizeObserver.triggerResize(triggerElement, newWidth);
+ });
+
+ // Verify updated width
+ triggerElement = getByTestId("select-container");
+
+ expect(triggerElement.offsetWidth).toBe(newWidth);
+ });
+ });
+});
+
+type ResizeObserverCallback = (entries: ResizeObserverEntry[]) => void;
+
+class ResizeObserverMock implements ResizeObserver {
+ private callback: ResizeObserverCallback;
+ private elements: Set;
+
+ constructor(callback: ResizeObserverCallback) {
+ this.callback = callback;
+ this.elements = new Set();
+ }
+
+ observe(element: Element): void {
+ this.elements.add(element);
+ }
+
+ unobserve(element: Element): void {
+ this.elements.delete(element);
+ }
+
+ disconnect(): void {
+ this.elements.clear();
+ }
+
+ // Utility method to trigger resize
+ triggerResize(element: Element, width: number): void {
+ if (this.elements.has(element)) {
+ this.callback([
+ {
+ target: element,
+ contentRect: {
+ width,
+ bottom: 0,
+ height: 0,
+ left: 0,
+ right: 0,
+ top: 0,
+ x: 0,
+ y: 0,
+ toJSON: jest.fn(),
+ },
+ borderBoxSize: [{ inlineSize: width, blockSize: 0 }],
+ contentBoxSize: [{ inlineSize: width, blockSize: 0 }],
+ devicePixelContentBoxSize: [{ inlineSize: width, blockSize: 0 }],
+ } as ResizeObserverEntry,
+ ]);
+ }
+ }
+}
diff --git a/app/client/src/widgets/JSONFormWidget/fields/SelectField.tsx b/app/client/src/widgets/JSONFormWidget/fields/SelectField.tsx
index 63bb33ae54..d2ac95ea5c 100644
--- a/app/client/src/widgets/JSONFormWidget/fields/SelectField.tsx
+++ b/app/client/src/widgets/JSONFormWidget/fields/SelectField.tsx
@@ -1,4 +1,11 @@
-import React, { useCallback, useContext, useMemo, useRef } from "react";
+import React, {
+ useCallback,
+ useContext,
+ useMemo,
+ useRef,
+ useEffect,
+ useState,
+} from "react";
import styled from "styled-components";
import { useController } from "react-hook-form";
@@ -101,6 +108,7 @@ function SelectField({
schemaItem.defaultValue,
passedDefaultValue as DefaultValue,
);
+ const [dropDownWidth, setDropDownWidth] = useState(10);
useRegisterFieldValidity({
isValid: isValueValid,
@@ -108,6 +116,29 @@ function SelectField({
fieldType: schemaItem.fieldType,
});
useUnmountFieldValidation({ fieldName: name });
+ useEffect(() => {
+ const updateWidth = () => {
+ if (wrapperRef.current) {
+ setDropDownWidth(wrapperRef.current.offsetWidth);
+ }
+ };
+
+ // Initial width
+ updateWidth();
+
+ // Create ResizeObserver instance
+ const resizeObserver = new ResizeObserver(updateWidth);
+
+ // Start observing the trigger element
+ if (wrapperRef.current) {
+ resizeObserver.observe(wrapperRef.current);
+ }
+
+ // Cleanup
+ return () => {
+ resizeObserver.disconnect();
+ };
+ }, [wrapperRef]);
const [updateFilterText] = useUpdateInternalMetaState({
propertyName: `${name}.filterText`,
@@ -158,7 +189,6 @@ function SelectField({
[onChange, schemaItem.onOptionChange, executeAction],
);
- const dropdownWidth = wrapperRef.current?.clientWidth;
const fieldComponent = useMemo(
() => (
@@ -168,7 +198,7 @@ function SelectField({
boxShadow={schemaItem.boxShadow}
compactMode={false}
disabled={schemaItem.isDisabled}
- dropDownWidth={dropdownWidth || 100}
+ dropDownWidth={dropDownWidth || 100}
hasError={isDirtyRef.current ? !isValueValid : false}
height={10}
isFilterable={schemaItem.isFilterable}
@@ -203,7 +233,7 @@ function SelectField({
isValueValid,
onOptionSelected,
selectedIndex,
- dropdownWidth,
+ dropDownWidth,
fieldClassName,
],
);