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 } 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() }) // Retired attachment/ready list expansion is replaced by real quota list coverage in quota-mobile-state.test.ts.