- ICMP checker 的 type/configKey/YAML 配置键/接口属性名从 ping 改为 icmp - IcmpChecker 添加 platform 构造函数注入,修复 Windows 测试兼容性 - 前端 target 表格延迟列优化:标题简化为「延迟」,单位下移到单元格,宽度 80px - Drawer 概览页 Descriptions 添加 tableLayout=auto 收窄 label 宽度 - 同步更新 README.md、DEVELOPMENT.md、probes.example.yaml、JSON Schema 和全部测试
186 lines
5.9 KiB
TypeScript
186 lines
5.9 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,
|
|
description: 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("生成 7 个目标表格列", () => {
|
|
const columns = createTargetTableColumns(["http", "cmd"]);
|
|
|
|
expect(columns.map((column) => column.colKey)).toEqual([
|
|
"latestCheck.matched",
|
|
"name",
|
|
"type",
|
|
"stats.availability",
|
|
"recentSamples",
|
|
"currentStreak",
|
|
"latestCheck.durationMs",
|
|
]);
|
|
});
|
|
|
|
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(streakColumn.title).toBe("连续(次)");
|
|
expect(element.props.children.join("")).toBe("▼ 30+");
|
|
});
|
|
|
|
test("延迟列超过 9999ms 时显示上限文案", () => {
|
|
const latencyColumn = getColumn(createTargetTableColumns(["http"]), "latestCheck.durationMs");
|
|
const renderCell = latencyColumn.cell as (params: PrimaryTableCellParams<TargetStatus>) => {
|
|
props: { children: string; className: string };
|
|
};
|
|
const element = renderCell({
|
|
col: latencyColumn,
|
|
colIndex: 6,
|
|
row: makeTarget({
|
|
latestCheck: {
|
|
detail: "200",
|
|
durationMs: 12000,
|
|
failure: null,
|
|
matched: true,
|
|
observation: null,
|
|
timestamp: "2026-01-01T00:00:00.000Z",
|
|
},
|
|
}),
|
|
rowIndex: 0,
|
|
});
|
|
|
|
expect(element.props.children).toEqual(["9999+", " ms"]);
|
|
expect(element.props.className).toContain("latency-value");
|
|
});
|
|
|
|
test("延迟列标题为 延迟", () => {
|
|
const latencyColumn = getColumn(createTargetTableColumns(["http"]), "latestCheck.durationMs");
|
|
expect(latencyColumn.title).toBe("延迟");
|
|
});
|
|
|
|
test("延迟列正常值包含 ms 单位", () => {
|
|
const latencyColumn = getColumn(createTargetTableColumns(["http"]), "latestCheck.durationMs");
|
|
const renderCell = latencyColumn.cell as (params: PrimaryTableCellParams<TargetStatus>) => {
|
|
props: { children: string; className: string };
|
|
};
|
|
const element = renderCell({
|
|
col: latencyColumn,
|
|
colIndex: 6,
|
|
row: makeTarget({
|
|
latestCheck: {
|
|
detail: "200",
|
|
durationMs: 123,
|
|
failure: null,
|
|
matched: true,
|
|
observation: null,
|
|
timestamp: "2026-01-01T00:00:00.000Z",
|
|
},
|
|
}),
|
|
rowIndex: 0,
|
|
});
|
|
expect(element.props.children).toEqual(["123", " ms"]);
|
|
});
|
|
|
|
test("名称列无排序配置", () => {
|
|
const nameColumn = getColumn(createTargetTableColumns(["http"]), "name");
|
|
expect(nameColumn.sorter).toBeUndefined();
|
|
expect(nameColumn.sortType).toBeUndefined();
|
|
});
|
|
|
|
test("名称列 name 为 null 时显示 id", () => {
|
|
const nameColumn = getColumn(createTargetTableColumns(["http"]), "name");
|
|
const renderCell = nameColumn.cell as (params: PrimaryTableCellParams<TargetStatus>) => string;
|
|
const result = renderCell({
|
|
col: nameColumn,
|
|
colIndex: 1,
|
|
row: makeTarget({ id: "my-api", name: null }),
|
|
rowIndex: 0,
|
|
});
|
|
expect(result).toBe("my-api");
|
|
});
|
|
|
|
test("名称列 name 有值时显示 name", () => {
|
|
const nameColumn = getColumn(createTargetTableColumns(["http"]), "name");
|
|
const renderCell = nameColumn.cell as (params: PrimaryTableCellParams<TargetStatus>) => string;
|
|
const result = renderCell({
|
|
col: nameColumn,
|
|
colIndex: 1,
|
|
row: makeTarget({ id: "my-api", name: "我的 API" }),
|
|
rowIndex: 0,
|
|
});
|
|
expect(result).toBe("我的 API");
|
|
});
|
|
});
|