test-mp-crm-product-dom.mjs 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. import assert from 'node:assert/strict'
  2. import { readFile } from 'node:fs/promises'
  3. const root = new URL('../src/views/m/crm/product/', import.meta.url)
  4. const list = await readFile(new URL('index.vue', root), 'utf8')
  5. const detail = await readFile(new URL('detail.vue', root), 'utf8')
  6. const form = await readFile(new URL('form.vue', root), 'utf8')
  7. const formDialog = await readFile(
  8. new URL('../src/components/business/product-form-dialog/index.vue', import.meta.url),
  9. 'utf8'
  10. )
  11. const order = ['<MpBusinessHeader', '<MpStatusTabs', '<MpThreeColumnFilters', '<MpExpenseCard'].map(
  12. (token) => list.indexOf(token)
  13. )
  14. assert.ok(
  15. order.every((index) => index >= 0),
  16. '产品列表必须使用四个共享展示原语'
  17. )
  18. assert.deepEqual(
  19. [...order].sort((a, b) => a - b),
  20. order,
  21. '列表必须依次为搜索、Tab、三栏筛选、卡片'
  22. )
  23. assert.match(list, /<template #actions>/, '产品卡必须提供虚线操作底栏')
  24. assert.match(list, /编辑/, '产品卡必须提供编辑动作')
  25. assert.match(list, /上架|下架/, '产品卡必须提供上下架动作')
  26. assert.match(list, /删除/, '产品卡必须保留删除动作')
  27. assert.equal(
  28. (list.match(/class="mp-wv-speed-item/g) || []).length,
  29. 2,
  30. 'Speed Dial 必须保留分类和新增双入口'
  31. )
  32. assert.match(list, /requestSeq/, '列表必须用请求序号隔离过期响应')
  33. assert.match(list, /requestSnapshot/, '列表必须用查询快照隔离过期响应')
  34. assert.match(list, /fetchProductColumnFacetValues/, '型号快捷筛选必须来自完整列值接口')
  35. assert.match(list, /role="alert"/, '分页失败必须显示可见错误')
  36. assert.match(list, /categoryRequestSeq/, '分类树加载必须隔离过期响应')
  37. assert.match(
  38. list,
  39. /categoryMapLoaded\.value\s*=\s*false|categoryMapLoaded\s*=\s*false/,
  40. '分类失败必须允许重试'
  41. )
  42. assert.match(
  43. list,
  44. /\.mp-wv-speed-item[\s\S]*min-height:\s*44px/,
  45. 'Speed Dial 项命中高度不得小于 44px'
  46. )
  47. assert.doesNotMatch(
  48. list,
  49. /from 'vue'|from 'vue-router'|from 'element-plus'/,
  50. '不得手工导入自动导入项'
  51. )
  52. assert.match(detail, /title="产品详情"/, '详情顶栏必须使用固定标题')
  53. assert.doesNotMatch(detail, /\{\{\s*headerTitle\s*\}\}/, '详情顶栏不得使用记录标题')
  54. assert.doesNotMatch(detail, /mp-wv-header__sub/, '详情顶栏不得展示副标题')
  55. assert.match(detail, /class="mp-product-detail-tabs"/, '详情必须提供业务 Tab')
  56. assert.match(detail, /mp-wv-fab-bar[\s\S]*mp-wv-touch-target/, '详情底栏按钮必须使用 44px 触达类')
  57. assert.match(detail, /preview-src-list/, '详情必须保留图片预览')
  58. assert.match(detail, /canDeleteByCreator/, '详情必须保留创建人删除权限')
  59. assert.match(detail, /requestSeq/, '详情必须隔离过期详情响应')
  60. assert.match(detail, /requestedId[\s\S]*route\.params\.id/, '详情必须校验 ID 查询快照')
  61. assert.match(detail, /categoryRequestSeq/, '详情分类树必须隔离过期响应')
  62. assert.match(detail, /status-tag--/, '详情状态必须使用 WebView 浅底语义标签')
  63. assert.doesNotMatch(
  64. detail,
  65. /from 'vue'|from 'vue-router'|from 'element-plus'/,
  66. '不得手工导入自动导入项'
  67. )
  68. assert.match(form, /<MpBusinessHeader/, '产品表单必须使用标准头并保留返回入口')
  69. assert.match(formDialog, /72px/, '移动产品图片必须使用约 72×72 宫格')
  70. assert.match(formDialog, /min-height:\s*44px/, '产品表单返回、底栏和上传操作命中高度不得小于 44px')
  71. console.log('product DOM contract: PASS')