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/UsersView.vue"), "utf-8"); const css = readFileSync(join(root, "src/assets/styles.css"), "utf-8"); assertIncludes(view, "view-stack users-page"); assertIncludes(view, "showUserModal"); assertIncludes(view, "openCreateModal"); assertIncludes(view, "closeUserModal"); assertIncludes(view, "user-list-panel"); assertIncludes(view, "user-list-header"); assertIncludes(view, "@click=\"openCreateModal\""); assertIncludes(view, "Teleport to=\"body\""); assertIncludes(view, "modal-backdrop user-modal-backdrop"); assertIncludes(view, "profile-modal user-modal"); assertIncludes(view, "aria-label=\"用户维护\""); assertIncludes(view, "user-modal-form"); assertIncludes(view, "user-modal-fields"); assertIncludes(view, "user-modal-actions"); assertIncludes(view, "@click=\"closeUserModal\""); assertNotIncludes(view, "
\n
\n
\n

新增用户

"); const pageBlock = cssBlock(".users-page"); assertIncludes(pageBlock, "gap: 14px;"); const listPanelBlock = cssBlock(".user-list-panel"); assertIncludes(listPanelBlock, "overflow: hidden;"); const listHeaderBlock = cssBlock(".user-list-header"); assertIncludes(listHeaderBlock, "align-items: center;"); const modalBlock = cssBlock(".user-modal"); assertIncludes(modalBlock, "width: min(920px, 100%);"); assertIncludes(modalBlock, "max-height: min(760px, calc(100vh - 48px));"); const modalFormBlock = cssBlock(".user-modal-form"); assertIncludes(modalFormBlock, "padding: 14px var(--panel-padding) var(--panel-padding);"); const modalFieldsBlock = cssBlock(".user-modal-fields"); assertIncludes(modalFieldsBlock, "grid-template-columns: repeat(4, minmax(0, 1fr));"); const modalActionsBlock = cssBlock(".user-modal-actions"); assertIncludes(modalActionsBlock, "grid-column: 1 / -1;"); assertIncludes(modalActionsBlock, "justify-content: flex-end;"); assertIncludes(css, ".user-modal-fields {\n grid-template-columns: 1fr;"); assertIncludes(css, ".user-modal-actions {\n justify-content: stretch;"); 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, "\\$&"); }