1
0
Files
DiAL/tests/web/constants/target-table-sorters.test.ts
lanyuanxiaoyao f48e39a615 refactor: 全面重构前端 Dashboard 为 TDesign + TanStack Query 分组表格布局
- 卡片式布局改为分组 PrimaryTable,Modal 改为 Drawer
- 手写 hooks 替换为 TanStack Query(轮询/缓存/条件查询)
- CSS 607行精简至73行,颜色迁移至 TDesign tokens
- 可用率进度条颜色按 10% 一档红→绿渐变
- 新增纯函数测试 34 项全通过(排序/筛选/色阶阈值)
- 同步更新主 specs 并归档变更文档
2026-05-12 01:06:53 +08:00

112 lines
3.7 KiB
TypeScript

import { describe, test, expect } from "bun:test";
import {
statusSorter,
availabilitySorter,
latencySorter,
nameSorter,
} from "../../../src/web/constants/target-table-sorters";
import type { TargetStatus } from "../../../src/shared/api";
function makeTarget(overrides: Partial<TargetStatus> = {}): TargetStatus {
return {
id: 1,
name: "test",
type: "http",
target: "https://example.com",
group: "default",
interval: "5s",
latestCheck: null,
stats: { totalChecks: 0, availability: 100 },
recentSamples: [],
...overrides,
};
}
describe("statusSorter", () => {
test("DOWN 排在 UP 前面", () => {
const up = makeTarget({
latestCheck: { timestamp: "", matched: true, durationMs: 10, statusDetail: null, failure: null },
});
const down = makeTarget({
latestCheck: { timestamp: "", matched: false, durationMs: 10, statusDetail: null, failure: null },
});
expect(statusSorter(down, up)).toBeLessThan(0);
expect(statusSorter(up, down)).toBeGreaterThan(0);
});
test("相同状态返回 0", () => {
const a = makeTarget({
latestCheck: { timestamp: "", matched: true, durationMs: 10, statusDetail: null, failure: null },
});
const b = makeTarget({
latestCheck: { timestamp: "", matched: true, durationMs: 20, statusDetail: null, failure: null },
});
expect(statusSorter(a, b)).toBe(0);
});
test("无 latestCheck 的目标排在最后", () => {
const noCheck = makeTarget();
const up = makeTarget({
latestCheck: { timestamp: "", matched: true, durationMs: 10, statusDetail: null, failure: null },
});
expect(statusSorter(noCheck, up)).toBeGreaterThan(0);
});
});
describe("availabilitySorter", () => {
test("低可用率排前面", () => {
const low = makeTarget({ stats: { totalChecks: 100, availability: 95 } });
const high = makeTarget({ stats: { totalChecks: 100, availability: 99.9 } });
expect(availabilitySorter(low, high)).toBeLessThan(0);
});
test("相同可用率返回 0", () => {
const a = makeTarget({ stats: { totalChecks: 100, availability: 99.9 } });
const b = makeTarget({ stats: { totalChecks: 50, availability: 99.9 } });
expect(availabilitySorter(a, b)).toBe(0);
});
test("无 stats 按 0 处理", () => {
const noStats = makeTarget({ stats: undefined as unknown as TargetStatus["stats"] });
const high = makeTarget({ stats: { totalChecks: 100, availability: 99.9 } });
expect(availabilitySorter(noStats, high)).toBeLessThan(0);
});
});
describe("latencySorter", () => {
test("低延迟排前面", () => {
const fast = makeTarget({
latestCheck: { timestamp: "", matched: true, durationMs: 50, statusDetail: null, failure: null },
});
const slow = makeTarget({
latestCheck: { timestamp: "", matched: true, durationMs: 200, statusDetail: null, failure: null },
});
expect(latencySorter(fast, slow)).toBeLessThan(0);
});
test("无延迟排最后", () => {
const noLatency = makeTarget({
latestCheck: { timestamp: "", matched: true, durationMs: null, statusDetail: null, failure: null },
});
const hasLatency = makeTarget({
latestCheck: { timestamp: "", matched: true, durationMs: 100, statusDetail: null, failure: null },
});
expect(latencySorter(noLatency, hasLatency)).toBeGreaterThan(0);
});
});
describe("nameSorter", () => {
test("按名称字母排序", () => {
const a = makeTarget({ name: "Alpha" });
const b = makeTarget({ name: "Beta" });
expect(nameSorter(a, b)).toBeLessThan(0);
});
test("中文名称排序", () => {
const a = makeTarget({ name: "百度" });
const b = makeTarget({ name: "谷歌" });
const result = nameSorter(a, b);
expect(typeof result).toBe("number");
});
});