146 lines
6.3 KiB
JavaScript
146 lines
6.3 KiB
JavaScript
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;
|
||
const sticky = props.find(prop => prop.name?.getText(source) === 'sticky');
|
||
assert.ok(sticky?.initializer && ts.isJsxExpression(sticky.initializer), '表头吸顶必须预留顶部栏高度');
|
||
assert.equal(sticky.initializer.expression.getText(source), 'sticky');
|
||
assert.match(code, /const sticky = useTableSticky\(\);/);
|
||
const pagination = props.find(prop => prop.name?.getText(source) === 'pagination');
|
||
assert.ok(pagination?.initializer && ts.isJsxExpression(pagination.initializer));
|
||
const config = pagination.initializer.expression;
|
||
assert.ok(
|
||
(ts.isIdentifier(config) && code.includes(`const ${config.text} = useTablePagination()`))
|
||
|| (ts.isCallExpression(config) && config.expression.getText(source) === 'tablePagination')
|
||
|| (ts.isObjectLiteralExpression(config) && config.properties.some(prop =>
|
||
ts.isSpreadAssignment(prop) && prop.expression.getText(source) === 'tablePagination()',
|
||
)),
|
||
'分页必须使用或扩展统一分页配置',
|
||
);
|
||
assert.doesNotMatch(code, /pagination=\{false\}/);
|
||
assert.match(code, /\.\.\.fixedLeft</);
|
||
assert.match(code, /\.\.\.fixedRight</);
|
||
});
|
||
|
||
test(`${file} 数据多或小屏时仍使用页面纵向滚动,横向滚动不变`, () => {
|
||
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: {} };
|
||
const routeContext = {}, proProvider = {};
|
||
let layout = {}, token = {};
|
||
vm.runInNewContext(tableCode, { exports: tableModule.exports, require: id => {
|
||
if (id === '@ant-design/pro-components') return { RouteContext: routeContext, ProProvider: proProvider };
|
||
if (id === 'react') return { useContext: context => context === routeContext ? layout : { token } };
|
||
if (id === '@/hooks/usePageState') return {};
|
||
throw new Error(`Unexpected import: ${id}`);
|
||
} }, { filename: tableFile });
|
||
const helpers = tableModule.exports;
|
||
|
||
test('mix 布局默认固定顶部栏,表头须避让;自定义高度随布局更新', () => {
|
||
for (const height of [56, 72, 96]) {
|
||
for (const isMobile of [false, true]) {
|
||
layout = { hasHeader: true, layout: 'mix', fixedHeader: false, isMobile };
|
||
token = { layout: { header: { heightLayoutHeader: height } } };
|
||
assert.equal(helpers.useTableSticky().offsetHeader, height);
|
||
}
|
||
}
|
||
});
|
||
|
||
test('遵循 ProLayout 默认顶部栏高度', () => {
|
||
layout = { hasHeader: true, layout: 'mix' };
|
||
token = {};
|
||
assert.equal(helpers.useTableSticky().offsetHeader, 56);
|
||
});
|
||
|
||
test('其他布局只在存在固定顶部栏时预留高度', () => {
|
||
token = { layout: { header: { heightLayoutHeader: 72 } } };
|
||
for (const kind of ['top', 'side']) {
|
||
for (const hasHeader of [false, true]) {
|
||
for (const fixedHeader of [false, true]) {
|
||
layout = { layout: kind, hasHeader, fixedHeader };
|
||
assert.equal(helpers.useTableSticky().offsetHeader, hasHeader && fixedHeader ? 72 : 0);
|
||
}
|
||
}
|
||
}
|
||
layout = { layout: 'mix', hasHeader: false, fixedHeader: true };
|
||
assert.equal(helpers.useTableSticky().offsetHeader, 0);
|
||
});
|
||
|
||
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);
|
||
});
|