diff --git a/src/features/editor/utils/formHelpers.ts b/src/features/editor/utils/formHelpers.ts
index e7fb173..11e2330 100644
--- a/src/features/editor/utils/formHelpers.ts
+++ b/src/features/editor/utils/formHelpers.ts
@@ -925,11 +925,15 @@ export const computeFormControllerPublicTokens = (
);
const mappedSubmitLabel = (mappedSubmitButton?.props as ButtonBlockProps | undefined)?.label ?? null;
- // FormBlock 은 레이아웃/스타일을 가지지 않는 순수 컨트롤러이므로
- // formClassName 은 고정 기본값만 사용하고, formStyle 은 항상 빈 객체로 유지한다.
+ // FormBlock 은 레이아웃/스타일을 가지지 않는 순수 컨트롤러이지만,
+ // 배경색 커스텀 값을 허용해 form 요소 배경만 제어할 수 있도록 한다.
const formClassNames = ["space-y-3"];
const formStyle: CSSProperties = {};
+ if (props.backgroundColorCustom && props.backgroundColorCustom.trim() !== "") {
+ formStyle.backgroundColor = props.backgroundColorCustom.trim();
+ }
+
return {
fields,
formClassName: formClassNames.join(" "),
diff --git a/tests/unit/PublicPageRendererBlockBackground.spec.tsx b/tests/unit/PublicPageRendererBlockBackground.spec.tsx
index 9314d22..eee9088 100644
--- a/tests/unit/PublicPageRendererBlockBackground.spec.tsx
+++ b/tests/unit/PublicPageRendererBlockBackground.spec.tsx
@@ -88,7 +88,7 @@ describe("PublicPageRenderer - 블록 배경색", () => {
expect(listNoBg!.style.backgroundColor === "" || listNoBg!.style.backgroundColor === "transparent").toBe(true);
});
- it("form 컨트롤러 블록은 프리뷰에서 별도 폼 래퍼를 렌더하지 않아야 한다", () => {
+ it("form 컨트롤러 블록은 backgroundColorCustom 이 설정된 경우에만 폼 요소에 배경색을 적용해야 한다", () => {
const blocksWithBg: Block[] = [
{
id: "form_with_bg",
@@ -107,8 +107,10 @@ describe("PublicPageRenderer - 블록 배경색", () => {
const { queryByTestId, rerender } = render();
- const formWithBg = queryByTestId("preview-form-controller");
- expect(formWithBg).toBeNull();
+ const formWithBg = queryByTestId("preview-form-controller") as HTMLElement | null;
+ expect(formWithBg).not.toBeNull();
+ // JSDOM 은 #111111 을 rgb(17, 17, 17) 형태로 노출한다.
+ expect(formWithBg!.style.backgroundColor).toBe("rgb(17, 17, 17)");
const blocksWithoutBg: Block[] = [
{
@@ -126,8 +128,11 @@ describe("PublicPageRenderer - 블록 배경색", () => {
rerender();
- const formNoBg = queryByTestId("preview-form-controller");
- expect(formNoBg).toBeNull();
+ const formNoBg = queryByTestId("preview-form-controller") as HTMLElement | null;
+ expect(formNoBg).not.toBeNull();
+ expect(
+ formNoBg!.style.backgroundColor === "" || formNoBg!.style.backgroundColor === "transparent",
+ ).toBe(true);
});
it("section 블록은 backgroundColorCustom 이 설정된 경우에만 섹션 요소에 배경색이 적용되어야 한다", () => {
diff --git a/tests/unit/PublicPageRendererFormSubmitMessages.spec.tsx b/tests/unit/PublicPageRendererFormSubmitMessages.spec.tsx
index 4244974..12eb399 100644
--- a/tests/unit/PublicPageRendererFormSubmitMessages.spec.tsx
+++ b/tests/unit/PublicPageRendererFormSubmitMessages.spec.tsx
@@ -12,10 +12,10 @@ describe("PublicPageRenderer - 폼 제출 메시지", () => {
cleanup();
// fetch 목 초기화
// eslint-disable-next-line @typescript-eslint/no-explicit-any
- (global as any).fetch = undefined;
+ (globalThis as any).fetch = undefined;
});
- it("FormBlock 이 있어도 프리뷰에서는 폼 컨트롤러를 렌더하지 않아야 한다 (성공 메시지 설정)", () => {
+ it("성공 응답 시 FormBlock 의 successMessage 를 성공 메시지로 렌더해야 한다", async () => {
const blocks: Block[] = [
{
id: "form_success",
@@ -25,6 +25,9 @@ describe("PublicPageRenderer - 폼 제출 메시지", () => {
submitTarget: "internal",
successMessage: "폼 성공 메시지 (config)",
errorMessage: "폼 에러 메시지 (config)",
+ fields: [
+ { id: "f1", name: "name", label: "이름", type: "text", required: true },
+ ],
fieldIds: [],
submitButtonId: null,
} as any,
@@ -38,16 +41,32 @@ describe("PublicPageRenderer - 폼 제출 메시지", () => {
}),
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
- (global as any).fetch = fetchMock;
+ (globalThis as any).fetch = fetchMock;
render();
- const form = screen.queryByTestId("preview-form-controller");
- expect(form).toBeNull();
- expect(fetchMock).not.toHaveBeenCalled();
+ const form = screen.getByTestId("preview-form-controller") as HTMLFormElement;
+ expect(form).toBeTruthy();
+
+ const input = form.querySelector('input[name="name"]') as HTMLInputElement | null;
+ expect(input).not.toBeNull();
+
+ const submitButton = screen.getByRole("button", { name: "폼 전송" });
+ expect(submitButton).toBeTruthy();
+
+ fireEvent.submit(form);
+
+ await waitFor(() => {
+ expect(fetchMock).toHaveBeenCalledTimes(1);
+ });
+
+ await waitFor(() => {
+ const msg = screen.getByText("폼 성공 메시지 (config)");
+ expect(msg).toBeTruthy();
+ });
});
- it("FormBlock 이 있어도 프리뷰에서는 폼 컨트롤러나 에러 메시지를 렌더하지 않아야 한다", () => {
+ it("실패 응답 시 FormBlock 의 errorMessage 를 에러 메시지로 렌더해야 한다", async () => {
const blocks: Block[] = [
{
id: "form_error",
@@ -57,6 +76,9 @@ describe("PublicPageRenderer - 폼 제출 메시지", () => {
submitTarget: "internal",
successMessage: "폼 성공 메시지 (config)",
errorMessage: "폼 에러 메시지 (config)",
+ fields: [
+ { id: "f1", name: "name", label: "이름", type: "text", required: true },
+ ],
fieldIds: [],
submitButtonId: null,
} as any,
@@ -70,13 +92,25 @@ describe("PublicPageRenderer - 폼 제출 메시지", () => {
}),
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
- (global as any).fetch = fetchMock;
+ (globalThis as any).fetch = fetchMock;
render();
- const form = screen.queryByTestId("preview-form-controller");
- expect(form).toBeNull();
- expect(fetchMock).not.toHaveBeenCalled();
- expect(screen.queryByText("폼 에러 메시지 (config)")).toBeNull();
+ const form = screen.getByTestId("preview-form-controller") as HTMLFormElement;
+ expect(form).toBeTruthy();
+
+ const submitButton = screen.getByRole("button", { name: "폼 전송" });
+ expect(submitButton).toBeTruthy();
+
+ fireEvent.submit(form);
+
+ await waitFor(() => {
+ expect(fetchMock).toHaveBeenCalledTimes(1);
+ });
+
+ await waitFor(() => {
+ const errorMsg = screen.getByText("폼 에러 메시지 (config)");
+ expect(errorMsg).toBeTruthy();
+ });
});
});
diff --git a/tests/unit/formHelpers.spec.ts b/tests/unit/formHelpers.spec.ts
index 73e68f4..2a996a8 100644
--- a/tests/unit/formHelpers.spec.ts
+++ b/tests/unit/formHelpers.spec.ts
@@ -467,9 +467,8 @@ describe("formHelpers.computeFormControllerPublicTokens", () => {
expect(checkboxField.groupLabelImageUrl).toBe("https://example.com/group.png");
expect(tokens.formClassName).toBe("space-y-3");
- // FormBlock 은 이제 레이아웃/배경 스타일을 가지지 않는 순수 컨트롤러이므로,
- // formStyle 은 항상 빈 객체여야 한다.
- expect(tokens.formStyle).toEqual({});
+ // FormBlock 은 레이아웃 정보는 가지지 않지만, backgroundColorCustom 으로 폼 래퍼 배경색만 제어할 수 있다.
+ expect(tokens.formStyle).toEqual({ backgroundColor: "#123456" });
expect(tokens.submitLabel).toBe("컨트롤러 버튼");
});
diff --git a/uploads/20b557a2-e4e8-4682-aa9b-bcb1cb23506d b/uploads/20b557a2-e4e8-4682-aa9b-bcb1cb23506d
new file mode 100644
index 0000000..87ccacf
--- /dev/null
+++ b/uploads/20b557a2-e4e8-4682-aa9b-bcb1cb23506d
@@ -0,0 +1 @@
+dummy-video
\ No newline at end of file
diff --git a/uploads/4205a274-0ee6-443d-963f-4714e64b9c06 b/uploads/4205a274-0ee6-443d-963f-4714e64b9c06
new file mode 100644
index 0000000..87ccacf
--- /dev/null
+++ b/uploads/4205a274-0ee6-443d-963f-4714e64b9c06
@@ -0,0 +1 @@
+dummy-video
\ No newline at end of file
diff --git a/uploads/test-image-1764642023862 b/uploads/test-image-1764642023862
new file mode 100644
index 0000000..0cc5db2
--- /dev/null
+++ b/uploads/test-image-1764642023862
@@ -0,0 +1 @@
+dummy-image
\ No newline at end of file
diff --git a/uploads/test-image-1764642096038 b/uploads/test-image-1764642096038
new file mode 100644
index 0000000..0cc5db2
--- /dev/null
+++ b/uploads/test-image-1764642096038
@@ -0,0 +1 @@
+dummy-image
\ No newline at end of file
diff --git a/uploads/test-section-bg-1764642023931 b/uploads/test-section-bg-1764642023931
new file mode 100644
index 0000000..0cc5db2
--- /dev/null
+++ b/uploads/test-section-bg-1764642023931
@@ -0,0 +1 @@
+dummy-image
\ No newline at end of file
diff --git a/uploads/test-section-bg-1764642096099 b/uploads/test-section-bg-1764642096099
new file mode 100644
index 0000000..0cc5db2
--- /dev/null
+++ b/uploads/test-section-bg-1764642096099
@@ -0,0 +1 @@
+dummy-image
\ No newline at end of file
diff --git a/uploads/test-section-bg-video-1764642023995 b/uploads/test-section-bg-video-1764642023995
new file mode 100644
index 0000000..badc796
--- /dev/null
+++ b/uploads/test-section-bg-video-1764642023995
@@ -0,0 +1 @@
+dummy-section-video
\ No newline at end of file
diff --git a/uploads/test-section-bg-video-1764642096131 b/uploads/test-section-bg-video-1764642096131
new file mode 100644
index 0000000..badc796
--- /dev/null
+++ b/uploads/test-section-bg-video-1764642096131
@@ -0,0 +1 @@
+dummy-section-video
\ No newline at end of file
diff --git a/uploads/test-video-1764642023985 b/uploads/test-video-1764642023985
new file mode 100644
index 0000000..87ccacf
--- /dev/null
+++ b/uploads/test-video-1764642023985
@@ -0,0 +1 @@
+dummy-video
\ No newline at end of file
diff --git a/uploads/test-video-1764642096117 b/uploads/test-video-1764642096117
new file mode 100644
index 0000000..87ccacf
--- /dev/null
+++ b/uploads/test-video-1764642096117
@@ -0,0 +1 @@
+dummy-video
\ No newline at end of file
diff --git a/uploads/test-video-poster-1764642023903 b/uploads/test-video-poster-1764642023903
new file mode 100644
index 0000000..7285c92
--- /dev/null
+++ b/uploads/test-video-poster-1764642023903
@@ -0,0 +1 @@
+dummy-poster
\ No newline at end of file
diff --git a/uploads/test-video-poster-1764642096084 b/uploads/test-video-poster-1764642096084
new file mode 100644
index 0000000..7285c92
--- /dev/null
+++ b/uploads/test-video-poster-1764642096084
@@ -0,0 +1 @@
+dummy-poster
\ No newline at end of file