From d5cc43ae274098f2827dd6688ca7e213a084b737 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Sun, 27 Sep 2026 00:36:49 +0800 Subject: [PATCH] =?UTF-8?q?test(title):=20=E8=A1=A5=E6=A0=87=E9=A2=98?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E5=87=BD=E6=95=B0=E5=8D=95=E6=B5=8B=EF=BC=8C?= =?UTF-8?q?=E5=89=8D=E7=AB=AF=E8=A6=86=E7=9B=96=E7=8E=87=E4=BB=8E49.99%?= =?UTF-8?q?=E6=8F=90=E5=8D=87=E5=88=B050.15%?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 src/test/components/title/titleUtils.test.ts 覆盖: - getFontFamily: 已知字体/未知字体回退/新增书法字体 - getTitlePreset: 合法 key/非法 key - titleStyleConfigToCamel: snake→camel 字段映射/空对象 - camelToTitleStyleConfig: camel→snake 映射/往返一致性 - buildPresetPreviewSettings: 未知 key 透传 base/合法 preset 固定字号 - templateToPreviewSettings: size 缩放逻辑/无 size 默认分支 覆盖率变化: - lines: 49.99% → 50.15%(过50%阈值) - branches: 65.44% → 65.79% - functions: 42.49% → 43.05% - Test Files: 99 passed / 1 skipped(全部通过) --- .../test/components/title/titleUtils.test.ts | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 apps/web/src/test/components/title/titleUtils.test.ts diff --git a/apps/web/src/test/components/title/titleUtils.test.ts b/apps/web/src/test/components/title/titleUtils.test.ts new file mode 100644 index 000000000..d76a6bb62 --- /dev/null +++ b/apps/web/src/test/components/title/titleUtils.test.ts @@ -0,0 +1,190 @@ +/** + * 标题工具函数单测 — 提升覆盖率到 50% 阈值以上 + */ +import { describe, it, expect } from "vitest" +import { + titleStyleConfigToCamel, + camelToTitleStyleConfig, + buildPresetPreviewSettings, + templateToPreviewSettings, +} from "@/components/title/utils" +import { + getFontFamily, + getTitlePreset, + TITLE_PRESETS, + FONT_OPTIONS, +} from "@/components/title/constants" +import { DEFAULT_TITLE_SETTINGS_FULL } from "@/pages/generate/types" +import type { TitleStyleConfig } from "@/components/title/types" +import type { TitleTemplate } from "@/components/title/template-types" + +describe("getFontFamily", () => { + it("已知字体名返回对应 family 栈", () => { + const f = getFontFamily("思源黑体") + expect(f).toContain("Noto Sans SC") + }) + + it("未知字体名回退到思源黑体", () => { + const f = getFontFamily("not-exist-font") + expect(f).toBe(FONT_OPTIONS[4].family) + }) + + it("新增书法字体能查到", () => { + expect(getFontFamily("马善政毛笔")).toContain("Ma Shan Zheng") + expect(getFontFamily("站酷小薇体")).toContain("ZCOOL XiaoWei") + }) +}) + +describe("getTitlePreset", () => { + it("合法 key 返回对应 preset", () => { + const p = getTitlePreset(TITLE_PRESETS[0].key) + expect(p).toBeDefined() + expect(p?.key).toBe(TITLE_PRESETS[0].key) + }) + + it("不存在的 key 返回 undefined", () => { + expect(getTitlePreset("__not_exist__")).toBeUndefined() + }) +}) + +describe("titleStyleConfigToCamel", () => { + it("snake_case 字段映射到 camelCase", () => { + const cfg: Partial = { + font: "思源黑体", + size: 48, + pos_x: 10, + pos_y: 20, + line_height: 1.4, + margin_top: 30, + max_chars_per_line: 8, + stroke_width: 4, + stroke_color: "#000", + shadow_offset_x: 2, + bg_enabled: true, + bg_padding: 12, + bg_radius: 6, + } + const out = titleStyleConfigToCamel(cfg) + expect(out.font).toBe("思源黑体") + expect(out.size).toBe(48) + expect(out.posX).toBe(10) + expect(out.posY).toBe(20) + expect(out.lineHeight).toBe(1.4) + expect(out.marginTop).toBe(30) + expect(out.maxCharsPerLine).toBe(8) + expect(out.strokeWidth).toBe(4) + expect(out.strokeColor).toBe("#000") + expect(out.shadowOffsetX).toBe(2) + expect(out.bgEnabled).toBe(true) + expect(out.bgPadding).toBe(12) + expect(out.bgRadius).toBe(6) + }) + + it("空对象返回空对象", () => { + expect(titleStyleConfigToCamel({})).toEqual({}) + }) +}) + +describe("camelToTitleStyleConfig", () => { + it("camelCase 字段映射到 snake_case", () => { + const out = camelToTitleStyleConfig({ + font: "思源宋体", + size: 36, + posX: 5, + posY: 15, + strokeWidth: 2, + shadowBlur: 8, + bgEnabled: false, + }) + expect(out.font).toBe("思源宋体") + expect(out.pos_x).toBe(5) + expect(out.pos_y).toBe(15) + expect(out.stroke_width).toBe(2) + expect(out.shadow_blur).toBe(8) + expect(out.bg_enabled).toBe(false) + }) + + it("两种转换在已知字段上往返一致", () => { + const camel = { + font: "优设标题黑", + size: 56, + color: "#ffffff", + stroke: true, + strokeWidth: 6, + bold: true, + shadow: true, + shadowOffsetX: 3, + shadowOffsetY: 3, + shadowBlur: 10, + bgEnabled: true, + bgColor: "#000000", + bgPadding: 16, + bgRadius: 8, + } as const + const snake = camelToTitleStyleConfig({ ...camel }) + const back = titleStyleConfigToCamel(snake) + for (const k of Object.keys(camel) as (keyof typeof camel)[]) { + expect(back[k]).toBe(camel[k]) + } + }) +}) + +describe("buildPresetPreviewSettings", () => { + it("未知 preset key 返回 base", () => { + const base = { ...DEFAULT_TITLE_SETTINGS_FULL, size: 32 } + const out = buildPresetPreviewSettings(base, "__no_such_preset__") + expect(out).toBe(base) + }) + + it("合法 preset 返回固定字号并缩放描边/阴影/padding", () => { + const key = TITLE_PRESETS[0].key + const out = buildPresetPreviewSettings(DEFAULT_TITLE_SETTINGS_FULL, key, 56) + expect(out.size).toBe(56) + expect(Array.isArray(out.lineOverrides)).toBe(true) + }) +}) + +describe("templateToPreviewSettings", () => { + it("按模板 style 合并默认值,固定字号并缩放装饰尺寸", () => { + const tpl: TitleTemplate = { + id: "tpl-test", + name: "测试模板", + category: "test", + thumbnail_url: "", + is_system: true, + style: { + font: "思源黑体", + size: 72, + color: "#ffd700", + stroke: true, + stroke_width: 8, + shadow: true, + shadow_offset_x: 4, + shadow_offset_y: 4, + shadow_blur: 12, + bg_enabled: false, + bg_padding: 24, + bg_radius: 0, + }, + } + const out = templateToPreviewSettings(tpl, 48) + expect(out.size).toBe(48) + expect(out.color).toBe("#ffd700") + expect(out.strokeWidth).toBe(Math.max(1, Math.round((48 / 72) * 8))) + expect(out.shadowBlur).toBe(Math.round((48 / 72) * 12)) + expect(Array.isArray(out.lineOverrides)).toBe(true) + }) + + it("模板未指定 size 时使用默认 size(不触发缩放)", () => { + const tpl: TitleTemplate = { + id: "tpl-no-size", + name: "无字号模板", + category: "test", + thumbnail_url: "", + is_system: false, + style: { font: "思源黑体" }, + } + const out = templateToPreviewSettings(tpl, 48) + expect(out.size).toBeDefined() + }) +}) -- 2.54.0