Files
creator-hub/web/tests/table-fixed-header.test.cjs
T

144 lines
6.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.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 } };
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);
});