test-mp-crm-customer-dom.mjs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. import assert from 'node:assert/strict'
  2. import { readFile } from 'node:fs/promises'
  3. const root = new URL('../src/views/m/crm/customer/', import.meta.url)
  4. const [list, detail, filters, attachments, fields, styles] = await Promise.all([
  5. readFile(new URL('index.vue', root), 'utf8'),
  6. readFile(new URL('detail.vue', root), 'utf8'),
  7. readFile(new URL('CustomerFilters.vue', root), 'utf8'),
  8. readFile(new URL('CustomerAttachments.vue', root), 'utf8'),
  9. readFile(new URL('CustomerFields.vue', root), 'utf8'),
  10. readFile(new URL('customer.scss', root), 'utf8')
  11. ])
  12. for (const component of [
  13. 'MpBusinessHeader',
  14. 'MpStatusTabs',
  15. 'MpThreeColumnFilters',
  16. 'MpExpenseCard'
  17. ]) {
  18. assert.match(list, new RegExp(`<${component}\\b`), `客户列表应使用 ${component}`)
  19. }
  20. const headerAt = list.indexOf('<MpBusinessHeader')
  21. const tabsAt = list.indexOf('<MpStatusTabs')
  22. const filtersAt = list.indexOf('<MpThreeColumnFilters')
  23. const cardAt = list.indexOf('<MpExpenseCard')
  24. assert.ok(headerAt >= 0 && headerAt < tabsAt && tabsAt < filtersAt && filtersAt < cardAt)
  25. assert.doesNotMatch(
  26. list,
  27. /class="mp-customer-actions"[\s\S]*+ 新增[\s\S]*筛选[\s\S]*显示[\s\S]*刷新/
  28. )
  29. assert.match(list, /class="mp-wv-speed-dial"/)
  30. assert.match(list, /class="mp-customer-batch-bar"/)
  31. assert.match(list, /requestSnapshot/)
  32. assert.match(list, /onKeywordUpdate/)
  33. assert.match(list, /customerTypeIn/)
  34. assert.match(list, /levelIn/)
  35. assert.match(list, /:show-actions="!selectMode"/, '选择模式必须隐藏卡片动作栏')
  36. assert.match(list, /rows\.value = \[\]/, 'reset 请求必须先清空旧列表')
  37. assert.match(list, /total\.value = 0/, 'reset 请求必须先清空旧总数')
  38. assert.match(list, /selected\.value = \[\]/, 'reset 请求必须先清空旧选择')
  39. assert.match(list, /customerCardTime\(row\)/, '客户卡时间必须支持 lastTime/createTime 回退')
  40. assert.match(detail, /<MpBusinessHeader\s+title="客户详情"/)
  41. assert.doesNotMatch(detail, /mp-wv-header__sub/)
  42. for (const label of ['资料', '跟进记录', '联系人', '商机', '合同', '开票信息', '操作日志']) {
  43. assert.ok(detail.includes(label), `详情应保留 ${label} Tab`)
  44. }
  45. assert.match(detail, /mp-customer-detail-tabs/)
  46. assert.match(detail, /watch\(/, '详情必须监听复用路由变化')
  47. assert.match(detail, /route\.params\.id/, '详情必须监听客户 ID')
  48. assert.match(detail, /route\.query\.tab/, '详情必须监听 query tab')
  49. assert.match(detail, /requestSeq/, '详情必须隔离过期请求')
  50. assert.match(detail, /requestedId/, '详情应用响应前必须核对请求客户 ID')
  51. assert.match(filters, />关键词</, 'More 面板必须展示并回写顶部关键词')
  52. assert.match(filters, />业务视图</, 'More 面板必须展示四个业务视图')
  53. assert.match(filters, /keyword:\s*keyword\.trim\(\)/, 'facet 请求必须传递服务端关键词')
  54. assert.match(filters, /facets\.value = \{\}/, '筛选上下文变化必须清空 facet')
  55. assert.match(filters, /facetContextVersion/, '筛选上下文变化必须隔离旧 facet 响应')
  56. assert.match(attachments, /<MpAttachmentGrid\b/)
  57. assert.match(attachments, /type="file"/)
  58. assert.match(attachments, /:disabled="uploading > 0"/, '上传期间必须禁止再次选择文件')
  59. assert.match(attachments, /if \(uploading\.value > 0\)/, '上传处理器必须拒绝并发选择')
  60. assert.match(
  61. attachments,
  62. /existing\.push\(url\)[\s\S]*emit\('update:modelValue', existing\.join\(','\)\)/,
  63. '每个文件成功后必须立即保留并提交引用'
  64. )
  65. assert.match(attachments, /ElMessage\.error\(/, '后续文件上传失败必须给出反馈')
  66. assert.doesNotMatch(fields, /<el-tag\b/, 'WebView 详情字典与状态不得使用桌面深色标签')
  67. assert.match(fields, /mp-customer-webview-tag/, 'WebView 详情字典与状态必须使用浅底标签')
  68. assert.match(styles, /\.mp-customer-batch-bar/)
  69. assert.match(styles, /min-height:\s*44px/)
  70. assert.match(styles, /\.mp-customer-webview-tag/)
  71. console.log('customer DOM contract: PASS')