2026-07-10 23:56:06 +08:00
|
|
|
import assert from 'node:assert/strict'
|
|
|
|
|
import { readFile } from 'node:fs/promises'
|
|
|
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
|
import path from 'node:path'
|
|
|
|
|
import { parse as parseSfc } from '@vue/compiler-sfc'
|
|
|
|
|
|
|
|
|
|
const scriptDir = path.dirname(fileURLToPath(import.meta.url))
|
2026-07-23 15:10:13 +08:00
|
|
|
const sourceRoot = path.resolve(scriptDir, '../src')
|
|
|
|
|
const viewPath = path.join(sourceRoot, 'views/data-process/DataProcessListView.vue')
|
|
|
|
|
const [source, apiSource] = await Promise.all([
|
|
|
|
|
readFile(viewPath, 'utf8'),
|
|
|
|
|
readFile(path.join(sourceRoot, 'api/modules/dataProcess.ts'), 'utf8'),
|
|
|
|
|
])
|
2026-07-10 23:56:06 +08:00
|
|
|
const { descriptor, errors } = parseSfc(source, { filename: viewPath })
|
|
|
|
|
|
|
|
|
|
assert.equal(errors.length, 0, `数据处理任务列表模板无法解析:${errors[0]}`)
|
|
|
|
|
assert.ok(descriptor.template?.content.trim(), '数据处理任务列表缺少可渲染模板')
|
|
|
|
|
assert.match(source, /:data="dataList"/, '任务表格必须直接展示完整任务数据')
|
|
|
|
|
assert.doesNotMatch(source, /activeTab|filteredDataList/, '不应保留状态切换筛选逻辑')
|
|
|
|
|
assert.doesNotMatch(source, /全部任务|处理中|已完成/, '不应保留状态切换按钮文案')
|
|
|
|
|
assert.doesNotMatch(source, /capsule-tabs|capsule-tab-item/, '不应保留状态切换专用样式')
|
2026-07-23 15:10:13 +08:00
|
|
|
assert.ok(source.includes("getDataProcessTasks({ page: 1, page_size: 200"), '列表没有通过真实 API 分页加载任务')
|
|
|
|
|
assert.doesNotMatch(source, /usePolling|refreshActiveTasks|startPolling/, '列表不应自动轮询刷新')
|
|
|
|
|
assert.doesNotMatch(source, /toolbar-extra|refreshData|refreshing|fa-refresh/, '列表不应显示手动刷新按钮')
|
|
|
|
|
assert.ok(source.includes('ElMessageBox.confirm('), '删除任务前缺少二次确认')
|
|
|
|
|
assert.ok(source.includes('await deleteDataProcessTask(row.id)'), '删除操作没有调用真实 API')
|
|
|
|
|
assert.ok(!source.includes('TODO: 接入真实接口'), '列表仍包含本地 Mock 任务')
|
|
|
|
|
assert.ok(source.includes('const dataList = ref<DataProcessTask[]>([])'), '任务列表必须以空数组初始化并等待真实 API 数据')
|
2026-07-27 09:50:26 +08:00
|
|
|
assert.match(source, /label="文档数量"[\s\S]*?documentCountLabel\(row as DataProcessTask\)/, '任务列表没有展示真实文档数量')
|
|
|
|
|
assert.match(source, /function documentCountLabel\(task: DataProcessTask\)[\s\S]*?`\$\{safeCount\(task\.source_file_count\)\} 个`/, '文档数量没有使用 source_file_count 或缺少单位')
|
|
|
|
|
assert.match(source, /label="生成个数"[\s\S]*?generatedCountLabel\(row as DataProcessTask\)/, '任务列表没有展示真实生成数量')
|
|
|
|
|
assert.match(source, /function generatedCountLabel\(task: DataProcessTask\)[\s\S]*?`\$\{safeCount\(task\.output_count\)\} 条`/, '生成数量没有使用 output_count 或缺少单位')
|
|
|
|
|
assert.doesNotMatch(source, /label="源数据集"|label="输出数据集"/, '任务列表仍使用旧的数据集列标题')
|
|
|
|
|
for (const label of ['待生成', '生成中', '已生成', '已发布', '生成失败', '已停止']) {
|
|
|
|
|
assert.ok(source.includes(`label: '${label}'`), `任务状态缺少“${label}”`)
|
|
|
|
|
}
|
|
|
|
|
assert.match(source, /task\.status === 'completed'[\s\S]*?task\.output_dataset_id[\s\S]*?已发布[\s\S]*?已生成/, '完成任务没有按当前轮输出指针区分已生成与已发布')
|
|
|
|
|
assert.doesNotMatch(source, /task\.output_datasets\?\.length[\s\S]*?已发布/, '上一轮保留的数据集不应将当前轮标记为已发布')
|
|
|
|
|
for (const [label, type] of [
|
|
|
|
|
['待生成', 'info'],
|
|
|
|
|
['生成中', 'primary'],
|
|
|
|
|
['已生成', 'warning'],
|
|
|
|
|
['已发布', 'success'],
|
|
|
|
|
['生成失败', 'danger'],
|
|
|
|
|
['已停止', 'info'],
|
|
|
|
|
]) {
|
|
|
|
|
assert.ok(source.includes(`label: '${label}', type: '${type}'`), `任务状态“${label}”颜色应为 ${type}`)
|
|
|
|
|
}
|
2026-07-10 23:56:06 +08:00
|
|
|
|
2026-07-23 15:10:13 +08:00
|
|
|
assert.match(apiSource, /export (?:async )?function getDataProcessTasks/, 'API 模块缺少任务列表方法')
|
|
|
|
|
assert.match(apiSource, /export const deleteDataProcessTask/, 'API 模块缺少任务删除方法')
|
|
|
|
|
assert.ok(apiSource.includes("get<DataProcessPage<DataProcessTask>>('/data-process', params)"), '任务列表 API 路径或分页契约不正确')
|
|
|
|
|
assert.ok(apiSource.includes('`/data-process/${encodeURIComponent(taskId)}`'), '任务详情资源路径没有安全编码任务 ID')
|
|
|
|
|
|
|
|
|
|
console.log('数据处理任务列表真实 API 回归检查通过')
|