From 76780840611d65bd940a344919720d1a1b6ea19e Mon Sep 17 00:00:00 2001 From: Dhruwang Jariwala <67850763+Dhruwang@users.noreply.github.com> Date: Fri, 16 May 2025 19:15:48 +0530 Subject: [PATCH] fix: unknown property warnings (#5800) --- apps/web/app/api/v1/og/route.tsx | 124 +++++++- .../icons/net-promoter-score-icon.tsx | 4 +- .../src/components/general/question-media.tsx | 2 +- .../questions/open-text-question.test.tsx | 294 +++++++++++++++++- .../questions/open-text-question.tsx | 8 +- 5 files changed, 405 insertions(+), 27 deletions(-) diff --git a/apps/web/app/api/v1/og/route.tsx b/apps/web/app/api/v1/og/route.tsx index bc8b17d5b7..092a016634 100644 --- a/apps/web/app/api/v1/og/route.tsx +++ b/apps/web/app/api/v1/og/route.tsx @@ -7,39 +7,133 @@ export const GET = async (req: NextRequest) => { return new ImageResponse( ( -
+
-
-
-
-

+
+
+
+

{name}

-
-
- + diff --git a/apps/web/modules/ui/components/icons/net-promoter-score-icon.tsx b/apps/web/modules/ui/components/icons/net-promoter-score-icon.tsx index 2d13c580ad..3fc063e84f 100644 --- a/apps/web/modules/ui/components/icons/net-promoter-score-icon.tsx +++ b/apps/web/modules/ui/components/icons/net-promoter-score-icon.tsx @@ -4,8 +4,8 @@ export const NetPromoterScoreIcon: React.FC> = (pr diff --git a/packages/surveys/src/components/general/question-media.tsx b/packages/surveys/src/components/general/question-media.tsx index 91bd97f76c..35810ddbf1 100644 --- a/packages/surveys/src/components/general/question-media.tsx +++ b/packages/surveys/src/components/general/question-media.tsx @@ -53,7 +53,7 @@ export function QuestionMedia({ imgUrl, videoUrl, altText = "Image" }: QuestionM setIsLoading(false); }} allow="accelerometer; autoplay; clipboard-write; encrypted-media; picture-in-picture; web-share" - referrerpolicy="strict-origin-when-cross-origin" + referrerPolicy="strict-origin-when-cross-origin" />
diff --git a/packages/surveys/src/components/questions/open-text-question.test.tsx b/packages/surveys/src/components/questions/open-text-question.test.tsx index 3836123b88..0bff21b187 100644 --- a/packages/surveys/src/components/questions/open-text-question.test.tsx +++ b/packages/surveys/src/components/questions/open-text-question.test.tsx @@ -1,5 +1,5 @@ import "@testing-library/jest-dom/vitest"; -import { cleanup, render, screen } from "@testing-library/preact"; +import { cleanup, fireEvent, render, screen } from "@testing-library/preact"; import userEvent from "@testing-library/user-event"; import { afterEach, describe, expect, test, vi } from "vitest"; import { type TSurveyOpenTextQuestion, TSurveyQuestionTypeEnum } from "@formbricks/types/surveys/types"; @@ -76,10 +76,7 @@ describe("OpenTextQuestion", () => { render(); const input = screen.getByPlaceholderText("Type here..."); - - // Directly set the input value and trigger the input event - Object.defineProperty(input, "value", { value: "Hello" }); - input.dispatchEvent(new Event("input", { bubbles: true })); + fireEvent.input(input, { target: { value: "Hello" } }); expect(onChange).toHaveBeenCalledWith({ q1: "Hello" }); }); @@ -163,4 +160,291 @@ describe("OpenTextQuestion", () => { expect(focusMock).toHaveBeenCalled(); }); + + test("handles input change for textarea with resize functionality", async () => { + // Create a spy on the Element.prototype to monitor style changes + const styleSpy = vi.spyOn(HTMLElement.prototype, "style", "get").mockImplementation( + () => + ({ + height: "", + overflow: "", + }) as CSSStyleDeclaration + ); + const onChange = vi.fn(); + + render( + + ); + + const textarea = screen.getByRole("textbox"); + // Only trigger a regular input event without trying to modify scrollHeight + fireEvent.input(textarea, { target: { value: "Test value for textarea" } }); + + // Check that onChange was called with the correct value + expect(onChange).toHaveBeenCalledWith({ q1: "Test value for textarea" }); + + // Clean up the spy + styleSpy.mockRestore(); + }); + + test("handles textarea resize with different heights", async () => { + // Mock styles and scrollHeight for handleInputResize testing + let heightValue = ""; + let overflowValue = ""; + + // Mock style setter to capture values + const originalSetProperty = CSSStyleDeclaration.prototype.setProperty; + CSSStyleDeclaration.prototype.setProperty = vi.fn(); + + // Mock to capture style changes + Object.defineProperty(HTMLElement.prototype, "style", { + get: vi.fn(() => ({ + height: heightValue, + overflow: overflowValue, + setProperty: (prop: string, value: string) => { + if (prop === "height") heightValue = value; + if (prop === "overflow") overflowValue = value; + }, + })), + }); + + const onChange = vi.fn(); + + render( + + ); + + const textarea = screen.getByRole("textbox"); + + // Simulate normal height (less than max) + const mockNormalEvent = { + target: { + style: { height: "", overflow: "" }, + scrollHeight: 100, // Less than max 160px + }, + }; + + // Get the event handler + const inputHandler = textarea.oninput as EventListener; + if (inputHandler) { + inputHandler(mockNormalEvent as unknown as Event); + } + + // Now simulate text that exceeds max height + const mockOverflowEvent = { + target: { + style: { height: "", overflow: "" }, + scrollHeight: 200, // More than max 160px + }, + }; + + if (inputHandler) { + inputHandler(mockOverflowEvent as unknown as Event); + } + + // Restore the original method + CSSStyleDeclaration.prototype.setProperty = originalSetProperty; + }); + + test("handles form submission by enter key", async () => { + const onSubmit = vi.fn(); + const setTtc = vi.fn(); + + const { container } = render( + + ); + + // Get the form element using container query + const form = container.querySelector("form"); + expect(form).toBeInTheDocument(); + + // Simulate form submission + fireEvent.submit(form!); + + expect(onSubmit).toHaveBeenCalledWith({ q1: "Test submission" }, {}); + expect(setTtc).toHaveBeenCalled(); + }); + + test("applies minLength constraint when configured", () => { + render( + + ); + + const input = screen.getByPlaceholderText("Type here..."); + expect(input).toHaveAttribute("minLength", "5"); + expect(input).toHaveAttribute("maxLength", "100"); + }); + + test("handles video URL in media", () => { + render( + + ); + + expect(screen.getByTestId("question-media")).toBeInTheDocument(); + }); + + test("doesn't autofocus when not current question", () => { + const focusMock = vi.fn(); + window.HTMLElement.prototype.focus = focusMock; + + render( + + ); + + expect(focusMock).not.toHaveBeenCalled(); + }); + + test("handles input change for textarea", async () => { + const onChange = vi.fn(); + + render( + + ); + + const textarea = screen.getByRole("textbox"); + fireEvent.input(textarea, { target: { value: "Long text response" } }); + + expect(onChange).toHaveBeenCalledWith({ q1: "Long text response" }); + }); + + test("applies phone number maxLength constraint", () => { + render(); + + const input = screen.getByPlaceholderText("Type here..."); + expect(input).toHaveAttribute("maxLength", "30"); + }); + + test("renders without subheader when not provided", () => { + const questionWithoutSubheader = { + ...defaultQuestion, + subheader: undefined, + }; + + render(); + expect(screen.getByTestId("mock-subheader")).toHaveTextContent(""); + }); + + test("sets correct tabIndex based on current question status", () => { + // When it's the current question + render(); + const inputCurrent = screen.getByPlaceholderText("Type here..."); + const submitCurrent = screen.getByRole("button", { name: "Submit" }); + + expect(inputCurrent).toHaveAttribute("tabIndex", "0"); + expect(submitCurrent).toHaveAttribute("tabIndex", "0"); + + // When it's not the current question + cleanup(); + render(); + const inputNotCurrent = screen.getByPlaceholderText("Type here..."); + const submitNotCurrent = screen.getByRole("button", { name: "Submit" }); + + expect(inputNotCurrent).toHaveAttribute("tabIndex", "-1"); + expect(submitNotCurrent).toHaveAttribute("tabIndex", "-1"); + }); + + test("applies title attribute for phone input in textarea", () => { + render( + + ); + + const textarea = screen.getByRole("textbox"); + expect(textarea).toHaveAttribute("title", "Please enter a valid phone number"); + }); + + test("applies character limits for textarea", () => { + render( + + ); + + const textarea = screen.getByRole("textbox"); + expect(textarea).toHaveAttribute("minLength", "10"); + expect(textarea).toHaveAttribute("maxLength", "200"); + }); + + test("renders input with no maxLength for other input types", () => { + render( + + ); + + const input = screen.getByPlaceholderText("Type here..."); + // Should be undefined for non-text, non-phone types + expect(input).not.toHaveAttribute("maxLength"); + }); + + test("applies autofocus attribute to textarea when enabled", () => { + render( + + ); + + const textarea = screen.getByRole("textbox"); + expect(textarea).toHaveAttribute("autoFocus"); + }); + + test("does not apply autofocus attribute to textarea when not current question", () => { + render( + + ); + + const textarea = screen.getByRole("textbox"); + expect(textarea).not.toHaveAttribute("autoFocus"); + }); }); diff --git a/packages/surveys/src/components/questions/open-text-question.tsx b/packages/surveys/src/components/questions/open-text-question.tsx index 20ccbea7ab..1fa8032bb1 100644 --- a/packages/surveys/src/components/questions/open-text-question.tsx +++ b/packages/surveys/src/components/questions/open-text-question.tsx @@ -115,8 +115,8 @@ export function OpenTextQuestion({ className="fb-border-border placeholder:fb-text-placeholder fb-text-subheading focus:fb-border-brand fb-bg-input-bg fb-rounded-custom fb-block fb-w-full fb-border fb-p-2 fb-shadow-sm focus:fb-outline-none focus:fb-ring-0 sm:fb-text-sm" pattern={question.inputType === "phone" ? "^[0-9+][0-9+\\- ]*[0-9]$" : ".*"} title={question.inputType === "phone" ? "Enter a valid phone number" : undefined} - minlength={question.inputType === "text" ? question.charLimit?.min : undefined} - maxlength={ + minLength={question.inputType === "text" ? question.charLimit?.min : undefined} + maxLength={ question.inputType === "text" ? question.charLimit?.max : question.inputType === "phone" @@ -143,8 +143,8 @@ export function OpenTextQuestion({ }} className="fb-border-border placeholder:fb-text-placeholder fb-bg-input-bg fb-text-subheading focus:fb-border-brand fb-rounded-custom fb-block fb-w-full fb-border fb-p-2 fb-shadow-sm focus:fb-ring-0 sm:fb-text-sm" title={question.inputType === "phone" ? "Please enter a valid phone number" : undefined} - minlength={question.inputType === "text" ? question.charLimit?.min : undefined} - maxlength={question.inputType === "text" ? question.charLimit?.max : undefined} + minLength={question.inputType === "text" ? question.charLimit?.min : undefined} + maxLength={question.inputType === "text" ? question.charLimit?.max : undefined} /> )} {question.inputType === "text" && question.charLimit?.max !== undefined && (