77 lines
3.5 KiB
JavaScript
77 lines
3.5 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import { readFile } from 'node:fs/promises'
|
|
|
|
const root = new URL('../src/views/m/crm/product/', import.meta.url)
|
|
const list = await readFile(new URL('index.vue', root), 'utf8')
|
|
const detail = await readFile(new URL('detail.vue', root), 'utf8')
|
|
const form = await readFile(new URL('form.vue', root), 'utf8')
|
|
const formDialog = await readFile(
|
|
new URL('../src/components/business/product-form-dialog/index.vue', import.meta.url),
|
|
'utf8'
|
|
)
|
|
|
|
const order = ['<MpBusinessHeader', '<MpStatusTabs', '<MpThreeColumnFilters', '<MpExpenseCard'].map(
|
|
(token) => list.indexOf(token)
|
|
)
|
|
assert.ok(
|
|
order.every((index) => index >= 0),
|
|
'产品列表必须使用四个共享展示原语'
|
|
)
|
|
assert.deepEqual(
|
|
[...order].sort((a, b) => a - b),
|
|
order,
|
|
'列表必须依次为搜索、Tab、三栏筛选、卡片'
|
|
)
|
|
assert.match(list, /<template #actions>/, '产品卡必须提供虚线操作底栏')
|
|
assert.match(list, /编辑/, '产品卡必须提供编辑动作')
|
|
assert.match(list, /上架|下架/, '产品卡必须提供上下架动作')
|
|
assert.match(list, /删除/, '产品卡必须保留删除动作')
|
|
assert.equal(
|
|
(list.match(/class="mp-wv-speed-item/g) || []).length,
|
|
2,
|
|
'Speed Dial 必须保留分类和新增双入口'
|
|
)
|
|
assert.match(list, /requestSeq/, '列表必须用请求序号隔离过期响应')
|
|
assert.match(list, /requestSnapshot/, '列表必须用查询快照隔离过期响应')
|
|
assert.match(list, /fetchProductColumnFacetValues/, '型号快捷筛选必须来自完整列值接口')
|
|
assert.match(list, /role="alert"/, '分页失败必须显示可见错误')
|
|
assert.match(list, /categoryRequestSeq/, '分类树加载必须隔离过期响应')
|
|
assert.match(
|
|
list,
|
|
/categoryMapLoaded\.value\s*=\s*false|categoryMapLoaded\s*=\s*false/,
|
|
'分类失败必须允许重试'
|
|
)
|
|
assert.match(
|
|
list,
|
|
/\.mp-wv-speed-item[\s\S]*min-height:\s*44px/,
|
|
'Speed Dial 项命中高度不得小于 44px'
|
|
)
|
|
assert.doesNotMatch(
|
|
list,
|
|
/from 'vue'|from 'vue-router'|from 'element-plus'/,
|
|
'不得手工导入自动导入项'
|
|
)
|
|
|
|
assert.match(detail, /title="产品详情"/, '详情顶栏必须使用固定标题')
|
|
assert.doesNotMatch(detail, /\{\{\s*headerTitle\s*\}\}/, '详情顶栏不得使用记录标题')
|
|
assert.doesNotMatch(detail, /mp-wv-header__sub/, '详情顶栏不得展示副标题')
|
|
assert.match(detail, /class="mp-product-detail-tabs"/, '详情必须提供业务 Tab')
|
|
assert.match(detail, /mp-wv-fab-bar[\s\S]*mp-wv-touch-target/, '详情底栏按钮必须使用 44px 触达类')
|
|
assert.match(detail, /preview-src-list/, '详情必须保留图片预览')
|
|
assert.match(detail, /canDeleteByCreator/, '详情必须保留创建人删除权限')
|
|
assert.match(detail, /requestSeq/, '详情必须隔离过期详情响应')
|
|
assert.match(detail, /requestedId[\s\S]*route\.params\.id/, '详情必须校验 ID 查询快照')
|
|
assert.match(detail, /categoryRequestSeq/, '详情分类树必须隔离过期响应')
|
|
assert.match(detail, /status-tag--/, '详情状态必须使用 WebView 浅底语义标签')
|
|
assert.doesNotMatch(
|
|
detail,
|
|
/from 'vue'|from 'vue-router'|from 'element-plus'/,
|
|
'不得手工导入自动导入项'
|
|
)
|
|
|
|
assert.match(form, /<MpBusinessHeader/, '产品表单必须使用标准头并保留返回入口')
|
|
assert.match(formDialog, /72px/, '移动产品图片必须使用约 72×72 宫格')
|
|
assert.match(formDialog, /min-height:\s*44px/, '产品表单返回、底栏和上传操作命中高度不得小于 44px')
|
|
|
|
console.log('product DOM contract: PASS')
|