// @vitest-environment jsdom /** * F5(docs/20)页脚/基础展示视觉位置示意: * ① 页脚分组底部渲染 FooterPreview 结构示意图(六处位置标注,已填内容回显); * ② asset 字段的 aspect 占位框(favicon 1:1 / 二维码 4:3,无值虚线框、有值比例预览)。 */ import { afterEach, describe, expect, it, vi } from "vitest"; import { createApp, defineComponent, h, nextTick, ref } from "vue"; import ViewUIPlus from "view-ui-plus"; vi.mock("@/api/module/cms", () => ({ assetUrl: (u: string) => u, uploadUrl: () => "/api/attachment/upload", })); import SiteConfigForm from "@/views/cms/components/SiteConfigForm.vue"; const cleanups: (() => void)[] = []; async function settle(frames = 4) { for (let i = 0; i < frames; i++) { await nextTick(); } await new Promise(r => setTimeout(r, 0)); await nextTick(); } const FOOTER_CONFIG = JSON.stringify({ contact: "电话 0571-88888888", footer_addresses: "潭山校区:南湖路 237 号\n淮河校区:大学路 1 号", qr_wechat: "/cms/upload/qr-wechat.png", social_weibo: "https://weibo.com/xxx", copyright: "XX学校 · 版权所有 © 2026", beian: "浙ICP备XXXXXXXX号-1", logo: "/cms/upload/logo.png", }); async function mountForm(configJson: string, groups?: string[]) { const el = document.createElement("div"); document.body.appendChild(el); const model = ref(configJson); const app = createApp( defineComponent({ render: () => h(SiteConfigForm, { modelValue: model.value, groups, "onUpdate:modelValue": (v: string) => (model.value = v), }), }), ); app.use(ViewUIPlus); app.mount(el); cleanups.push(() => { app.unmount(); el.remove(); }); await settle(); return el; } afterEach(() => { cleanups.splice(0).forEach(fn => fn()); }); describe("F5 视觉位置示意(docs/20)", () => { it("页脚分组:底部渲染结构示意图,六处位置标注 + 已填内容回显", async () => { const el = await mountForm(FOOTER_CONFIG, ["footer"]); const preview = el.querySelector(".footer-preview")!; expect(preview).toBeTruthy(); const text = preview.textContent || ""; // 已填字段实时回显内容(而非占位标注) expect(text).toContain("电话 0571-88888888"); expect(text).toContain("潭山校区:南湖路 237 号"); expect(text).toContain("XX学校 · 版权所有 © 2026"); expect(text).toContain("浙ICP备XXXXXXXX号-1"); expect(preview.querySelector('img[src="/cms/upload/qr-wechat.png"]')).toBeTruthy(); // 未填字段显示位置标注(微博二维码空 → 占位) expect(text).toContain("微博二维码"); expect(text).toContain("社媒图标行"); }); it("页脚全空配置:六处位置标注完整(① 联系方式/② 地址/③ 二维码/④ 社媒/⑤ 版权/⑥ 备案)", async () => { const el = await mountForm("{}", ["footer"]); const text = el.querySelector(".footer-preview")!.textContent || ""; expect(text).toContain("① 联系方式"); expect(text).toContain("② 多校区地址"); expect(text).toContain("微信二维码"); expect(text).toContain("③ 4:3"); expect(text).toContain("④ 社媒图标行"); expect(text).toContain("⑤ 版权文字"); expect(text).toContain("⑥ 备案号"); }); it("基础展示分组:无示意图(仅页脚有)", async () => { const el = await mountForm(FOOTER_CONFIG, ["display"]); expect(el.querySelector(".footer-preview")).toBeFalsy(); }); it("aspect 占位框:二维码无值时 4:3 虚线占位、favicon 无值时 1:1 占位", async () => { const el = await mountForm("{}", ["display", "footer"]); const holders = el.querySelectorAll(".iaf-holder"); expect(holders.length).toBe(3); // favicon 1:1 + 微信/微博 4:3 expect(el.querySelector(".iaf-holder-1x1")).toBeTruthy(); expect(el.querySelectorAll(".iaf-holder-4x3").length).toBe(2); expect(holders[0].textContent).toContain("1:1"); }); });