feat(banner): 首页常驻滚动通知与管理配置及类型样式支持
This commit is contained in:
@@ -292,3 +292,77 @@ test("request logs display user credit billing independently from upstream cost"
|
||||
expect(apiSource).toContain("billingAmountMicrocredits: number");
|
||||
expect(apiSource).toContain("billingAvailable: boolean");
|
||||
});
|
||||
|
||||
test("banner announcement editor keeps title styles through edit, save and status toggle", async () => {
|
||||
const [panelSource, editorSource, sliderSource, apiSource, contentSource, emojiPickerSource, noticeSource] = await Promise.all([
|
||||
Bun.file(new URL("../src/pages/admin/components/admin-banner-announcements-panel.tsx", import.meta.url)).text(),
|
||||
Bun.file(new URL("../src/pages/admin/components/banner-title-editor.tsx", import.meta.url)).text(),
|
||||
Bun.file(new URL("../src/components/layout/banner-announcements-slider.tsx", import.meta.url)).text(),
|
||||
Bun.file(new URL("../src/services/api/announcements.ts", import.meta.url)).text(),
|
||||
Bun.file(new URL("../src/components/layout/banner-announcement-content.tsx", import.meta.url)).text(),
|
||||
Bun.file(new URL("../src/pages/admin/components/banner-notice-emoji-picker.tsx", import.meta.url)).text(),
|
||||
Bun.file(new URL("../src/lib/announcements/banner-notice.ts", import.meta.url)).text(),
|
||||
]);
|
||||
const panel = compactSource(panelSource);
|
||||
const slider = compactSource(sliderSource);
|
||||
|
||||
// 状态开关与保存都必须带上样式分段与通知类型:后端更新走显式字段表,漏传会清空它们。
|
||||
expect(panel).toContain("titleRuns: banner.titleRuns");
|
||||
expect(panel).toContain("titleRuns: runs");
|
||||
expect(panel).toContain("noticeType: selectedNoticeType");
|
||||
expect(panel).toContain("noticeType: normalizeBannerNoticeType(banner.noticeType)");
|
||||
// 编辑入口不能被新建信号重置:父级 createOpen 消费后立即复位,编辑路径不再写回该标志。
|
||||
expect(panel).toContain("onCreateOpenChange(false)");
|
||||
expect(panel).toContain('setDialog({ mode: "edit", banner })');
|
||||
expect(panel).toContain("banner.titleRuns?.length");
|
||||
// AntD 6 用 destroyOnHidden,destroyOnClose 已废弃。
|
||||
expect(panel).toContain("destroyOnHidden");
|
||||
expect(panel).not.toContain("destroyOnClose");
|
||||
// Modal 渲染在 body portal 里,必须挂 admin-modal-root 才能拿到弹窗作用域的强边框 / 分层 token,
|
||||
// 否则编辑器等自绘控件的边框回落到 :root 的 8% 透明度,肉眼不可见。
|
||||
expect(panel).toContain('rootClassName="admin-modal-root"');
|
||||
// 非表单控件不能放进 Form.Item(会被注入 value/onChange/ref)。
|
||||
expect(panel).toContain("<BannerNoticePreview runs={titleRuns} hasLink={Boolean(linkValue?.trim())} noticeType={noticeType} />");
|
||||
// 通知类型在后台要有独立入口;emoji 图标不设独立字段,经编辑器「图标」按钮插入。
|
||||
expect(panel).toContain("<BannerNoticeTypeSelector");
|
||||
expect(panel).not.toContain("BannerNoticeIconPicker");
|
||||
expect(panel).not.toContain("normalizeBannerNoticeIcon");
|
||||
|
||||
expect(editorSource).toContain("applyBannerTitleStyle");
|
||||
expect(editorSource).toContain("clearBannerTitleStyle");
|
||||
expect(editorSource).toContain("lowContrastBannerTitleColors");
|
||||
// 标题是单行语义,Enter 不产生新段落。
|
||||
expect(editorSource).toContain('event.key === "Enter"');
|
||||
// emoji 素材插到光标处、作为普通文本保存(无独立字段、无默认图标)。
|
||||
expect(editorSource).toContain("<BannerNoticeEmojiPopover");
|
||||
expect(editorSource).toContain("insertContent(emoji)");
|
||||
expect(editorSource).not.toContain("BannerAnnouncementIcon");
|
||||
// 预览必须走前台同一份展示单元,否则「预览即前台」不成立。
|
||||
expect(editorSource).toContain("bannerAnnouncementBarStyle(noticeType)");
|
||||
|
||||
// 前台通知条必须按分段渲染,不能退回纯文本;底色来自当前通知的类型,标题前不再有固定图标。
|
||||
expect(sliderSource).toContain("BannerAnnouncementTitle");
|
||||
expect(sliderSource).toContain("currentBanner.titleRuns");
|
||||
expect(slider).toContain("bannerAnnouncementBarStyle(currentBanner.noticeType)");
|
||||
expect(slider).not.toContain("BannerAnnouncementIcon");
|
||||
expect(slider).not.toContain("notice-banner-surface");
|
||||
|
||||
// 展示单元是唯一来源:底色、富文本标题、详情入口都在这里定义,前台与预览共用;
|
||||
// 图标素材是标题文本的一部分,展示单元不再单独处理图标。
|
||||
expect(contentSource).toContain("export function bannerAnnouncementBarStyle");
|
||||
expect(contentSource).toContain("export function BannerAnnouncementLinkHint");
|
||||
expect(contentSource).toContain("export function BannerAnnouncementTitle");
|
||||
expect(contentSource).not.toContain("BannerAnnouncementIcon");
|
||||
|
||||
// emoji 面板:默认收起(Popover 点击触发),插入后不自动关闭,方便连续插入。
|
||||
expect(emojiPickerSource).toContain('trigger="click"');
|
||||
expect(emojiPickerSource).toContain('onPick(item.char)');
|
||||
expect(noticeSource).toContain("BANNER_NOTICE_EMOJI_GROUPS");
|
||||
expect(noticeSource).not.toContain("DEFAULT_ICON");
|
||||
|
||||
expect(apiSource).toContain("titleRuns?: BannerTitleRun[]");
|
||||
expect(apiSource).toContain("noticeType?: BannerNoticeType");
|
||||
expect(apiSource).not.toContain("icon?:");
|
||||
expect(apiSource).toContain("export type { BannerTitleRun }");
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user