99 lines
5.1 KiB
TypeScript
99 lines
5.1 KiB
TypeScript
import { readFileSync } from 'node:fs'
|
|
import { join } from 'node:path'
|
|
import { describe, expect, it } from 'vitest'
|
|
|
|
const source = readFileSync(join(process.cwd(), 'src/modules/fba-pricing/carrier-rates/pages/CarrierRatesView.vue'), 'utf8')
|
|
const queryToolbarSource = readFileSync(join(process.cwd(), 'src/shared/components/QueryToolbar.vue'), 'utf8')
|
|
|
|
describe('CarrierRatesView source contract', () => {
|
|
it('keeps operation column first and covers every required business field', () => {
|
|
const customerColumn = "key: 'customer', label: '所属企业'"
|
|
const destinationColumn = "key: 'destinationCode', prop: 'destinationCode'"
|
|
expect(source.indexOf("key: 'actions'")).toBeLessThan(source.indexOf(customerColumn))
|
|
expect(source.indexOf(customerColumn)).toBeLessThan(source.indexOf(destinationColumn))
|
|
expect(source.indexOf(destinationColumn)).toBeLessThan(source.indexOf("key: 'rate'"))
|
|
for (const label of ['起运仓', '业务类型', '渠道编码', '船司', 'FBA 目的仓', '计费单位', '单价', '币种', '固定附加费', '有效期', '备注', '生效时间', '结束时间']) {
|
|
expect(source).toContain(label)
|
|
}
|
|
expect(source).toContain("placeholder: 'FBA 目的仓编码'")
|
|
expect(source).toContain("placeholder: '渠道编码'")
|
|
})
|
|
|
|
it('implements immutable version actions with exact backend permissions', () => {
|
|
expect(source).toContain("firstleg:fba-pricing:rate:edit")
|
|
expect(source).toContain('创建版本')
|
|
expect(source).toContain('新版本')
|
|
expect(source).toContain('停用')
|
|
expect(source).not.toContain('编辑价格')
|
|
})
|
|
|
|
it('keeps the customer company scope in the query toolbar without exposing tenant concepts', () => {
|
|
expect(source).toContain("key: 'customerId'")
|
|
expect(source.indexOf("key: 'customerId'")).toBeLessThan(source.indexOf("key: 'rateCode'"))
|
|
expect(source).toContain("'aria-label': '所属企业'")
|
|
expect(source).toContain('listPlatformTenants')
|
|
expect(source).toContain('loadedCustomerId')
|
|
expect(source).not.toContain('PlatformTenantSelector')
|
|
expect(source).not.toContain('selectedTenantId')
|
|
expect(source).not.toContain('租户')
|
|
})
|
|
|
|
it('uses semantic compact filter widths and keeps the customer selection empty by default', () => {
|
|
for (const field of [
|
|
"key: 'customerId',\n type: 'select',\n width: 280",
|
|
"key: 'rateCode', type: 'input', width: 220",
|
|
"key: 'destinationCode', type: 'input', width: 220",
|
|
"key: 'channelCode', type: 'input', width: 220",
|
|
"key: 'chargeUnit', type: 'select', width: 180",
|
|
"key: 'status', type: 'select', width: 160",
|
|
]) expect(source).toContain(field)
|
|
expect(source).toContain("customerId: ''")
|
|
expect(source).toContain("placeholder: customerLoadError.value ? '企业列表加载失败' : '全部客户'")
|
|
expect(source).not.toContain(':search-on-reset="false"')
|
|
expect(source).not.toContain('请先选择所属企业')
|
|
expect(source).not.toContain('请选择所属企业并查询价格数据')
|
|
expect(source).not.toContain('customers.value[0]')
|
|
})
|
|
|
|
it('loads all customers initially and after reset while preserving row scope for record actions', () => {
|
|
expect(source).toContain('void loadRateData()')
|
|
expect(source).toContain("listPlatformCarrierRates(customerId ? { customerId } : {})")
|
|
expect(source).toContain('loadRateData(customerId)')
|
|
expect(source).toContain('getPlatformCarrierRate(String(row.tenantId), row.id)')
|
|
expect(source).toContain('retirePlatformCarrierRate(String(row.tenantId), row.id)')
|
|
expect(source).toContain('customerLabel(detail.tenantId)')
|
|
})
|
|
|
|
it('inherits QueryToolbar wrapping and full-width mobile controls', () => {
|
|
expect(queryToolbarSource).toContain('flex-wrap: wrap')
|
|
expect(queryToolbarSource).toContain('@media (max-width: 720px)')
|
|
expect(queryToolbarSource).toContain('width: 100%')
|
|
expect(source).not.toContain('--query-field-width')
|
|
})
|
|
|
|
it('guards unsaved work, failures and narrow screens', () => {
|
|
expect(source).toContain('useUnsavedWorkRegistration')
|
|
expect(source).toContain('LoadErrorState')
|
|
expect(source).toContain('ApiErrorMeta')
|
|
expect(source).toContain('@media (max-width: 720px)')
|
|
})
|
|
|
|
it('reuses the first-leg order list primitives for status, empty state and pagination', () => {
|
|
expect(source).toContain("import StatusBadge from '@/shared/components/StatusBadge.vue'")
|
|
expect(source).toContain('<StatusBadge :status="statusLabel(')
|
|
expect(source).toContain('<template #empty><el-empty')
|
|
expect(source).toContain('<div class="business-page">')
|
|
expect(source).not.toContain('<QueryToolbar v-model="filters" class="surface-panel"')
|
|
expect(source).not.toContain('<template #pagination-left>')
|
|
expect(source).not.toContain('<el-tag')
|
|
})
|
|
|
|
it('does not create route or navigation ownership in the page task', () => {
|
|
expect(source).not.toContain('createRouter')
|
|
expect(source).not.toContain('adminNavigation')
|
|
for (const unsupportedCapability of ['导入', '导出', '全部船期', '参考时效', '最晚进仓时间']) {
|
|
expect(source).not.toContain(unsupportedCapability)
|
|
}
|
|
})
|
|
})
|