const assert = require('node:assert/strict'); const { readFileSync } = require('node:fs'); const { test } = require('node:test'); const vm = require('node:vm'); const ts = require('typescript'); // 页面纵向滚动 + sticky 表头吸顶 + 横向滚动 + 固定列 + 分页。 const files = [ ['src/components/accounts/MonitoringAccountList.tsx', 1100], ['src/components/accounts/AccountManagementList.tsx', 'max-content'], ['src/pages/accounts/import.tsx', 1000], ['src/pages/network-exits/index.tsx', 1100], ['src/pages/gateways/index.tsx', 960], ]; for (const [file, width] of files) { const source = ts.createSourceFile( file, readFileSync(`${__dirname}/../${file}`, 'utf8'), ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX, ); const code = source.getFullText(); const tables = []; function visit(node) { if ((ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) && node.tagName.getText(source) === 'Table') tables.push(node); ts.forEachChild(node, visit); } visit(source); test(`${file} 保留表头吸顶、分页和固定列`, () => { assert.equal(tables.length, 1); const props = tables[0].attributes.properties; assert.ok(props.some(prop => prop.name?.getText(source) === 'sticky')); assert.match(code, /pagination=\{tablePagination\(\)\}/); assert.doesNotMatch(code, /pagination=\{false\}/); assert.match(code, /\.\.\.fixedLeft { const scroll = tables[0].attributes.properties.find(prop => prop.name?.getText(source) === 'scroll'); assert.ok(scroll?.initializer && ts.isJsxExpression(scroll.initializer)); const expression = scroll.initializer.expression.getText(source); for (const horizontal of [false, true]) { for (const height of [480, 1080]) { for (const rowCount of [0, 1, 20, 100]) { const result = vm.runInNewContext(`(${expression})`, { horizontal, vertical: rowCount * 48 + 120 >= height - 300 || horizontal, tableScroll: (x, y) => ({ x, y }), }); assert.equal(Object.hasOwn(result, 'y'), false, `不应配置 scroll.y(行数 ${rowCount},高度 ${height})`); assert.equal(result.x, width === 'max-content' ? width : horizontal ? width : undefined); } } } assert.doesNotMatch(code, /window\.innerHeight|useOverflowGrid|tableScroll/, '不再保留按高度和行数启用表内滚动的旧路径'); if (width !== 'max-content') assert.match(code, /!Grid\.useBreakpoint\(\)\.xl/, '横向断点保持 xl'); }); } const tableFile = `${__dirname}/../src/utils/table.ts`; const tableCode = ts.transpileModule(readFileSync(tableFile, 'utf8'), { fileName: tableFile, compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022 }, }).outputText; const tableModule = { exports: {} }; vm.runInNewContext(tableCode, { exports: tableModule.exports }, { filename: tableFile }); const helpers = tableModule.exports; test('分页仍为每页 20 条,单页隐藏分页条', () => { assert.equal(helpers.TABLE_PAGE_SIZE, 20); const pagination = helpers.tablePagination(); assert.equal(pagination.pageSize, 20); assert.equal(pagination.hideOnSinglePage, true); }); test('固定列保留原配置且不修改输入', () => { const column = { title: '账号', width: 240 }; for (const [helper, side] of [[helpers.fixedLeft, 'left'], [helpers.fixedRight, 'right']]) { const fixed = helper(column); assert.equal(fixed.fixed, side); assert.equal(fixed.title, column.title); assert.equal(fixed.width, column.width); assert.notEqual(fixed, column); assert.equal(Object.hasOwn(column, 'fixed'), false); } }); test('移除纵向滚动判断与无必要的滚动包装函数', () => { assert.equal(helpers.useOverflowGrid, undefined); assert.equal(helpers.tableScroll, undefined); });