import test from 'node:test' import assert from 'node:assert/strict' import { readSource } from './helpers.ts' // module13(时间统一 YYYY-MM-DD HH:mm:ss)全页接入不变式: // 所有时间展示列/文本走 formatDateTime;不残留“裸日期 prop 列”或“时间 || '—'”旧写法。 // 例外:DuplicateCheckPage 不动。 const PAGES = [ 'src/pages/account/GroupsPage.vue', 'src/pages/account/MenusPage.vue', 'src/pages/account/UsersPage.vue', 'src/pages/asin/AsinInvalidPage.vue', 'src/pages/asin/DedupeRegistryPage.vue', 'src/pages/asin/QueryAsinPage.vue', 'src/pages/asin/SkipPricePage.vue', 'src/pages/records/RecordsHistoryPage.vue', 'src/pages/records/RecordsSoftwareVersionPage.vue', 'src/pages/records/RecordsDigitalHumanVersionPage.vue', 'src/pages/shop/ShopKeysPage.vue', 'src/pages/shop/ShopManagePage.vue', 'src/pages/tasks/ImageVideoTasksPage.vue', 'src/pages/tasks/ShopDataTasksPage.vue', ] const TIME_PROPS = 'createdAt|updatedAt|releasedAt|submittedAt|completedAt' /** 页面含时间展示内容(列名/标签)才受统一格式化不变式约束;无时间列页面不强引(与 task-268 口径一致)。 */ const TIME_CONTENT = /创建时间|更新时间|生成时间|发布时间|提交时间|完成时间|修改时间|上架时间|最新/ test('test_datetime_sweep_normal_primary_path', () => { for (const page of PAGES) { const src = readSource(page) if (TIME_CONTENT.test(src)) assert.match(src, /formatDateTime/, `${page} 需引用 formatDateTime`) } }) test('test_datetime_sweep_normal_variant_input', () => { // 含时间展示的页:时间列/文本确实经由 formatDateTime 包裹(至少含一次调用点)。 for (const page of PAGES) { const src = readSource(page) if (TIME_CONTENT.test(src)) assert.ok((src.match(/formatDateTime\(/g) || []).length >= 1, `${page} 至少一处 formatDateTime 调用`) } }) test('test_datetime_sweep_normal_repeated_operation_is_idempotent', () => { const check = (src: string) => new RegExp(`prop="(${TIME_PROPS})"[^>]*/>`).test(src) for (const page of PAGES) { const src = readSource(page) assert.equal(check(src), false, `${page} 不得残留无 formatter 的裸日期 prop 列`) } }) test('test_datetime_sweep_boundary_empty_input', () => { // 不再使用“时间字段 || '—'”旧兜底写法(空值由 formatDateTime 统一处理; // 允许 updatedAt || createdAt 这种字段优先级写法,其值最终仍进 formatDateTime)。 for (const page of PAGES) { const src = readSource(page) assert.ok(!new RegExp(`\\.(${TIME_PROPS})\\s*\\|\\|\\s*['"]—['"]`).test(src), `${page} 不得再写 时间||'—'`) } }) test('test_datetime_sweep_boundary_single_item', () => { // 含时间展示的页:时间标签仍存在(列还在),只是改成走格式化;无时间列页面豁免。 for (const page of PAGES) { const src = readSource(page) if (TIME_CONTENT.test(src)) assert.match(src, /时间|最新/, `${page} 仍应含“时间/最新”列/文案`) } }) test('test_datetime_sweep_boundary_limit_or_missing_field', () => { // 工具模块可被各页 import;路径为 @/utils/datetime。无时间列页面豁免 import 检查。 for (const page of PAGES) { const src = readSource(page) if (TIME_CONTENT.test(src)) assert.match(src, /from ['"]@\/utils\/datetime['"]/, `${page} 需 import 自 @/utils/datetime`) } }) test('test_datetime_sweep_invalid_input_rejected', () => { // 例外页 DuplicateCheckPage 未接入且未改动(保持自身实现)。 const dup = readSource('src/pages/tasks/DuplicateCheckPage.vue') assert.equal(/formatDateTime/.test(dup), false, 'DuplicateCheckPage 不应引入统一时间格式化') }) test('test_datetime_sweep_dependency_failure_returns_actionable_message', () => { // 时间字段名清单应覆盖当前出现过的展示字段。 const util = readSource('src/utils/datetime.ts') assert.match(util, /formatDateTime/) assert.match(util, /\\d\{2\}:\\d\{2\}:\\d\{2\}/, '工具输出含 HH:mm:ss 正则') })