1
0
Files
DiAL/tests/web/constants/target-table-columns.test.ts
lanyuanxiaoyao 1c5cfafda6 feat: 前端指标体系增强 — Dashboard/Metrics API、2×4 统计区、趋势图面积+异常标记、连续状态列
- 新增 GET /api/dashboard 合并原 summary+targets 首屏接口
- 新增 GET /api/targets/:id/metrics 合并原 stats+trend 概览接口
- 后端指标纯函数:可用率、百分位、故障段分析、连续状态、UTC 小时分桶
- ProbeStore 窗口取数方法替代全量历史查询
- SummaryCards 扩展为 4 卡片(新增异常事件数)+ 数据新鲜度展示
- 表格新增「连续」列(Tag 渲染 capped 状态)
- OverviewTab 重构为 2×4 Statistic 多维度布局
- TrendChart 改为延迟范围面积图 + 红色异常标记点
- 删除旧路由(summary/targets/trend)和 computeTrendStats
- 同步 delta specs 到主 specs 并归档变更
2026-05-14 12:32:41 +08:00

102 lines
3.1 KiB
TypeScript

import type { PrimaryTableCellParams, PrimaryTableCol } from "tdesign-react";
import { describe, expect, test } from "bun:test";
import type { TargetStatus } from "../../../src/shared/api";
import { createTargetTableColumns } from "../../../src/web/constants/target-table-columns";
interface TableFilter {
list?: Array<{ label: string; value: string }>;
type?: string;
}
function getColumn(columns: Array<PrimaryTableCol<TargetStatus>>, colKey: string): PrimaryTableCol<TargetStatus> {
const column = columns.find((item) => item.colKey === colKey);
expect(column).toBeDefined();
return column!;
}
function makeTarget(overrides: Partial<TargetStatus> = {}): TargetStatus {
return {
currentStreak: null,
group: "default",
id: 1,
interval: "5s",
latestCheck: null,
name: "test",
recentSamples: [],
stats: { availability: 100, downChecks: 0, totalChecks: 0, upChecks: 0 },
target: "https://example.com",
type: "http",
...overrides,
};
}
describe("createTargetTableColumns", () => {
test("生成 8 个目标表格列", () => {
const columns = createTargetTableColumns(["http", "cmd"]);
expect(columns.map((column) => column.colKey)).toEqual([
"latestCheck.matched",
"name",
"type",
"stats.availability",
"recentSamples",
"currentStreak",
"latestCheck.durationMs",
"interval",
]);
});
test("根据 checkerTypes 生成类型筛选器", () => {
const typeColumn = getColumn(createTargetTableColumns(["http", "cmd", "tcp"]), "type");
const filter = typeColumn.filter as TableFilter;
expect(filter.type).toBe("single");
expect(filter.list).toEqual([
{ label: "全部", value: "" },
{ label: "http", value: "http" },
{ label: "cmd", value: "cmd" },
{ label: "tcp", value: "tcp" },
]);
});
test("checkerTypes 为空时只保留全部选项", () => {
const typeColumn = getColumn(createTargetTableColumns([]), "type");
const filter = typeColumn.filter as TableFilter;
expect(filter.list).toEqual([{ label: "全部", value: "" }]);
});
test("类型列直接渲染原始 type 文本", () => {
const typeColumn = getColumn(createTargetTableColumns(["tcp"]), "type");
const renderCell = typeColumn.cell as (params: PrimaryTableCellParams<TargetStatus>) => {
props: { children: unknown };
};
const element = renderCell({
col: typeColumn,
colIndex: 2,
row: makeTarget({ type: "tcp" }),
rowIndex: 0,
});
expect(element.props.children).toBe("tcp");
});
test("连续状态列渲染 capped 标记", () => {
const streakColumn = getColumn(createTargetTableColumns(["http"]), "currentStreak");
const renderCell = streakColumn.cell as (params: PrimaryTableCellParams<TargetStatus>) => {
props: { children: unknown[] };
};
const element = renderCell({
col: streakColumn,
colIndex: 5,
row: makeTarget({ currentStreak: { capped: true, count: 30, up: false } }),
rowIndex: 0,
});
expect(element.props.children.join("")).toBe("▼ 30+");
});
});