financial_system/frontend/tests/commissionsLayout.test.ts
2026-06-29 14:59:49 +08:00

135 lines
5.6 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 view = readFileSync(join(root, "src/views/CommissionsView.vue"), "utf-8");
const css = readFileSync(join(root, "src/assets/styles.css"), "utf-8");
assertIncludes(view, "view-stack commissions-page");
assertIncludes(view, "summary-strip commission-summary-strip");
assertIncludes(view, "commission-list-panel");
assertIncludes(view, "commission-filter-bar");
assertIncludes(view, "commission-keyword-field");
assertIncludes(view, "commission-month-field");
assertIncludes(view, "commission-search-button");
assertIncludes(view, "row-action-group commission-row-actions");
assertIncludes(view, "table-action-icon");
assertIncludes(view, "title=\"编辑提成\"");
assertIncludes(view, "title=\"删除提成\"");
assertIncludes(view, "sourceTypeLabel");
assertIncludes(view, "manual: \"手工录入\"");
assertIncludes(view, "excel: \"Excel导入\"");
assertIncludes(view, "dingtalk: \"钉钉同步\"");
assertIncludes(view, "{{ sourceTypeLabel(record.source_type) }}");
assertNotIncludes(view, "{{ record.source_type }}");
assertIncludes(view, "openCreateModal");
assertIncludes(view, "showCommissionModal");
assertIncludes(view, "closeCommissionModal");
assertIncludes(view, "Teleport to=\"body\"");
assertIncludes(view, "modal-backdrop commission-modal-backdrop");
assertIncludes(view, "profile-modal commission-modal");
assertIncludes(view, "aria-label=\"提成维护\"");
assertIncludes(view, "commission-form");
assertIncludes(view, "commission-form-grid");
assertIncludes(view, "commission-business-field");
assertIncludes(view, "commission-remark-field");
assertIncludes(view, "rows=\"2\"");
assertIncludes(view, "commission-form-actions");
assertIncludes(view, "@click=\"openCreateModal\"");
assertIncludes(view, "@click=\"closeCommissionModal\"");
assertNotIncludes(view, "field span-row");
assertNotIncludes(view, "commission-entry-panel");
const pageBlock = cssBlock(".commissions-page");
assertIncludes(pageBlock, "gap: 14px;");
const summaryBlock = cssBlock(".commission-summary-strip");
assertIncludes(summaryBlock, "display: grid;");
assertIncludes(summaryBlock, "grid-template-columns: repeat(3, minmax(0, 1fr));");
assertIncludes(summaryBlock, "padding: 8px;");
const summaryMetricBlock = cssBlock(".commission-summary-strip .summary-metric");
assertIncludes(summaryMetricBlock, "min-height: 58px;");
assertIncludes(summaryMetricBlock, "padding: 8px 12px;");
const summaryStrongBlock = cssBlock(".commission-summary-strip .summary-copy strong");
assertIncludes(summaryStrongBlock, "font-size: 20px;");
const listPanelBlock = cssBlock(".commission-list-panel");
assertIncludes(listPanelBlock, "overflow: hidden;");
const listHeaderBlock = cssBlock(".commission-list-header");
assertIncludes(listHeaderBlock, "align-items: center;");
const filterBlock = cssBlock(".commission-filter-bar");
assertIncludes(filterBlock, "grid-template-columns: minmax(220px, 420px) 180px 104px minmax(0, 1fr);");
assertIncludes(filterBlock, "align-items: end;");
const searchButtonBlock = cssBlock(".commission-search-button");
assertIncludes(searchButtonBlock, "width: 104px;");
const rowActionsBlock = cssBlock(".commission-row-actions");
assertIncludes(rowActionsBlock, "display: inline-flex;");
assertIncludes(rowActionsBlock, "justify-content: flex-end;");
const actionIconBlock = cssBlock(".table-action-icon");
assertIncludes(actionIconBlock, "width: 34px;");
assertIncludes(actionIconBlock, "height: 34px;");
const modalBlock = cssBlock(".commission-modal");
assertIncludes(modalBlock, "width: min(900px, 100%);");
assertIncludes(modalBlock, "max-height: min(720px, calc(100vh - 48px));");
const formBlock = cssBlock(".commission-form");
assertIncludes(formBlock, "padding: 14px var(--panel-padding) var(--panel-padding);");
const formGridBlock = cssBlock(".commission-form-grid");
assertIncludes(formGridBlock, "grid-template-columns: minmax(220px, 1.2fr) minmax(160px, 0.75fr) minmax(190px, 1fr) minmax(150px, 0.7fr);");
assertIncludes(formGridBlock, "gap: 10px 14px;");
const remarkFieldBlock = cssBlock(".commission-remark-field textarea");
assertIncludes(remarkFieldBlock, "min-height: 44px;");
assertIncludes(remarkFieldBlock, "max-height: 76px;");
const formActionsBlock = cssBlock(".commission-form-actions");
assertIncludes(formActionsBlock, "align-self: end;");
assertIncludes(formActionsBlock, "justify-content: flex-end;");
assertIncludes(css, ".commission-business-field,\n .commission-remark-field,\n .commission-form-actions {\n grid-column: auto;");
assertIncludes(css, ".commission-summary-strip,\n .commission-form-grid,\n .commission-filter-bar {\n grid-template-columns: 1fr;");
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, "\\$&");
}