import { readFileSync } from 'node:fs' import { resolve } from 'node:path' import { describe, expect, it } from 'vitest' const page = (name: string) => readFileSync(resolve(process.cwd(), 'src/modules/overseas-warehouse/pages', name), 'utf8') const component = (name: string) => readFileSync(resolve(process.cwd(), 'src/modules/overseas-warehouse/components', name), 'utf8') describe('overseas warehouse 1920px layout acceptance', () => { it('keeps action columns first and wide enough for every visible action', () => { const widths: Record = { 'LastMileOrdersView.vue': 270, 'InboundOrdersView.vue': 190, 'DispatchesView.vue': 240, 'OutboundsView.vue': 190, 'DeliveryOrdersView.vue': 300, 'RelabelOrdersView.vue': 190, 'PalletsView.vue': 250, 'InventoryView.vue': 110, } for (const [name, width] of Object.entries(widths)) { const source = page(name) const columns = source.slice(source.indexOf('const columns'), source.indexOf('async function', source.indexOf('const columns'))) expect(columns).toContain(`{ key: 'actions', label: '操作', width: ${width}, fixed: 'left'`) expect(columns.indexOf("key: 'actions'")).toBeLessThan(columns.indexOf("label:", columns.indexOf("key: 'actions'") + 20)) } }) it('assigns explicit desktop widths to dense query inputs', () => { for (const name of ['LastMileOrdersView.vue', 'InboundOrdersView.vue', 'OutboundsView.vue', 'DeliveryOrdersView.vue', 'RelabelOrdersView.vue', 'PalletsView.vue', 'InventoryView.vue']) { const source = page(name) const fieldLines = source.split(/\r?\n/).filter((line) => /type: '(input|select|daterange)'/.test(line)) expect(fieldLines.length, name).toBeGreaterThan(0) expect(fieldLines.every((line) => line.includes('width:')), `${name} has a query field without width`).toBe(true) } }) it('provides semantic placeholders for editable form controls', () => { for (const name of ['LastMileOrdersView.vue', 'InboundOrdersView.vue', 'OutboundsView.vue', 'DeliveryOrdersView.vue', 'RelabelOrdersView.vue', 'PalletsView.vue', 'InventoryView.vue']) { const editableControls = [...page(name).matchAll(/][^>]*>/g)] .map(([tag]) => tag) .filter((tag) => !/\s(?:readonly|disabled)(?:\s|\/?>)/.test(tag)) .filter((tag) => !tag.includes('v-model="planEditForm.warehouseId"')) expect(editableControls.every((tag) => tag.includes('placeholder=')), `${name} has an editable control without placeholder`).toBe(true) } }) it('uses four-field desktop density and full-width form controls', () => { const sharedDetail = component('OverseasReadOnlyDetail.vue') expect(sharedDetail).toContain('grid-template-columns: repeat(2, minmax(0, 1fr))') expect(page('LastMileOrderDetailView.vue')).toContain('.detail-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr))') expect(page('InboundOrderDetailView.vue')).toContain('.detail-group:last-child .detail-fields{grid-template-columns:repeat(4,minmax(0,1fr))}') expect(page('DispatchDetailView.vue')).toContain('.document-section { grid-column: 1 / -1; }') expect(page('DispatchDetailView.vue')).toContain('.document-section .detail-fields { grid-template-columns: repeat(3, minmax(0, 1fr)); }') expect(page('DeliveryOrderDetailView.vue')).toContain('.info-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr))') expect(page('InventoryDetailView.vue')).toContain('grid-template-columns:repeat(2,minmax(0,1fr))') expect(page('OutboundsView.vue')).toContain('.create-outbound-form :deep(.el-input-number) { width: 100%; }') expect(page('RelabelOrdersView.vue')).toContain('.el-form :deep(.el-date-editor) { width: 100%; }') expect(page('PalletsView.vue')).toContain('.el-form :deep(.el-input-number) { width: 100%; }') expect(page('RelabelOrdersView.vue')).toContain('.el-form :deep(.el-row) { margin-left: 0 !important; margin-right: 0 !important; }') expect(page('PalletsView.vue')).toContain('.el-form :deep(.el-row) { margin-left: 0 !important; margin-right: 0 !important; }') }) })