import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import test from 'node:test' import { compile, computed, createSSRApp, h, inject, provide } from 'vue' import { renderToString } from 'vue/server-renderer' import ts from 'typescript' const source = readFileSync(new URL('./InboundBillingPanel.vue', import.meta.url), 'utf8') const confirmationBody = source.slice(source.indexOf('
${confirmationBody}`), setup: () => ({ props: { data }, ...formatters }), }) app.component('ElTable', { props: ['data'], setup(tableProps, { slots }) { provide('billingRows', computed(() => tableProps.data)) return () => h('table', slots.default?.()) }, }) app.component('ElTableColumn', { props: ['label', 'prop'], setup(columnProps, { slots }) { const rows = inject('billingRows') return () => h('tr', [h('th', columnProps.label), ...rows.value.map(row => h('td', slots.default?.({ row }) ?? row[columnProps.prop] ?? ''))]) }, }) return renderToString(app) } test('renders loading, pending, isolated error, and published states', () => { assert.match(source, /v-if="props\.loading"/) assert.match(source, /v-else-if="props\.error"/) assert.match(source, /role="alert"/) assert.match(source, /v-else-if="props\.unavailable \|\| !props\.data"/) assert.match(source, /role="status"/) assert.match(source, /费用已发布 · 待确认/) assert.match(source, /\$emit\('retry'\)/) }) test('supports a standalone dialog and keeps the unpushed billing-weight state visible', () => { assert.match(source, /dialogOnly\?: boolean/) assert.match(source, /v-if="!props\.dialogOnly"/) assert.match(source, /watch\(\(\) => props\.autoOpen/) assert.match(source, /if \(autoOpen\) feeDialogOpen\.value = true/) assert.match(source, /v-else-if="props\.unavailable \|\| !props\.data"/) assert.match(source, /平台推送费用后,可在这里核对并确认/) assert.match(source, /@closed="emit\('closed'\)"/) }) test('shows the published merchant inbound, measurement details and customer confirmation entry', () => { for (const label of ['入仓码', '平台收货仓', '实际毛重', '实测体积', '托盘与库位', '换算与精度', '最终计费量', '单价', '基础费用', '附加费用', '费用合计', '平台备注']) { assert.ok(source.includes(label), `missing label: ${label}`) } assert.match(source, /formatInboundMoney\(props\.data\.latestFee\.totalAmount/) assert.match(source, /formatConversionPrecision\(/) assert.match(source, /title="确认计费重"/) assert.match(source, /确认后当前费用版本将锁定/) assert.match(source, /customerConfirmationStatus === 'CONFIRMED'/) assert.match(source, /confirmMerchantInboundFee/) assert.match(source, /measurementItems/) assert.doesNotMatch(source, /调整费用|发送费用|下载照片/) assert.doesNotMatch(source, /internalNotes|statusHistory|files/) assert.doesNotMatch(source, /latestFee\.(feeVersion|ruleCode|rateCode|chargeRuleVersion|carrierRateVersion|sentAt)/) assert.match(source, /箱规规则/) assert.match(source, /getCalculationRuleLabel\(row\.calculationRuleVersion\)/) }) test('keeps the billing summary, confirmation table, notice and footer', () => { assert.match(source, /width="min\(1180px, calc\(100vw - 40px\)\)"/) assert.match(source, /class="fee-dialog-summary" aria-label="计费汇总"/) for (const label of ['计算重', '单价', '总金额', '计费毛重', '计费体积', '计费方式', '最终计费量']) assert.ok(confirmationBody.includes(label), `missing billing label: ${label}`) assert.match(source, /class="fee-confirm-notice"/) assert.match(source, /请核对计费毛重、计费体积、计费量、单价和总金额。确认后当前费用版本将锁定。/) assert.match(source, /确认计费量和费用/) assert.match(source, /\.fee-dialog-summary \{ display:grid; grid-template-columns:repeat\(3,minmax\(0,1fr\)\)/) assert.match(source, /\.fee-dialog-table :deep\(\.el-table__body td\.el-table__cell\)/) }) test('confirms the selected billing weight and volume even when outer carton totals differ', async () => { const html = await renderConfirmation({ latestFee: { actualWeightKg: 570.5, actualVolumeCbm: 3.6894, chargeableQuantity: 616.1298, chargeMode: 'KG', chargeUnit: 'KG', unitPrice: 13.6, totalAmount: 8379.37, currency: 'CNY', }, billingBasis: { chargeableWeightKg: 650.298 }, measurementItems: [{ lengthCm: 63, widthCm: 53, heightCm: 53, packageCount: 22, unitVolumeCbm: 0.177, totalVolumeCbm: 3.894, volumeWeightKg: 650.298 }], }) assert.match(html, /570\.5 kg/) assert.match(html, /3\.6894 m³/) assert.match(html, /616\.13 kg/) assert.match(html, /8,379\.37/) assert.doesNotMatch(html, /3\.894|650\.298|0\.177/) assert.doesNotMatch(confirmationBody, /measurementItems|billingBasis|箱规长|每箱体积/) }) test('uses the published volume charge quantity and retains six decimal places', async () => { const html = await renderConfirmation({ latestFee: { actualWeightKg: 600, actualVolumeCbm: 1.234567, chargeableQuantity: 1.652893, chargeMode: 'CBM', chargeUnit: 'CBM', unitPrice: 100, totalAmount: 165.29, currency: 'CNY', }, billingBasis: { chargeableWeightKg: 600 }, measurementItems: [], }) assert.match(html, /计费量/) assert.match(html, /按体积计费/) assert.match(html, /600 kg/) assert.match(html, /1\.234567 m³/) assert.match(html, /1\.652893 m³/) assert.doesNotMatch(html, /1\.652893 kg/) }) test('stacks core information for 720 and 360 pixel layouts', () => { assert.match(source, /@media \(max-width: 720px\)/) assert.match(source, /\.inbound-overview, \.inbound-measurements, \.fee-calculation-grid \{ grid-template-columns: 1fr;/) assert.match(source, /\.inbound-billing-state \.el-button \{[^}]*min-height: 44px;/) assert.match(source, /@media \(max-width: 360px\)/) })