Files
ctms/frontend/src/components/Layout.desktop.test.ts
T

488 lines
30 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
const readLayoutSource = () => readFileSync(resolve(__dirname, "./Layout.vue"), "utf8");
const readAppSource = () => readFileSync(resolve(__dirname, "../App.vue"), "utf8");
const readDesktopLayoutSource = () => readFileSync(resolve(__dirname, "./DesktopLayout.vue"), "utf8");
const readWebLayoutSource = () => readFileSync(resolve(__dirname, "./WebLayout.vue"), "utf8");
const readNavigationSource = () => readFileSync(resolve(__dirname, "./layout/navigation.ts"), "utf8");
const readTauriConfigSource = () => readFileSync(resolve(__dirname, "../../src-tauri/tauri.conf.json"), "utf8");
const readDesktopPreferencesSource = () => readFileSync(resolve(__dirname, "../views/DesktopPreferences.vue"), "utf8");
const readDesktopServerSettingsSource = () => readFileSync(resolve(__dirname, "../views/DesktopServerSettings.vue"), "utf8");
const readDesktopUpdateManagerSource = () => readFileSync(resolve(__dirname, "../session/desktopUpdateManager.ts"), "utf8");
const readDesktopActivityCenterSource = () => readFileSync(resolve(__dirname, "../session/desktopActivityCenter.ts"), "utf8");
const readProfileSettingsSource = () => readFileSync(resolve(__dirname, "../views/ProfileSettings.vue"), "utf8");
const readLoginSource = () => readFileSync(resolve(__dirname, "../views/Login.vue"), "utf8");
const readRegisterSource = () => readFileSync(resolve(__dirname, "../views/Register.vue"), "utf8");
const readForgotPasswordSource = () => readFileSync(resolve(__dirname, "../views/ForgotPassword.vue"), "utf8");
const readFileTaskFeedbackSource = () => readFileSync(resolve(__dirname, "../utils/fileTaskFeedback.ts"), "utf8");
const readAttachmentListSource = () => readFileSync(resolve(__dirname, "./attachments/AttachmentList.vue"), "utf8");
const readDocumentDetailSource = () => readFileSync(resolve(__dirname, "../views/documents/DocumentDetail.vue"), "utf8");
const readMainStyleSource = () => readFileSync(resolve(__dirname, "../styles/main.css"), "utf8");
const readFaqSource = () => readFileSync(resolve(__dirname, "../views/Faq.vue"), "utf8");
const readFaqListSource = () => readFileSync(resolve(__dirname, "./FaqList.vue"), "utf8");
const readProjectOverviewSource = () => readFileSync(resolve(__dirname, "../views/ia/ProjectOverview.vue"), "utf8");
describe("desktop layout shell", () => {
it("routes desktop and web shells through the runtime flag", () => {
const source = readLayoutSource();
const app = readAppSource();
expect(source).toContain("const isDesktop = isTauriRuntime()");
expect(source).toContain("<DesktopLayout v-if=\"isDesktop\" />");
expect(source).toContain("<WebLayout v-else />");
expect(app).toContain("const isDesktopRuntime = isTauriRuntime();");
expect(app).toContain('document.body.classList.add("is-desktop-runtime")');
expect(app).toContain('document.body.classList.remove("is-desktop-runtime")');
});
it("uses route-only desktop preference storage", () => {
const source = readDesktopLayoutSource();
const webSource = readWebLayoutSource();
expect(source).toContain("readDesktopFavoriteRoutes");
expect(source).toContain("currentDesktopRoutePreference");
expect(source).toContain("toggleDesktopFavoriteRoute");
expect(source).not.toContain("readDesktopRecentRoutes");
expect(source).not.toContain("recordDesktopRecentRoute");
expect(source).not.toContain("desktopRecentRoutes");
expect(source).not.toContain("最近访问");
expect(webSource).toContain("readDesktopFavoriteRoutes");
expect(webSource).toContain("toggleDesktopFavoriteRoute");
expect(webSource).not.toContain("readDesktopRecentRoutes");
expect(webSource).not.toContain("recordDesktopRecentRoute");
expect(webSource).not.toContain("desktopRecentRoutes");
expect(webSource).not.toContain("最近访问");
});
it("shares active route mapping between web and desktop shells", () => {
const webLayout = readWebLayoutSource();
const desktopLayout = readDesktopLayoutSource();
const navigation = readNavigationSource();
expect(webLayout).toContain("getActiveLayoutPath(route.path)");
expect(desktopLayout).toContain("getActiveLayoutPath(route.path)");
expect(navigation).toContain("export const getActiveLayoutPath");
});
it("keeps desktop context labels and command entry points de-duplicated", () => {
const source = readDesktopLayoutSource();
expect(source).toContain("<h1>{{ TEXT.common.appName }}</h1>");
expect(source).toContain('const DESKTOP_ADMIN_SECTION_LABEL = "系统管理";');
expect(source).toContain('data-tauri-drag-region');
expect(source).toContain('class="toolbar-title"');
expect(source).toContain('class="toolbar-subtitle"');
expect(source).toContain("desktopToolbarTitle");
expect(source).toContain("desktopToolbarSubtitle");
expect(source).not.toContain("desktopBreadcrumbs");
expect(source).not.toContain("breadcrumb-chip");
expect(source).not.toContain("history-controls");
expect(source).not.toContain('title="后退"');
expect(source).not.toContain('title="前进"');
expect(source).not.toContain('title="刷新当前视图"');
expect(source).not.toContain("const sidebarTitle");
expect(source).not.toContain('title="搜索命令"');
expect(source).not.toContain("desktop-statusbar");
expect(source).not.toContain("status-item");
expect(source).not.toContain("accountProjectRoleLabel");
expect(source).not.toContain("projectStatusLabel");
expect(source).toContain("grid-template-rows: 52px auto minmax(0, 1fr);");
expect(source).toContain("const adminDesktopNavigationItems");
expect(source).toContain("const projectDesktopNavigationItems");
expect(source).toContain('id: "desktop:refresh"');
expect(source).toContain('shortcut: "⌘R"');
expect(source).toContain('command === "ctms.desktop.back"');
expect(source).toContain('command === "ctms.desktop.forward"');
expect(source).not.toContain("const root = study.currentStudy?.name || TEXT.menu.currentProject");
});
it("uses macOS overlay titlebar without adding window permissions", () => {
const tauriConfig = readTauriConfigSource();
const layout = readDesktopLayoutSource();
expect(tauriConfig).toContain('"decorations": true');
expect(tauriConfig).toContain('"titleBarStyle": "Overlay"');
expect(tauriConfig).toContain('"hiddenTitle": true');
expect(tauriConfig).toContain('"trafficLightPosition": { "x": 16, "y": 18 }');
expect(layout).toContain("padding: 44px 10px 10px;");
expect(layout).toContain("-webkit-app-region: drag;");
expect(layout).toContain("-webkit-app-region: no-drag;");
expect(layout).not.toContain(["@tauri-apps", "api", "window"].join("/"));
});
it("keeps the desktop sidebar dense enough for navigation-heavy screens", () => {
const layout = readDesktopLayoutSource();
const sidebarHeadStart = layout.indexOf('<header class="sidebar-head">');
const sidebarHeadEnd = layout.indexOf("</header>", sidebarHeadStart);
const sidebarHeadTemplate = layout.slice(sidebarHeadStart, sidebarHeadEnd);
expect(layout).toContain("grid-template-columns: 248px minmax(0, 1fr);");
expect(layout).toContain("padding: 44px 10px 10px;");
expect(layout).toContain("grid-template-columns: auto minmax(0, 1fr);");
expect(layout).toContain("margin-top: 0;");
expect(layout).toContain("const desktopProjectSectionLabel = computed(() => study.currentStudy?.name || TEXT.menu.currentProject)");
expect(layout).toContain("{{ desktopProjectSectionLabel }}");
expect(layout).toContain('command="projectEntry"');
expect(layout).toContain("projectEntryMenuLabel");
expect(layout).toContain("openDesktopProjectEntry");
expect(layout).toContain("padding: 10px 8px 24px;");
expect(layout).toContain("margin-top: 12px;");
expect(layout).toContain("font-size: 14px;");
expect(sidebarHeadTemplate).toContain('<div class="sidebar-title-row">');
expect(sidebarHeadTemplate.indexOf("<h1>{{ TEXT.common.appName }}</h1>")).toBeLessThan(
sidebarHeadTemplate.indexOf('<button v-if="!study.currentStudy" class="study-switcher-trigger empty"'),
);
expect(sidebarHeadTemplate).not.toContain("study-context-badge");
expect(layout).not.toContain(".study-context-badge");
expect(layout).not.toContain(".study-name");
expect(sidebarHeadTemplate).not.toContain('@command="handleStudySwitch"');
expect(layout).not.toContain("handleStudySwitch");
expect(layout).not.toContain("`切换项目:${item.name}`");
expect(layout).not.toContain("grid-template-columns: 272px minmax(0, 1fr);");
expect(layout).not.toContain("padding: 54px 16px 14px;");
expect(layout).not.toContain("padding: 44px 12px 12px;");
});
it("renders desktop preferences as a split settings panel", () => {
const preferences = readDesktopPreferencesSource();
const desktopLayout = readDesktopLayoutSource();
const webLayout = readWebLayoutSource();
expect(preferences).toContain('class="preferences-sidebar"');
expect(preferences).toContain('class="preferences-pane"');
expect(preferences).toContain("const activeSectionId = ref<PreferenceSectionId>");
expect(preferences).toContain('grid-template-columns: 232px minmax(0, 1fr);');
expect(preferences).toContain("height: min(700px, calc(100vh - 96px));");
expect(preferences).toContain("scrollbar-gutter: stable;");
expect(preferences).toContain('{ id: "connection", label: "连接"');
expect(preferences).toContain('{ id: "appearance", label: "外观"');
expect(preferences).toContain('{ id: "notifications", label: "通知"');
expect(preferences).toContain('{ id: "updates", label: "更新"');
expect(preferences).toContain('{ id: "diagnostics", label: "诊断信息"');
expect(preferences).toContain("testDesktopServerConnection");
expect(preferences).toContain("saveDesktopServerConfig");
expect(preferences).toContain("测试连通性");
expect(preferences).not.toContain("保存服务器");
expect(preferences).toContain('ElMessage.success("服务器设置已保存")');
expect(preferences).toContain("ElMessage.error(`保存失败:${message}`)");
expect(preferences).toContain("normalizeDesktopServerUrl");
expect(preferences).toContain("确认切换服务器");
expect(preferences).toContain('<Transition name="preferences-header" mode="out-in">');
expect(preferences).toContain('<Transition name="preferences-panel" mode="out-in">');
expect(preferences).toContain('<Transition name="connection-feedback">');
expect(preferences).toContain("const selectSection = (sectionId: PreferenceSectionId)");
expect(preferences).toContain("const setConnectionPending = (message: string)");
expect(preferences).toContain("const scheduleConnectionPending = (message: string)");
expect(preferences).toContain("}, 180);");
expect(preferences).toContain('scrollTo({ top: 0, behavior: "smooth" })');
expect(preferences).not.toContain("connectionStatus.value = null");
expect(preferences).toContain("min-width: 100px;");
expect(preferences).toContain("connection-feedback-enter-active");
expect(preferences).toContain("@media (prefers-reduced-motion: reduce)");
expect(preferences).toContain(':global([data-ctms-theme="dark"] .desktop-preferences)');
expect(preferences).not.toContain(':global([data-ctms-theme="dark"]) .desktop-preferences');
expect(desktopLayout).toContain(':global([data-ctms-theme="dark"] .desktop-workbench)');
expect(desktopLayout).not.toContain(':global([data-ctms-theme="dark"]) .desktop-workbench');
expect(desktopLayout).toContain('width="940px"');
expect(webLayout).toContain('width="940px"');
expect(desktopLayout).toContain('title: "连接设置"');
expect(webLayout).toContain('title: "连接设置"');
expect(desktopLayout).not.toContain('router.push("/desktop/server-settings")');
expect(webLayout).not.toContain('router.push("/desktop/server-settings")');
expect(desktopLayout).not.toContain('width="720px"');
expect(webLayout).not.toContain('width="720px"');
});
it("keeps client diagnostics out of profile while desktop controls stay in preferences", () => {
const profile = readProfileSettingsSource();
const preferences = readDesktopPreferencesSource();
expect(profile).not.toContain("form-section--desktop");
expect(profile).not.toContain("客户端与通知");
expect(profile).not.toContain("getDesktopNotificationSubscription");
expect(profile).not.toContain("setDesktopNotificationSubscription");
expect(profile).not.toContain("checkDesktopUpdateAndPrompt");
expect(profile).not.toContain("desktopNotificationsEnabled");
expect(profile).not.toContain("form-section--diagnostics");
expect(profile).not.toContain("客户端诊断");
expect(profile).not.toContain("clientDiagnosticRows");
expect(profile).not.toContain("copyClientDiagnostics");
expect(profile).not.toContain("getAppMetadata");
expect(profile).not.toContain("getDesktopServerUrl");
expect(profile).not.toContain("clientRuntime.capabilities");
expect(profile).not.toContain("诊断信息已复制");
expect(preferences).toContain("getDesktopNotificationSubscription");
expect(preferences).toContain("checkDesktopUpdateAndPrompt");
expect(preferences).toContain("clientMetadataRows");
expect(preferences).not.toContain('{ label: "主题"');
expect(preferences).not.toContain('{ label: "服务器"');
});
it("keeps workspace tabs stable and draggable like browser tabs", () => {
const source = readDesktopLayoutSource();
const tabsStart = source.indexOf('<div class="workspace-tabs"');
const tabsEnd = source.indexOf('<main class="desktop-content"', tabsStart);
const tabsTemplate = source.slice(tabsStart, tabsEnd);
expect(tabsTemplate).toContain('@click="navigateWorkspaceTab(item.path)"');
expect(tabsTemplate).toContain('draggable="true"');
expect(tabsTemplate).toContain('@dragstart="startWorkspaceTabDrag(item.path, $event)"');
expect(tabsTemplate).toContain('@drop.prevent="dropWorkspaceTab(item.path, $event)"');
expect(source).toContain("const draggingWorkspaceTabPath = ref(\"\")");
expect(source).toContain("const navigateWorkspaceTab = (path: string) => {");
expect(source).toContain("if (activeMenu.value === path) return;");
expect(source).toContain("next[existingIndex] = { ...next[existingIndex], ...item };");
expect(source).toContain("const [moved] = next.splice(sourceIndex, 1);");
expect(source).toContain("<KeepAlive :max=\"DESKTOP_WORKSPACE_TAB_CACHE_MAX\">");
expect(source).toContain(":key=\"desktopRouteCacheKey(currentRoute)\"");
expect(source).toContain("const desktopRouteCacheKey = (currentRoute: { fullPath: string }) => currentRoute.fullPath;");
expect(source).not.toContain('<div :key="currentRoute.fullPath" class="desktop-route-shell">');
expect(tabsTemplate).not.toContain('@click="router.push(item.path)"');
expect(source).not.toContain(".slice(-7)");
expect(tabsTemplate).toContain('@contextmenu.prevent.stop="openWorkspaceTabMenu(item, $event)"');
expect(tabsTemplate).not.toContain('class="tab-group"');
expect(tabsTemplate).not.toContain("{{ item.group }}");
expect(source).toContain("const lastClosedWorkspaceTab = ref<DesktopRoutePreference | null>(null);");
expect(source).toContain("const workspaceTabMenu = ref<");
expect(source).toContain("const closeOtherWorkspaceTabs = (path: string) => {");
expect(source).toContain("const restoreLastClosedWorkspaceTab = () => {");
expect(source).toContain('id: `workspace-tab:${item.path}`');
expect(source).toContain('title: `切换标签:${item.title}`');
expect(source).toContain('title: "重新打开最近关闭标签"');
});
it("keeps desktop navigation hierarchy aligned with the web sidebar", () => {
const desktopLayout = readDesktopLayoutSource();
const navigation = readNavigationSource();
const sidebarStart = desktopLayout.indexOf('<div class="sidebar-scroll">');
const sidebarEnd = desktopLayout.indexOf("</aside>", sidebarStart);
const sidebarTemplate = desktopLayout.slice(sidebarStart, sidebarEnd);
expect(sidebarTemplate.indexOf('v-if="adminNavigationItems.length"')).toBeLessThan(
sidebarTemplate.indexOf('v-if="projectNavigationItems.length"'),
);
expect(sidebarTemplate).toContain('@click="toggleNavigationGroup(item)"');
expect(sidebarTemplate).toContain(':aria-expanded="isNavigationGroupExpanded(item)"');
expect(sidebarTemplate).toContain('v-show="isNavigationGroupExpanded(item)"');
expect(desktopLayout).toContain("const expandedNavigationGroups = ref<Set<string>>(new Set());");
expect(navigation).toContain('label: "系统设置"');
expect(navigation).toContain('label: "邮件服务"');
expect(navigation).toContain('group: "系统设置"');
expect(navigation).toContain("item.children?.length ? item.children : [item]");
});
it("keeps notification and update preferences lightweight", () => {
const serverSettings = readDesktopServerSettingsSource();
const preferences = readDesktopPreferencesSource();
const desktopUpdateManager = readDesktopUpdateManagerSource();
const desktopLayout = readDesktopLayoutSource();
expect(serverSettings).toContain("connectionDiagnostic");
expect(serverSettings).not.toContain("复制连接诊断");
expect(serverSettings).not.toContain("copyConnectionDiagnostic");
expect(serverSettings).toContain("确认切换服务器");
expect(serverSettings).toContain("切换服务器会退出当前会话并清除当前项目上下文");
expect(serverSettings).toContain("auth.logout({ rememberCurrentStudy: false })");
expect(serverSettings).not.toContain("服务器连接已确认");
expect(preferences).toContain("connectionDiagnostic");
expect(preferences).not.toContain("复制连接诊断");
expect(preferences).not.toContain("copyConnectionDiagnostic");
expect(preferences).not.toContain("服务器连通性正常");
expect(preferences).not.toContain("服务器连接已确认");
expect(preferences).toContain("auth.logout({ rememberCurrentStudy: false })");
expect(preferences).not.toContain("系统通知已开启");
expect(preferences).not.toContain("系统通知已关闭");
expect(preferences).not.toContain("已授权");
expect(preferences).toContain("showNotificationPermissionTag");
expect(preferences).toContain("showSystemNotificationProbe");
expect(preferences).toContain("sendDesktopNotificationTest");
expect(preferences).toContain("测试通知");
expect(preferences).not.toContain("通知诊断");
expect(preferences).not.toContain("更新诊断");
expect(preferences).not.toContain("listenDesktopNotificationDiagnostics");
expect(preferences).not.toContain(["@tauri-apps", "plugin-notification"].join("/"));
expect(preferences).toContain("listenDesktopUpdateStatus");
expect(preferences).toContain("promptForPendingDesktopUpdate");
expect(preferences).toContain("当前已是最新版本");
expect(desktopUpdateManager).not.toContain("当前构建未启用桌面端自动更新");
expect(desktopUpdateManager).not.toContain("该版本已选择稍后提醒");
expect(desktopUpdateManager).toContain("当前已是最新版本");
expect(desktopUpdateManager).toContain("桌面端更新检查失败,请稍后重试或联系管理员。");
expect(desktopLayout).toContain("desktopUpdateNoticeVisible");
expect(desktopLayout).toContain("listenDesktopUpdateStatus");
expect(desktopLayout).toContain("新版本 ${pending.version}");
});
it("routes user-facing file actions through feedback helpers", () => {
const helper = readFileTaskFeedbackSource();
const attachments = readAttachmentListSource();
const documentDetail = readDocumentDetailSource();
expect(helper).toContain("export const pickFilesWithFeedback");
expect(helper).toContain("export const saveFileWithFeedback");
expect(helper).toContain("export const openFileWithFeedback");
expect(helper).toContain("startDesktopActivity");
expect(helper).toContain("finishDesktopActivity");
expect(helper).toContain("desktopFileActivitiesEnabled");
expect(attachments).toContain("pickFilesWithFeedback");
expect(attachments).toContain("saveFileWithFeedback");
expect(attachments).toContain("openFileWithFeedback");
expect(attachments).toContain("startDesktopActivity");
expect(attachments).toContain('title: "下载附件"');
expect(attachments).toContain('title: "上传附件"');
expect(documentDetail).toContain("pickFilesWithFeedback");
expect(documentDetail).toContain("saveFileWithFeedback");
expect(documentDetail).toContain("openFileWithFeedback");
expect(attachments).not.toContain("openFile, pickFiles, saveFile");
expect(documentDetail).not.toContain("openFile, pickFiles, saveFile");
});
it("surfaces persistent desktop activity feedback without local task persistence", () => {
const desktopLayout = readDesktopLayoutSource();
const activityCenter = readDesktopActivityCenterSource();
const updateManager = readDesktopUpdateManagerSource();
expect(desktopLayout).toContain('popper-class="desktop-activity-popover"');
expect(desktopLayout).toContain("desktopActivities");
expect(desktopLayout).toContain("listenDesktopActivities");
expect(desktopLayout).toContain("clearFinishedDesktopActivities");
expect(desktopLayout).toContain("desktopActivityBadgeCount");
expect(activityCenter).toContain("DESKTOP_ACTIVITY_CHANGED_EVENT");
expect(activityCenter).toContain("safeActivityText");
expect(activityCenter).toContain("unsafeActivityTextPattern");
expect(activityCenter).not.toContain("localStorage");
expect(activityCenter).not.toContain("sessionStorage");
expect(updateManager).toContain('title: "检查桌面更新"');
expect(updateManager).toContain('title: "安装桌面更新"');
expect(updateManager).toContain("finishUpdateActivity");
});
it("keeps desktop business pages dense and workbench-like", () => {
const styles = readMainStyleSource();
expect(styles).toContain("/* Desktop workbench density */");
expect(styles).toContain(".desktop-workbench .desktop-route-shell.page");
expect(styles).toContain(".desktop-workbench .desktop-route-shell.ctms-page-shell");
expect(styles).toContain(".desktop-workbench .desktop-route-shell .page-body");
expect(styles).toContain(".desktop-workbench .desktop-route-shell .page-inner");
expect(styles).toContain(".desktop-workbench .desktop-route-shell .overview");
expect(styles).toContain("padding: 0 !important;");
expect(styles).toContain(".desktop-workbench .desktop-route-shell .table-card");
expect(styles).toContain(".desktop-workbench .desktop-route-shell .hero-banner");
expect(styles).toContain(".desktop-workbench .desktop-route-shell .faq-hero");
expect(styles).toContain(".desktop-workbench .desktop-route-shell .page-bg-dots");
expect(styles).toContain(".desktop-workbench .desktop-route-shell .module-placeholder-surface");
expect(styles).toContain("box-shadow: none !important;");
expect(styles).toContain(".desktop-workbench .desktop-route-shell .el-table th.el-table__cell");
expect(styles).toContain("height: 34px;");
expect(styles).toContain(".desktop-workbench .desktop-route-shell .el-table td.el-table__cell");
expect(styles).toContain("padding: 7px 10px;");
expect(styles).toContain(".desktop-workbench .desktop-route-shell .el-pagination");
expect(styles).toContain(".desktop-workbench .desktop-route-shell .el-drawer__body");
expect(styles).toContain(":root[data-ctms-theme=\"dark\"] .desktop-workbench .desktop-route-shell .hero-stat");
});
it("keeps authentication styles self-contained for desktop CSP", () => {
const sources = [
readMainStyleSource(),
readLoginSource(),
readRegisterSource(),
readForgotPasswordSource(),
].join("\n");
expect(sources).not.toContain("fonts.googleapis.com");
expect(sources).not.toContain("fonts.gstatic.com");
expect(sources).not.toMatch(/@import\s+url\(["']https?:\/\//);
});
it("renders Element Plus modals with desktop-native surfaces in the desktop runtime", () => {
const styles = readMainStyleSource();
expect(styles).toContain("/* Desktop runtime modal surfaces */");
expect(styles).toContain("body.is-desktop-runtime .el-overlay");
expect(styles).toContain("left: 0 !important;");
expect(styles).toContain("backdrop-filter: blur(12px) saturate(135%);");
expect(styles).toContain("body.is-desktop-runtime .el-overlay-dialog");
expect(styles).toContain("body.is-desktop-runtime .el-overlay-message-box");
expect(styles).toContain("body.is-desktop-runtime .el-dialog,");
expect(styles).toContain("body.is-desktop-runtime .el-message-box");
expect(styles).toContain("border-radius: 12px;");
expect(styles).toContain("body.is-desktop-runtime .el-dialog__header");
expect(styles).toContain("body.is-desktop-runtime .el-message-box__header");
expect(styles).toContain("body.is-desktop-runtime .desktop-preferences-dialog");
expect(styles).toContain("body.is-desktop-runtime .desktop-preferences-dialog .el-dialog__body");
expect(styles).toContain("body.is-desktop-runtime .desktop-preferences-dialog .el-dialog__body {\n padding: 0;");
expect(styles).toContain("body.is-desktop-runtime .el-message-box__btns");
expect(styles).toContain("body.is-desktop-runtime .dialog-fade-enter-from .el-dialog");
expect(styles).toContain("body.is-desktop-runtime .msgbox-fade-enter-from .el-message-box");
expect(styles).toContain(':root[data-ctms-theme="dark"] body.is-desktop-runtime .desktop-preferences-dialog');
expect(styles).toContain(':root[data-ctms-theme="dark"] body.is-desktop-runtime .el-dialog');
});
it("keeps first-pass desktop content pages workbench-oriented", () => {
const faq = readFaqSource();
const faqList = readFaqListSource();
const projectOverview = readProjectOverviewSource();
expect(faq).toContain("const isDesktop = isTauriRuntime();");
expect(faq).toContain(":class=\"{ 'medical-consult-page--desktop': isDesktop }\"");
expect(faq).toContain('v-if="!isDesktop" class="page-bg-dots"');
expect(faq).toContain('<h1 v-if="!isDesktop"');
expect(faq).toContain('v-else class="desktop-toolbar-meta"');
expect(faq).toContain('v-if="isDesktop" action="faq.create"');
expect(faq).toContain('<div v-if="!isDesktop" class="list-toolbar">');
expect(faq).toContain(".medical-consult-page--desktop .faq-workspace");
expect(faq).toContain("grid-template-columns: 236px minmax(0, 1fr);");
expect(faqList).toContain(":class=\"{ 'faq-list-card--desktop': isDesktop }\"");
expect(faqList).toContain("const isDesktop = isTauriRuntime();");
expect(faqList).toContain(".faq-list-card--desktop .faq-table");
expect(projectOverview).toContain(":class=\"{ 'project-overview--desktop': isDesktop }\"");
expect(projectOverview).not.toContain("overview-summary-strip");
expect(projectOverview).not.toContain("const activeCenterCount");
expect(projectOverview).toContain("desktop-attention-section");
expect(projectOverview).not.toContain("项目关注");
expect(projectOverview).not.toContain("desktop-attention-head");
expect(projectOverview).toContain('class="overview-updated-at">更新 {{ overviewUpdatedAtLabel }}</span>');
expect(projectOverview.indexOf("刷新")).toBeLessThan(projectOverview.indexOf('class="overview-updated-at"'));
expect(projectOverview.indexOf('class="overview-updated-at"')).toBeLessThan(projectOverview.indexOf('class="progress-legend"'));
expect(projectOverview).toContain("overview-workbench");
expect(projectOverview).toContain("enrollment-snapshot");
expect(projectOverview).toContain("desktop-attention-board");
expect(projectOverview).toContain("const stageStatusSummary");
expect(projectOverview).toContain("const activeStageItems");
expect(projectOverview).toContain("const attentionItems");
expect(projectOverview).toContain("grid-template-columns: minmax(620px, 1fr) minmax(300px, 360px);");
expect(projectOverview).toContain("max-height: min(360px, calc(100vh - 300px));");
expect(projectOverview).toContain("@media (max-width: 1240px)");
expect(projectOverview).toContain(".project-overview--desktop .overview-card");
expect(projectOverview).toContain(".project-overview--desktop .overview-card--enrollment");
expect(projectOverview).toContain(".project-overview--desktop :deep(.center-row)");
expect(projectOverview).toContain(".project-overview--desktop :deep(.stage-node)");
});
it("keeps desktop entry surfaces stable at the minimum window size", () => {
const login = readLoginSource();
const serverSettings = readDesktopServerSettingsSource();
const profile = readProfileSettingsSource();
const preferences = readDesktopPreferencesSource();
expect(login).toContain("@media (max-width: 1280px)");
expect(login).toContain("width: min(440px, 100%);");
expect(login).toContain("overflow-wrap: anywhere;");
expect(login).toContain("white-space: nowrap;");
expect(serverSettings).toContain("max-height: calc(100vh - 64px);");
expect(serverSettings).toContain("overflow: auto;");
expect(serverSettings).toContain(".diagnostic-grid code");
expect(profile).toContain('<div class="profile-layout">');
expect(profile).not.toContain('class="page"');
expect(profile).toContain("height: min(720px, calc(100vh - 64px));");
expect(profile).toContain("overflow: hidden;");
expect(profile).not.toContain("overflow: auto;");
expect(profile).toContain("overflow-wrap: anywhere;");
expect(preferences).toContain("flex-wrap: wrap;");
expect(preferences).toContain("overflow-wrap: anywhere;");
});
});