import { readFileSync } from 'node:fs' import { resolve } from 'node:path' import { describe, expect, it } from 'vitest' function source(name: string) { return readFileSync(resolve(process.cwd(), `src/modules/overseas-master-data/pages/${name}.vue`), 'utf8') } describe('overseas master data real contract pages', () => { it('gives every list query toolbar a unique stable preference key', () => { const expectedKeys = new Map([ ['OverseasQuotesView', 'overseas-quotes-query'], ['ExchangeRatesView', 'overseas-exchange-rates-query'], ['VehiclesView', 'overseas-vehicles-query'], ]) const actualKeys: string[] = [] for (const [name, expectedKey] of expectedKeys) { const view = source(name) const toolbar = view.match(/]*\/>/s)?.[0] expect(toolbar, `${name} should render QueryToolbar`).toBeDefined() expect(toolbar).toContain(`preference-key="${expectedKey}"`) const actualKey = toolbar?.match(/preference-key="([^"]+)"/)?.[1] expect(actualKey).toBe(expectedKey) actualKeys.push(actualKey!) } expect(new Set(actualKeys).size).toBe(actualKeys.length) }) it('keeps operation columns first and preserves the prototype fields', () => { const quotes = source('OverseasQuotesView') const exchangeRates = source('ExchangeRatesView') const vehicles = source('VehiclesView') expect(quotes.indexOf("key:'actions'")).toBeLessThan(quotes.indexOf("key:'name'")) for (const label of ['报价名称', '海外仓', '服务商', '币种', '生效日期', '失效日期', '报价版本', '状态', '更新时间', '备注']) { expect(quotes).toContain(`label:'${label}'`) } const exchangeColumns = exchangeRates.slice(exchangeRates.indexOf('const columns')) expect(exchangeColumns.indexOf("key: 'actions'")).toBeLessThan(exchangeColumns.indexOf("key: 'month'")) expect(vehicles.indexOf("key:'actions'")).toBeLessThan(vehicles.indexOf("key:'plateNumber'")) for (const label of ['自有车辆', '外派车辆', '司机 / 外派单位']) expect(vehicles).toContain(label) expect(vehicles).toContain("key:'region'") expect(vehicles).toContain("placeholder:'全部区域'") expect(vehicles).toContain('class="status-tabs density-status-tabs"') expect(vehicles).toContain("'status-tab',{'is-active':ownership===tab[1]}") expect(vehicles).not.toContain(' { for (const name of ['OverseasQuotesView', 'ExchangeRatesView', 'VehiclesView']) { const view = source(name) expect(view).toContain("from '../api/overseasMasterData'") expect(view).toContain('access.can(permission.') expect(view).toContain('ElMessage.success') } expect(source('OverseasQuotesView')).toContain('导出CSV') expect(source('VehiclesView')).toContain('导出CSV') expect(source('ExchangeRatesView')).toContain("'monthly-exchange-rates.csv'") for (const name of ['OverseasQuotesView', 'ExchangeRatesView', 'VehiclesView']) { expect(source(name)).not.toMatch(/deleteQuote|deleteExchangeRate|deleteVehicle/) } expect(source('OverseasQuotesView')).toContain('changeQuoteStatus(row.id,next,row.recordVersion)') expect(source('ExchangeRatesView')).toContain('changeExchangeRateStatus(row.month, next, row.recordVersion, null)') expect(source('VehiclesView')).toContain('changeVehicleStatus(row.id,statusTarget.value,row.recordVersion)') for (const name of ['OverseasQuotesView', 'ExchangeRatesView', 'VehiclesView']) { expect(source(name)).toContain("masterDataErrorMessage(") expect(source(name)).toContain('saveCsv(await export') } }) it('uses an independent API-backed vehicle detail page without inventing fulfillment history', () => { const detail = source('VehicleDetailView') expect(detail).toContain('车辆信息') expect(detail).toContain('派送订单明细') expect(detail).toContain('派送更换记录') expect(detail).toContain('getVehicle(') expect(detail).toContain(':vehicle-id="detail.id" kind="deliveries"') expect(detail).toContain(':vehicle-id="detail.id" kind="changes"') expect(detail).not.toContain('车辆更换记录尚未接入') expect(detail).not.toContain('AppDrawer') expect(detail).not.toContain('const vehicle =') }) it('records the prototype evidence before implementation', () => { const matrix = readFileSync(resolve(process.cwd(), 'src/modules/overseas-master-data/PROTOTYPE_MATRIX.md'), 'utf8') for (const id of ['gen-partner-warehouse', 'gen-overseas-quote', 'gen-exchange-rate', 'vehicle-detail']) expect(matrix).toContain(id) for (const modal of ['modal-gen-overseas-quote-detail', 'modal-gen-overseas-quote', 'modal-exchange-rate-edit', 'modal-vehicle-edit']) expect(matrix).toContain(modal) expect(matrix).toContain('旧版原型未定义的车辆文件预览、审核/确认流程不自行补充') expect(matrix).toContain('新版车辆保养及加油接入矩阵') expect(matrix).toContain('modal-vehicle-ops-record') expect(matrix).toContain('target="_blank"') }) it('records the real service boundary and remaining unsupported operations', () => { const gaps = readFileSync(resolve(process.cwd(), 'src/modules/overseas-master-data/CONTRACT_GAPS.md'), 'utf8') expect(gaps).toContain('/api/platform/v1/last-leg/master-data') expect(gaps).toContain('/overseas-quotes/warehouse-options') expect(gaps).toContain('浏览器不调用国内') expect(gaps).toContain('没有删除端点') expect(gaps).toContain('JSON 错误 Blob') expect(gaps).not.toContain('尚无已确认') expect(matrixSource()).not.toContain('写入口禁用') expect(matrixSource()).not.toContain('等待查询接口') }) }) function matrixSource() { return readFileSync(resolve(process.cwd(), 'src/modules/overseas-master-data/PROTOTYPE_MATRIX.md'), 'utf8') }