import test from 'node:test' import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import { fileURLToPath } from 'node:url' import { dirname, resolve } from 'node:path' const currentDir = dirname(fileURLToPath(import.meta.url)) function readView(name) { return readFileSync(resolve(currentDir, name), 'utf8') } function cssBlock(source, selector) { const start = source.indexOf(`${selector} {`) assert.notEqual(start, -1) const end = source.indexOf('\n}', start) assert.notEqual(end, -1) return source.slice(start, end) } test('diagram center places the diagram menu above the canvas', () => { const source = readView('DiagramCenterView.vue') const layoutStyle = cssBlock(source, '.diagram-layout') assert.match(layoutStyle, /grid-template-columns:\s*1fr;/) assert.doesNotMatch(layoutStyle, /grid-template-columns:\s*280px\s+minmax\(0,\s*1fr\);/) const sidebarStyle = cssBlock(source, '.diagram-sidebar') assert.match(sidebarStyle, /border-bottom:\s*1px solid #e7ecf3;/) assert.doesNotMatch(sidebarStyle, /border-right:\s*1px solid #e7ecf3;/) const menuStyle = cssBlock(source, '.diagram-kind-list') assert.match(menuStyle, /display:\s*flex;/) assert.match(menuStyle, /flex-wrap:\s*wrap;/) }) test('diagram center uses the full content width', () => { const source = readView('DiagramCenterView.vue') const pageStyle = cssBlock(source, '.diagram-center-page') assert.match(pageStyle, /width:\s*calc\(100% - 40px\);/) assert.match(pageStyle, /max-width:\s*none;/) }) test('diagram center can open directly on a requested diagram tab', () => { const source = readView('DiagramCenterView.vue') assert.equal(source.includes('function normalizeInitialDiagram'), true) assert.equal(source.includes("const activeDiagram = ref(normalizeInitialDiagram(route.query.diagram))"), true) assert.equal(source.includes("return DIAGRAM_QUERY_ALIASES[String(key || '')] || 'three_line_table'"), true) assert.match(source, /module:\s*'module'/) }) test('diagram center promotes the three-line table tab and removes overview', () => { const source = readView('DiagramCenterView.vue') const menuStart = source.indexOf('') assert.notEqual(menuStart, -1) const menuEnd = source.indexOf('', menuStart) assert.notEqual(menuEnd, -1) const menu = source.slice(menuStart, menuEnd) const labels = [...menu.matchAll(/ match[1]) assert.deepEqual(labels, ['three_line_table', 'er', 'module', 'architecture', 'flowchart', 'use_case', 'sequence']) assert.match(menu, />生成 ER 图<\/el-radio-button>/) assert.match(menu, />生成功能模块图<\/el-radio-button>/) assert.match(menu, />生成系统架构图<\/el-radio-button>/) assert.match(menu, />生成流程图<\/el-radio-button>/) assert.match(menu, />生成用例图<\/el-radio-button>/) assert.match(menu, />生成时序图<\/el-radio-button>/) assert.doesNotMatch(source, /overview:\s*'overview'/) assert.doesNotMatch(source, /activeDiagram\.value === 'overview'/) assert.doesNotMatch(source, /function buildOverviewGraph/) }) test('diagram center groups secondary diagrams in a more charts dropdown', () => { const source = readView('DiagramCenterView.vue') assert.match(source, /]+class="more-diagram-dropdown"[^>]+@command="handleMoreDiagramCommand"/) assert.match(source, /]*>生成 UML 类图<\/el-dropdown-item>/) assert.doesNotMatch(source, //) assert.doesNotMatch(source, //) assert.match(source, /生成 UML 活动图<\/el-dropdown-item>/) assert.match(source, /生成 UML 状态图<\/el-dropdown-item>/) assert.match(source, /生成组织结构图<\/el-dropdown-item>/) assert.match(source, /生成数据流图<\/el-dropdown-item>/) assert.match(source, /生成 AI 图<\/el-dropdown-item>/) assert.equal(source.includes('moreDiagramLabel'), true) }) test('diagram center opens UML class diagram editor directly from the more charts dropdown', () => { const source = readView('DiagramCenterView.vue') assert.doesNotMatch(source, /if \(command === 'class_diagram'\)/) assert.match(source, /function handleMoreDiagramCommand\(command\) \{[\s\S]*activeDiagram\.value = command[\s\S]*\}/) }) test('diagram center lets users rename and delete saved diagram drafts', () => { const source = readView('DiagramCenterView.vue') assert.equal(source.includes("import { ElMessage, ElMessageBox } from 'element-plus'"), true) assert.equal(source.includes('deleteProjectDiagram'), true) assert.equal(source.includes('@click.stop="renameSavedDiagram(diagram)"'), true) assert.equal(source.includes('@click.stop="removeSavedDiagram(diagram)"'), true) assert.equal(source.includes('function renameSavedDiagram'), true) assert.equal(source.includes('function removeSavedDiagram'), true) }) test('diagram center centralizes saved diagram lookup for current payloads', () => { const source = readView('DiagramCenterView.vue') assert.equal(source.includes('function findSavedDiagram(diagramType)'), true) assert.equal(source.includes("findSavedDiagram('er')"), true) assert.equal(source.includes("findSavedDiagram('class_diagram')"), true) assert.equal(source.includes('findSavedDiagram(activeDiagram.value)'), true) }) test('diagram center exposes a dedicated use case diagram tab and direct route', () => { const source = readView('DiagramCenterView.vue') assert.equal(source.includes('生成用例图'), true) assert.match(source, /use_case:\s*'use_case'/) assert.equal(source.includes("const useCaseDsl = ref('')"), true) }) test('diagram center removes the edit project action from the page header', () => { const source = readView('DiagramCenterView.vue') assert.doesNotMatch(source, />编辑项目<\/el-button>/) assert.doesNotMatch(source, /router\.push\(\{ path: '\/generate', query: \{ projectId, mode: 'expert' \} \}\)/) }) test('diagram center saves and restores use case diagram DSL payloads', () => { const source = readView('DiagramCenterView.vue') assert.equal(source.includes('function applySavedUseCaseDiagram'), true) assert.equal(source.includes("savedDiagrams.value.find((item) => item.diagramType === 'use_case')"), true) assert.equal(source.includes("diagramType: 'use_case'"), true) assert.equal(source.includes('dsl: useCaseDsl.value'), true) assert.equal(source.includes('graph: useCaseDiagram.value'), true) }) test('diagram center wires use case SVG and PNG export handlers', () => { const source = readView('DiagramCenterView.vue') assert.equal(source.includes('buildUseCaseExportSvg'), true) assert.equal(source.includes('function useCaseSvgText'), true) assert.equal(source.includes('downloadUseCaseSvg'), true) assert.equal(source.includes('downloadUseCasePng'), true) assert.equal(source.includes('useCaseRelationPath'), true) }) test('diagram center exposes UML class diagram in the more charts dropdown and direct route', () => { const source = readView('DiagramCenterView.vue') assert.equal(source.includes('生成 UML 类图'), true) assert.match(source, /class_diagram:\s*'class_diagram'/) assert.equal(source.includes("const classDiagramDsl = ref('')"), true) assert.equal(source.includes("v-else-if=\"activeDiagram === 'class_diagram'\""), true) assert.equal(source.includes('UML 类图 DSL'), true) assert.equal(source.includes('v-model="classDiagramDsl"'), true) }) test('diagram center wires UML class diagram parsing, saving, restoring, and exports', () => { const source = readView('DiagramCenterView.vue') assert.equal(source.includes("from '@/utils/classDiagram'"), true) assert.equal(source.includes('const parsedClassDiagram = computed(() => parseClassDiagramDsl(classDiagramDsl.value))'), true) assert.equal(source.includes('const classDiagram = computed(() => buildClassDiagram(parsedClassDiagram.value'), true) assert.equal(source.includes('const classDiagramStatsText = computed'), true) assert.equal(source.includes('function applySavedClassDiagram'), true) assert.equal(source.includes("savedDiagrams.value.find((item) => item.diagramType === 'class_diagram')"), true) assert.equal(source.includes("diagramType: 'class_diagram'"), true) assert.equal(source.includes('dsl: classDiagramDsl.value'), true) assert.equal(source.includes('graph: classDiagram.value'), true) assert.equal(source.includes('function classDiagramSvgText'), true) assert.equal(source.includes('downloadClassDiagramSvg'), true) assert.equal(source.includes('downloadClassDiagramPng'), true) })