79 lines
3.9 KiB
JavaScript
79 lines
3.9 KiB
JavaScript
import assert from 'node:assert/strict'
|
||
import { readFile } from 'node:fs/promises'
|
||
|
||
const root = new URL('../src/views/m/crm/customer/', import.meta.url)
|
||
const [list, detail, filters, attachments, fields, styles] = await Promise.all([
|
||
readFile(new URL('index.vue', root), 'utf8'),
|
||
readFile(new URL('detail.vue', root), 'utf8'),
|
||
readFile(new URL('CustomerFilters.vue', root), 'utf8'),
|
||
readFile(new URL('CustomerAttachments.vue', root), 'utf8'),
|
||
readFile(new URL('CustomerFields.vue', root), 'utf8'),
|
||
readFile(new URL('customer.scss', root), 'utf8')
|
||
])
|
||
|
||
for (const component of [
|
||
'MpBusinessHeader',
|
||
'MpStatusTabs',
|
||
'MpThreeColumnFilters',
|
||
'MpExpenseCard'
|
||
]) {
|
||
assert.match(list, new RegExp(`<${component}\\b`), `客户列表应使用 ${component}`)
|
||
}
|
||
|
||
const headerAt = list.indexOf('<MpBusinessHeader')
|
||
const tabsAt = list.indexOf('<MpStatusTabs')
|
||
const filtersAt = list.indexOf('<MpThreeColumnFilters')
|
||
const cardAt = list.indexOf('<MpExpenseCard')
|
||
assert.ok(headerAt >= 0 && headerAt < tabsAt && tabsAt < filtersAt && filtersAt < cardAt)
|
||
assert.doesNotMatch(
|
||
list,
|
||
/class="mp-customer-actions"[\s\S]*+ 新增[\s\S]*筛选[\s\S]*显示[\s\S]*刷新/
|
||
)
|
||
assert.match(list, /class="mp-wv-speed-dial"/)
|
||
assert.match(list, /class="mp-customer-batch-bar"/)
|
||
assert.match(list, /requestSnapshot/)
|
||
assert.match(list, /onKeywordUpdate/)
|
||
assert.match(list, /customerTypeIn/)
|
||
assert.match(list, /levelIn/)
|
||
assert.match(list, /:show-actions="!selectMode"/, '选择模式必须隐藏卡片动作栏')
|
||
assert.match(list, /rows\.value = \[\]/, 'reset 请求必须先清空旧列表')
|
||
assert.match(list, /total\.value = 0/, 'reset 请求必须先清空旧总数')
|
||
assert.match(list, /selected\.value = \[\]/, 'reset 请求必须先清空旧选择')
|
||
assert.match(list, /customerCardTime\(row\)/, '客户卡时间必须支持 lastTime/createTime 回退')
|
||
|
||
assert.match(detail, /<MpBusinessHeader\s+title="客户详情"/)
|
||
assert.doesNotMatch(detail, /mp-wv-header__sub/)
|
||
for (const label of ['资料', '跟进记录', '联系人', '商机', '合同', '开票信息', '操作日志']) {
|
||
assert.ok(detail.includes(label), `详情应保留 ${label} Tab`)
|
||
}
|
||
assert.match(detail, /mp-customer-detail-tabs/)
|
||
assert.match(detail, /watch\(/, '详情必须监听复用路由变化')
|
||
assert.match(detail, /route\.params\.id/, '详情必须监听客户 ID')
|
||
assert.match(detail, /route\.query\.tab/, '详情必须监听 query tab')
|
||
assert.match(detail, /requestSeq/, '详情必须隔离过期请求')
|
||
assert.match(detail, /requestedId/, '详情应用响应前必须核对请求客户 ID')
|
||
|
||
assert.match(filters, />关键词</, 'More 面板必须展示并回写顶部关键词')
|
||
assert.match(filters, />业务视图</, 'More 面板必须展示四个业务视图')
|
||
assert.match(filters, /keyword:\s*keyword\.trim\(\)/, 'facet 请求必须传递服务端关键词')
|
||
assert.match(filters, /facets\.value = \{\}/, '筛选上下文变化必须清空 facet')
|
||
assert.match(filters, /facetContextVersion/, '筛选上下文变化必须隔离旧 facet 响应')
|
||
|
||
assert.match(attachments, /<MpAttachmentGrid\b/)
|
||
assert.match(attachments, /type="file"/)
|
||
assert.match(attachments, /:disabled="uploading > 0"/, '上传期间必须禁止再次选择文件')
|
||
assert.match(attachments, /if \(uploading\.value > 0\)/, '上传处理器必须拒绝并发选择')
|
||
assert.match(
|
||
attachments,
|
||
/existing\.push\(url\)[\s\S]*emit\('update:modelValue', existing\.join\(','\)\)/,
|
||
'每个文件成功后必须立即保留并提交引用'
|
||
)
|
||
assert.match(attachments, /ElMessage\.error\(/, '后续文件上传失败必须给出反馈')
|
||
assert.doesNotMatch(fields, /<el-tag\b/, 'WebView 详情字典与状态不得使用桌面深色标签')
|
||
assert.match(fields, /mp-customer-webview-tag/, 'WebView 详情字典与状态必须使用浅底标签')
|
||
assert.match(styles, /\.mp-customer-batch-bar/)
|
||
assert.match(styles, /min-height:\s*44px/)
|
||
assert.match(styles, /\.mp-customer-webview-tag/)
|
||
|
||
console.log('customer DOM contract: PASS')
|