Files
shanxia2.0/web-admin/scripts/mobile-cert-card-fields.test.ts
T

178 lines
5.8 KiB
TypeScript

import assert from 'node:assert/strict'
import test from 'node:test'
import { readFileSync } from 'node:fs'
import { parse } from '@vue/compiler-sfc'
import ts from 'typescript'
import { computed, effectScope, ref, watch, nextTick } from 'vue'
import { useMobilePlanListDetails } from '../src/views/m/pl/plan/mobileListDetails'
import { formatBrandConstraintLabel } from '../src/utils/crm-product-brand'
import { getPlanProductActualQuantity } from '../src/utils/pl-display'
function card(plan: any) {
const ast = ts.createSourceFile(
'card.ts',
parse(
readFileSync(new URL('../src/views/m/pl/plan-cert/PlanCard.vue', import.meta.url), 'utf8')
).descriptor.scriptSetup!.content,
ts.ScriptTarget.Latest,
true
)
const code = ast.statements
.filter(
(n) =>
ts.isVariableStatement(n) &&
n.declarationList.declarations.some((d) => d.name.getText(ast) === 'productNameLabel')
)
.map((n) => n.getText(ast))
.join('\n')
const shared = ts.createSourceFile(
'shared.ts',
readFileSync(new URL('../src/utils/mp-pl-plan-card.ts', import.meta.url), 'utf8'),
ts.ScriptTarget.Latest,
true
)
const productCode = shared.statements
.filter(
(node) =>
ts.isFunctionDeclaration(node) &&
[
'formatStopProductLine',
'resolveLinkedPlanProduct',
'formatQty',
'resolveUnitLabel'
].includes(node.name!.text)
)
.map((node) => node.getText(shared))
.join('\n')
const env = {
props: { plan },
computed,
formatBrandConstraintLabel,
getPlanProductActualQuantity,
resolveProductHazardFlags: () => ({ isToxic: false, isExplosive: false }),
resolveMpPackageSpecLabel: (value: string) => value || '—',
resolveMpProductUnitLabel: (value: string) => value || '—'
}
return new Function(
...Object.keys(env),
`${ts.transpile(code + '\n' + productCode, { target: ts.ScriptTarget.ESNext })}; return {productNameLabel,productLine: (product, kind) => formatStopProductLine(props.plan, { kind }, product)}`
)(...Object.values(env))
}
test('certificate expanded card joins list standard names, preserves segment empty brands and actual quantities', async () => {
const scope = effectScope()
const detail = {
id: 'A',
products: [
{
id: 'p',
productName: '根别名',
brandMode: 'required',
brandName: '根品牌',
aliasName: '根别名'
}
]
}
const api = scope.run(() =>
useMobilePlanListDetails({ scope: () => 'query/account', load: async () => detail })
)!
await api.ensure('A')
const displayed = api.cardPlan({
id: 'A',
products: [{ id: 'p', productName: '标准产品' }]
} as any)
const h = card(displayed)
const row = {
planProductId: 'p',
productName: '根别名',
model: '99%',
unit: '吨',
planQty: 3,
inboundQty: 8,
outboundQty: 0,
mobileProductMeta: { brandMode: 'any', brandName: '', aliasName: '送货别名' }
}
assert.equal(h.productNameLabel.value, '标准产品')
const renderProduct = h.productLine
const delivery = renderProduct(row, 'delivery')
assert.equal(delivery.name, '标准产品')
assert.equal(delivery.brand, '—')
assert.equal(delivery.alias, '送货别名')
assert.equal(delivery.actualQty, '0')
assert.equal(renderProduct({ ...row, outboundQty: undefined }, 'delivery').actualQty, '—')
assert.equal(renderProduct(row, 'load').actualQty, '8')
scope.stop()
})
test('actual certificate list expands only the requested card and fetches mobile segment metadata', async () => {
const source = parse(
readFileSync(new URL('../src/views/m/pl/plan-cert/index.vue', import.meta.url), 'utf8')
).descriptor.scriptSetup!.content
const ast = ts.createSourceFile('list.ts', source, ts.ScriptTarget.Latest, true)
const code = ast.statements
.filter(
(n) =>
(ts.isVariableStatement(n) &&
n.declarationList.declarations.some((d) => d.name.getText(ast) === 'planDetails')) ||
(ts.isFunctionDeclaration(n) && n.name?.text === 'toggleExpanded') ||
(ts.isExpressionStatement(n) &&
ts.isCallExpression(n.expression) &&
n.expression.expression.getText(ast) === 'watch' &&
n.expression.arguments[0]?.getText(ast) === 'expandedIds')
)
.map((n) => n.getText(ast))
.join('\n')
const calls: any[] = []
const env = {
useMobilePlanListDetails,
watch,
expandedIds: ref(new Set()),
requestKey: () => 'scope',
planApi: {
get: (id: string, mobile: boolean) =>
new Promise((resolve) => calls.push({ id, mobile, resolve }))
}
}
const scope = effectScope()
const api = scope.run(() =>
new Function(
...Object.keys(env),
`${ts.transpile(code, { target: ts.ScriptTarget.ESNext })};return {planDetails,toggleExpanded}`
)(...Object.values(env))
)
assert.equal(calls.length, 0)
api.toggleExpanded('A', true)
await nextTick()
assert.deepEqual(
calls.map(({ id, mobile }) => [id, mobile]),
[['A', true]]
)
assert.equal(api.planDetails.records.A.plan, null)
calls[0].resolve({
id: 'A',
products: [{ id: 'p', productName: '根别名' }],
deliveries: [
{
products: [
{
planProductId: 'p',
mobileProductMeta: { aliasName: '段次别名', brandMode: 'any', brandName: '' }
}
]
}
]
})
await api.planDetails.ensure('A')
const plan = api.planDetails.cardPlan({
id: 'A',
products: [{ id: 'p', productName: '标准产品' }]
})
const rendered = card(plan)
assert.equal(rendered.productNameLabel.value, '标准产品')
assert.equal(rendered.productLine(plan.deliveries[0].products[0], 'delivery').alias, '段次别名')
api.toggleExpanded('A', false)
api.toggleExpanded('A', true)
await nextTick()
assert.equal(calls.length, 1)
scope.stop()
})