declare const process: { cwd(): string }; declare function require(name: string): { readFileSync?: (path: string, encoding: string) => string; join?: (...parts: string[]) => string; }; const { readFileSync } = require("node:fs"); const { join } = require("node:path"); if (!readFileSync || !join) { throw new Error("测试运行环境缺少文件读取能力"); } const root = process.cwd(); const css = readFileSync(join(root, "src/assets/styles.css"), "utf-8"); const themeStore = readFileSync(join(root, "src/stores/theme.ts"), "utf-8"); const rootBlock = cssBlock(":root"); assertIncludes(rootBlock, "--base-font-size: 14px;"); assertIncludes(rootBlock, "--page-padding: 20px;"); assertIncludes(rootBlock, "--content-gap: 14px;"); assertIncludes(rootBlock, "--panel-padding: 16px;"); const pageHeaderBlock = cssBlock(".page-header"); assertIncludes(pageHeaderBlock, "min-height: 52px;"); assertIncludes(pageHeaderBlock, "padding-bottom: 2px;"); const pageTitleBlock = cssBlock(".page-header h1"); assertIncludes(pageTitleBlock, "font-size: 26px;"); const summaryStripBlock = cssBlock(".summary-strip"); assertIncludes(summaryStripBlock, "display: flex;"); assertIncludes(summaryStripBlock, "padding: 6px 8px;"); const summaryMetricBlock = cssBlock(".summary-metric"); assertIncludes(summaryMetricBlock, "min-height: 42px;"); assertIncludes(summaryMetricBlock, "padding: 5px 8px;"); const summaryIconBlock = cssBlock(".summary-icon"); assertIncludes(summaryIconBlock, "width: 26px;"); assertIncludes(summaryIconBlock, "height: 26px;"); const panelHeaderBlock = cssBlock(".panel-header"); assertIncludes(panelHeaderBlock, "padding: 14px var(--panel-padding);"); const tableFilterBlock = cssBlock(".table-filter-bar"); assertIncludes(tableFilterBlock, "padding: 10px var(--panel-padding);"); assertIncludes(tableFilterBlock, "background: var(--surface);"); const tableHeaderBlock = cssBlock(".data-table th"); assertIncludes(tableHeaderBlock, "position: sticky;"); assertIncludes(tableHeaderBlock, "top: 0;"); const modalBackdropBlock = cssBlock(".modal-backdrop"); assertIncludes(modalBackdropBlock, "backdrop-filter: blur(8px);"); const employeeMetricBlock = cssBlock(".employee-inline-metric"); assertIncludes(employeeMetricBlock, "min-height: 42px;"); assertIncludes(employeeMetricBlock, "padding: 6px 10px;"); const userFormBlock = cssBlock(".user-form"); assertIncludes(userFormBlock, "grid-template-columns: repeat(4, minmax(0, 1fr));"); const paginationActionsBlock = cssBlock(".table-pagination .form-actions"); assertIncludes(paginationActionsBlock, "justify-content: flex-end;"); assertIncludes(paginationActionsBlock, "background: transparent;"); assertIncludes(themeStore, '"--base-font-size": "14px"'); assertIncludes(themeStore, '"--page-padding": "20px"'); assertIncludes(themeStore, '"--content-gap": "14px"'); assertIncludes(themeStore, '"--panel-padding": "16px"'); function cssBlock(selector: string): string { const pattern = new RegExp(`${escapeRegExp(selector)}\\s*\\{([\\s\\S]*?)\\n\\}`, "m"); const match = css.match(pattern); if (!match) { throw new Error(`缺少样式块 ${selector}`); } return match[1]; } function assertIncludes(content: string, expected: string): void { if (!content.includes(expected)) { throw new Error(`期望包含 ${expected}`); } } function assertNotIncludes(content: string, unexpected: string): void { if (content.includes(unexpected)) { throw new Error(`不应包含 ${unexpected}`); } } function escapeRegExp(value: string): string { return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); }