import { readFileSync } from 'node:fs' import { resolve } from 'node:path' import { describe, expect, it } from 'vitest' const pages = [ ['src/modules/container-loading/pages/ContainersView.vue', "key: 'cabinetNo'"], ['src/modules/loading-lists/components/LoadingListsView.vue', "key: 'preloadNo'"], ['src/modules/ocean-bookings/pages/OceanBookingsView.vue', "prop: 'bookingNo'"], ['src/modules/port-schedules/pages/PortSchedulesView.vue', "prop: 'schedule.scheduleNo'"], ['src/modules/trucking/pages/TruckAppointmentsView.vue', "key: 'appointmentNo'"], ['src/modules/customs/pages/CustomsCasesView.vue', "prop: 'customsNo'"], ['src/modules/outbound-dispatch/pages/OutboundDispatchesView.vue', "prop: 'inboundCode'"], ] as const function source(path: string) { return readFileSync(resolve(process.cwd(), path), 'utf8') } describe('domestic outbound list responsive contracts', () => { it.each(pages)('%s keeps the operation column first and fixed left', (path, firstBusinessColumn) => { const content = source(path) const firstAction = content.indexOf("label: '操作'") expect(firstAction).toBeGreaterThan(-1) expect(firstAction).toBeLessThan(content.indexOf(firstBusinessColumn, firstAction)) const actionObjects = [...content.matchAll(/\{[^{}]*label: '操作'[^{}]*\}/g)].map((match) => match[0]) expect(actionObjects.length).toBeGreaterThan(0) for (const column of actionObjects) expect(column).toContain("fixed: 'left'") }) it.each(pages)('%s gives every business column a stable width constraint', (path) => { const content = source(path) const columns = [...content.matchAll(/\{[^{}]*(?:key|prop): '[^']+'[^{}]*label: '[^']+'[^{}]*\}/g)] .map((match) => match[0]) .filter((column) => !column.includes("type: 'input'") && !column.includes("type: 'select'") && !column.includes("type: 'daterange'")) expect(columns.length).toBeGreaterThan(1) for (const column of columns) expect(column).toMatch(/\b(?:width|minWidth):\s*\d+/) }) it('keeps shared 320px degradation rules for filters, actions and pagination', () => { const queryToolbar = source('src/shared/components/QueryToolbar.vue') const dataTable = source('src/shared/components/DataTable.vue') const listLayout = source('src/shared/components/ListPageLayout.vue') expect(queryToolbar).toContain('@media (max-width: 720px)') expect(queryToolbar).toContain('.query-toolbar__field { width: 100%; }') expect(queryToolbar).toContain('grid-template-columns: repeat(auto-fit, minmax(120px, 1fr))') expect(dataTable).toContain('@media (max-width: 720px)') expect(dataTable).toContain('flex-direction: column') expect(dataTable).toContain('.data-table__page-buttons { flex-wrap: wrap; }') expect(listLayout).toContain('min-width: 0') }) })