196 lines
5.1 KiB
TypeScript
196 lines
5.1 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import React from "react";
|
|
import ReactDOMServer from "react-dom/server";
|
|
|
|
import type { Block, ProjectConfig } from "@/features/editor/state/editorStore";
|
|
import { PublicPageRenderer } from "@/features/editor/components/PublicPageRenderer";
|
|
import { buildStaticHtml } from "@/app/api/export/route";
|
|
|
|
describe("프리뷰와 정적 내보내기 일치 (고수준)", () => {
|
|
it("여러 블록이 섞인 페이지에서 핵심 텍스트는 프리뷰와 정적 HTML 모두에 존재해야 한다", () => {
|
|
const blocks: Block[] = [
|
|
{
|
|
id: "text_root",
|
|
type: "text",
|
|
props: {
|
|
text: "텍스트 블록",
|
|
align: "left",
|
|
size: "base",
|
|
},
|
|
} as any,
|
|
{
|
|
id: "btn_root",
|
|
type: "button",
|
|
props: {
|
|
label: "버튼 A",
|
|
href: "#",
|
|
align: "center",
|
|
},
|
|
} as any,
|
|
{
|
|
id: "img_root",
|
|
type: "image",
|
|
props: {
|
|
src: "/api/image/sample-id",
|
|
alt: "이미지 설명",
|
|
align: "center",
|
|
widthMode: "auto",
|
|
borderRadius: "md",
|
|
},
|
|
} as any,
|
|
{
|
|
id: "sec_1",
|
|
type: "section",
|
|
props: {
|
|
background: "primary",
|
|
paddingY: "lg",
|
|
columns: [
|
|
{
|
|
id: "sec_1_col_1",
|
|
span: 12,
|
|
},
|
|
],
|
|
maxWidthMode: "normal",
|
|
gapX: "md",
|
|
alignItems: "top",
|
|
},
|
|
} as any,
|
|
{
|
|
id: "sec_1_text",
|
|
type: "text",
|
|
props: {
|
|
text: "섹션 안 텍스트",
|
|
align: "left",
|
|
size: "base",
|
|
},
|
|
sectionId: "sec_1",
|
|
columnId: "sec_1_col_1",
|
|
} as any,
|
|
{
|
|
id: "sec_1_btn",
|
|
type: "button",
|
|
props: {
|
|
label: "섹션 버튼",
|
|
href: "#",
|
|
align: "left",
|
|
},
|
|
sectionId: "sec_1",
|
|
columnId: "sec_1_col_1",
|
|
} as any,
|
|
{
|
|
id: "divider_1",
|
|
type: "divider",
|
|
props: {
|
|
align: "center",
|
|
thickness: "medium",
|
|
widthMode: "full",
|
|
},
|
|
} as any,
|
|
{
|
|
id: "list_1",
|
|
type: "list",
|
|
props: {
|
|
items: ["리스트 아이템 1", "리스트 아이템 2"],
|
|
ordered: false,
|
|
align: "left",
|
|
},
|
|
} as any,
|
|
{
|
|
id: "form_1",
|
|
type: "form",
|
|
props: {
|
|
kind: "contact",
|
|
submitTarget: "internal",
|
|
// v1 fallback 필드를 사용해 양쪽 렌더러가 동일한 폼 필드를 가지도록 한다.
|
|
fields: [
|
|
{ id: "f_name", name: "name", label: "폼 이름", type: "text", required: true },
|
|
{ id: "f_email", name: "email", label: "폼 이메일", type: "email", required: true },
|
|
{ id: "f_msg", name: "message", label: "폼 메시지", type: "textarea", required: true },
|
|
],
|
|
fieldIds: [],
|
|
submitButtonId: null,
|
|
formWidthMode: "full",
|
|
},
|
|
} as any,
|
|
{
|
|
id: "input_standalone",
|
|
type: "formInput",
|
|
props: {
|
|
label: "입력(단독)",
|
|
formFieldName: "single_input",
|
|
required: true,
|
|
},
|
|
} as any,
|
|
{
|
|
id: "select_standalone",
|
|
type: "formSelect",
|
|
props: {
|
|
label: "선택(단독)",
|
|
formFieldName: "single_select",
|
|
options: [
|
|
{ label: "옵션 A", value: "a" },
|
|
{ label: "옵션 B", value: "b" },
|
|
],
|
|
required: false,
|
|
},
|
|
} as any,
|
|
{
|
|
id: "checkbox_standalone",
|
|
type: "formCheckbox",
|
|
props: {
|
|
groupLabel: "체크 그룹",
|
|
formFieldName: "checks",
|
|
options: [
|
|
{ label: "체크 A", value: "a" },
|
|
{ label: "체크 B", value: "b" },
|
|
],
|
|
required: false,
|
|
},
|
|
} as any,
|
|
{
|
|
id: "radio_standalone",
|
|
type: "formRadio",
|
|
props: {
|
|
groupLabel: "라디오 그룹",
|
|
formFieldName: "radios",
|
|
options: [
|
|
{ label: "라디오 A", value: "a" },
|
|
{ label: "라디오 B", value: "b" },
|
|
],
|
|
required: false,
|
|
},
|
|
} as any,
|
|
];
|
|
|
|
const projectConfig: ProjectConfig = {
|
|
title: "프리뷰-내보내기 고수준 테스트",
|
|
slug: "preview-export-parity",
|
|
canvasPreset: "full",
|
|
};
|
|
|
|
const previewHtml = ReactDOMServer.renderToString(
|
|
React.createElement(PublicPageRenderer, { blocks }),
|
|
);
|
|
|
|
const staticHtml = buildStaticHtml(blocks, projectConfig);
|
|
|
|
const importantStrings = [
|
|
"텍스트 블록",
|
|
"버튼 A",
|
|
"이미지 설명",
|
|
"섹션 안 텍스트",
|
|
"섹션 버튼",
|
|
"리스트 아이템 1",
|
|
"입력(단독)",
|
|
"선택(단독)",
|
|
"체크 A",
|
|
"라디오 A",
|
|
];
|
|
|
|
for (const text of importantStrings) {
|
|
expect(previewHtml).toContain(text);
|
|
expect(staticHtml).toContain(text);
|
|
}
|
|
});
|
|
});
|