Files
shanxia2.0/web-admin/scripts/test-mp-crm-primitives.mjs
2026-10-19 18:28:02 +08:00

222 lines
8.2 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from 'node:assert/strict'
import { mkdir } from 'node:fs/promises'
import { chromium } from 'playwright'
const origin = process.env.MP_CRM_PRIMITIVES_ORIGIN || 'http://localhost:3006'
const artifacts = '/tmp/shanxia-mp-crm-primitives'
await mkdir(artifacts, { recursive: true })
const browser = await chromium.launch({ headless: true, channel: 'chrome' })
const context = await browser.newContext({
viewport: { width: 375, height: 812 },
isMobile: true,
deviceScaleFactor: 1
})
const page = await context.newPage()
const pageErrors = []
page.on('pageerror', (error) => pageErrors.push(error.message))
try {
await page.goto(origin, { waitUntil: 'domcontentloaded' })
await page.evaluate(async () => {
const [
{ createApp, h, ref },
{ default: Header },
{ default: Tabs },
{ default: Filters },
{ default: Card },
{ default: Attachments },
{ default: Timeline }
] = await Promise.all([
import('/node_modules/.vite/deps/vue.js'),
import('/src/components/mp/MpBusinessHeader.vue'),
import('/src/components/mp/MpStatusTabs.vue'),
import('/src/components/mp/MpThreeColumnFilters.vue'),
import('/src/components/mp/MpExpenseCard.vue'),
import('/src/components/mp/MpAttachmentGrid.vue'),
import('/src/components/mp/MpApprovalTimeline.vue'),
import('/src/styles/mp-webview.scss')
])
document.body.innerHTML = '<div id="primitive-fixture"></div>'
document.body.style.margin = '0'
window.__primitiveEvents = []
createApp({
setup() {
const keyword = ref('')
const status = ref('all')
const quickFilters = ref([
{
key: 'owner',
label: '负责人',
value: 'all',
options: [
{ label: '全部负责人', value: 'all' },
{ label: '测试用户', value: 'user-1' }
]
},
{
key: 'date',
label: '创建时间',
value: 'all',
options: [
{ label: '全部时间', value: 'all' },
{ label: '本月', value: 'month' }
]
}
])
const event = (name, payload) => window.__primitiveEvents.push({ name, payload })
return () =>
h(
'main',
{
class: 'primitive-page',
style: {
boxSizing: 'border-box',
width: '100%',
padding: '0 10px 24px',
overflowX: 'clip'
}
},
[
h(Header, {
title: '报价管理',
searchable: true,
keyword: keyword.value,
searchPlaceholder: '搜索报价单号或客户',
'onUpdate:keyword': (value) => (keyword.value = value),
onSearch: () => event('search', keyword.value),
onBack: () => event('back')
}),
h(Tabs, {
modelValue: status.value,
tabs: [
{ label: '全部', value: 'all', count: 2 },
{ label: '草稿', value: 'draft', count: 1 }
],
'onUpdate:modelValue': (value) => (status.value = value),
onChange: (value) => event('status', value)
}),
h(Filters, {
quickFilters: quickFilters.value,
moreActive: true,
onSelect: (payload) => event('filter', payload),
onMore: () => event('more')
}),
h(
Card,
{
title: 'BJ20261017001',
status: '审批中',
statusTone: 'warning',
amount: '¥ 12,680.00',
amountLabel: '报价金额',
time: '2026-10-17 10:30',
onOpen: () => event('open')
},
{
emphasis: () => h('span', '山峡化工测试客户'),
kv: () => [h('div', '有效期:30 天'), h('div', '负责人:测试用户')],
actions: () => h('button', { type: 'button' }, '编辑')
}
),
h(Attachments, {
items: [{ id: '1', url: '/fixture.pdf', name: '报价附件.pdf' }],
editable: true,
onAdd: () => event('attachment-add')
}),
h(Timeline, {
items: [
{
id: '1',
name: '张审批',
status: '已通过',
tone: 'success',
opinion: '同意',
time: '2026-10-17 11:00'
}
]
}),
h('section', { class: 'legacy-filter-smoke', 'aria-label': '历史两栏筛选冒烟' }, [
h('div', { class: 'mp-wv-filter-bar' }, [
h('button', { class: 'mp-wv-filter-trig', type: 'button' }, '历史筛选一'),
h('button', { class: 'mp-wv-filter-trig', type: 'button' }, '历史筛选二')
])
])
]
)
}
}).mount('#primitive-fixture')
})
await page.locator('.primitive-page').waitFor()
const searchBox = page.locator('.mp-wv-search')
assert.equal(await searchBox.getAttribute('aria-label'), '搜索')
assert.ok((await searchBox.boundingBox()).height >= 44, '搜索框触达高度不足 44px')
await searchBox.fill('测试报价')
await searchBox.press('Enter')
await page.locator('.mp-wv-status-tabs .filter-tag').nth(1).click()
assert.equal(
await page.locator('.mp-wv-status-tabs .filter-tag').nth(1).getAttribute('aria-pressed'),
'true'
)
const firstFilter = page.locator('.mp-wv-filter-trig').first()
await firstFilter.click()
const option = page.locator('.mp-wv-filter-panel .mp-wv-filter-opt').nth(1)
await option.waitFor()
const optionIsTopmost = await option.evaluate((element) => {
const box = element.getBoundingClientRect()
const topmost = document.elementFromPoint(box.left + box.width / 2, box.top + box.height / 2)
return topmost === element || element.contains(topmost)
})
assert.equal(optionIsTopmost, true, '筛选遮罩覆盖了下拉选项')
assert.ok((await option.boundingBox()).height >= 44, '筛选选项触达高度不足 44px')
await option.click()
assert.equal(
await page.locator('.mp-wv-filter-panel').getAttribute('class'),
'mp-wv-filter-panel'
)
await firstFilter.click()
await page.locator('.mp-wv-filter-mask.open').waitFor()
await page.mouse.click(5, 760)
assert.equal(await firstFilter.getAttribute('aria-expanded'), 'false')
const cardOpen = page.locator('.mp-crm-expense-card .expense-card__open')
await cardOpen.focus()
await cardOpen.press('Enter')
await cardOpen.press('Space')
const eventNames = await page.evaluate(() => window.__primitiveEvents.map((item) => item.name))
assert.deepEqual(eventNames.slice(0, 5), ['search', 'status', 'filter', 'open', 'open'])
const legacyColumns = await page
.locator('.legacy-filter-smoke .mp-wv-filter-bar')
.evaluate((element) => getComputedStyle(element).gridTemplateColumns.split(' ').length)
assert.equal(legacyColumns, 2, '历史筛选栏不应被改成三列')
const attachmentBox = await page.locator('.mp-crm-att-grid .att-item').first().boundingBox()
assert.equal(attachmentBox.width, 72)
assert.equal(attachmentBox.height, 72)
await page.evaluate(() => document.activeElement?.blur())
const viewportGeometry = await page.evaluate(() => ({
clientWidth: document.documentElement.clientWidth,
scrollWidth: document.documentElement.scrollWidth
}))
assert.equal(viewportGeometry.clientWidth, 375)
assert.ok(
viewportGeometry.scrollWidth <= viewportGeometry.clientWidth,
`公共原语出现横向溢出:${JSON.stringify(viewportGeometry)}`
)
await page.screenshot({ path: `${artifacts}/primitives-375.png`, fullPage: true })
assert.deepEqual(pageErrors, [], `页面异常:${pageErrors.join(';')}`)
console.log('CRM 公共原语浏览器交互回归通过:搜索、Tab、筛选、键盘开卡、附件与历史两栏冒烟')
} finally {
await browser.close()
}