forked from jiaoly/financial_system
89 lines
3.4 KiB
TypeScript
89 lines
3.4 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 component = readFileSync(join(root, "src/components/DatePicker.vue"), "utf-8");
|
||
const css = readFileSync(join(root, "src/assets/styles.css"), "utf-8");
|
||
|
||
const datePages = [
|
||
"CommissionsView.vue",
|
||
"MonthlyPayrollView.vue",
|
||
"PayrollView.vue",
|
||
"RealtimeAttendanceView.vue",
|
||
"ReportsView.vue",
|
||
"SalaryProfilesView.vue",
|
||
];
|
||
|
||
for (const page of datePages) {
|
||
const content = readFileSync(join(root, "src/views", page), "utf-8");
|
||
assertIncludes(content, "DatePicker", `${page} 应使用统一 DatePicker 组件`);
|
||
assertNotIncludes(content, "type=\"month\"", `${page} 不应再使用浏览器原生月份选择器`);
|
||
assertNotIncludes(content, "type=\"date\"", `${page} 不应再使用浏览器原生日期选择器`);
|
||
}
|
||
|
||
assertIncludes(component, 'mode: "month" | "date"');
|
||
assertIncludes(component, "date-picker-panel");
|
||
assertIncludes(component, "<Teleport to=\"body\">", "日期面板应挂到 body,避免被父级面板裁剪");
|
||
assertIncludes(component, "panelRef", "日期面板应独立追踪自身节点,保证弹层内部点击不会被当成外部点击");
|
||
assertIncludes(component, "panelStyle", "日期面板应使用运行时坐标定位到触发按钮附近");
|
||
assertIncludes(component, "updatePanelPosition", "日期面板打开、滚动或窗口变化时应重新定位");
|
||
assertIncludes(component, "month-grid");
|
||
assertIncludes(component, "calendar-grid");
|
||
assertIncludes(component, "emit(\"change\"");
|
||
assertIncludes(component, "本月");
|
||
assertIncludes(component, "今天");
|
||
|
||
const pickerBlock = cssBlock(".date-picker");
|
||
assertIncludes(pickerBlock, "position: relative;");
|
||
|
||
const triggerBlock = cssBlock(".date-picker-trigger");
|
||
assertIncludes(triggerBlock, "min-height: var(--control-height);");
|
||
assertIncludes(triggerBlock, "border: 1px solid var(--line);");
|
||
|
||
const panelBlock = cssBlock(".date-picker-panel");
|
||
assertIncludes(panelBlock, "position: fixed;");
|
||
assertIncludes(panelBlock, "max-height: min(420px, calc(100vh - 24px));");
|
||
assertIncludes(panelBlock, "overflow: auto;");
|
||
assertIncludes(panelBlock, "box-shadow: var(--shadow);");
|
||
|
||
const monthGridBlock = cssBlock(".month-grid");
|
||
assertIncludes(monthGridBlock, "grid-template-columns: repeat(4, minmax(0, 1fr));");
|
||
|
||
const calendarGridBlock = cssBlock(".calendar-grid");
|
||
assertIncludes(calendarGridBlock, "grid-template-columns: repeat(7, minmax(0, 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, message?: string): void {
|
||
if (!content.includes(expected)) {
|
||
throw new Error(message || `期望包含 ${expected}`);
|
||
}
|
||
}
|
||
|
||
function assertNotIncludes(content: string, unexpected: string, message?: string): void {
|
||
if (content.includes(unexpected)) {
|
||
throw new Error(message || `不应包含 ${unexpected}`);
|
||
}
|
||
}
|
||
|
||
function escapeRegExp(value: string): string {
|
||
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||
}
|