110 lines
4.0 KiB
TypeScript
110 lines
4.0 KiB
TypeScript
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 appRootBlock = cssBlock("html,\nbody,\n#app");
|
|
assertIncludes(appRootBlock, "max-width: 100%;");
|
|
assertIncludes(appRootBlock, "overflow-x: hidden;");
|
|
|
|
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 bodyBlock = cssBlock("body");
|
|
assertIncludes(bodyBlock, "overflow-x: hidden;");
|
|
|
|
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 tableWrapBlock = cssBlock(".table-wrap");
|
|
assertIncludes(tableWrapBlock, "max-width: 100%;");
|
|
assertIncludes(tableWrapBlock, "min-width: 0;");
|
|
assertIncludes(tableWrapBlock, "contain: inline-size;");
|
|
assertIncludes(tableWrapBlock, "overflow-x: auto;");
|
|
|
|
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: 30px;");
|
|
assertIncludes(employeeMetricBlock, "box-shadow: none;");
|
|
|
|
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, "\\$&");
|
|
}
|