mirror of
https://github.com/Quad4-Software/MeshChatX.git
synced 2026-08-18 09:49:09 -04:00
124 lines
4.7 KiB
JavaScript
124 lines
4.7 KiB
JavaScript
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
import {
|
|
ANNOUNCE_HASH_CHUNK_SIZE,
|
|
VIZ_ANNOUNCE_ASPECTS,
|
|
buildPathGraph,
|
|
buildPathGraphJs,
|
|
computeLodUpdatesJs,
|
|
dedupeIconQueueEntries,
|
|
dedupeIconQueueEntriesJs,
|
|
lodLevelFromScale,
|
|
pathHashesWithinHopFilter,
|
|
pathHashesWithinHopFilterJs,
|
|
layoutSpringLength,
|
|
pickAdaptiveFetchConcurrency,
|
|
} from "@/js/networkVisualiserPerf.js";
|
|
|
|
describe("networkVisualiserPerf", () => {
|
|
beforeEach(() => {
|
|
delete globalThis.meshchatxVisualiserPathHashes;
|
|
delete globalThis.meshchatxVisualiserDedupeIcons;
|
|
delete globalThis.meshchatxVisualiserBuildPathGraph;
|
|
delete globalThis.meshchatxVisualiserLODLevel;
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
it("exports visualiser constants", () => {
|
|
expect(VIZ_ANNOUNCE_ASPECTS).toEqual(["lxmf.delivery", "nomadnetwork.node"]);
|
|
expect(ANNOUNCE_HASH_CHUNK_SIZE).toBe(500);
|
|
expect(layoutSpringLength(3)).toBe(200);
|
|
expect(layoutSpringLength(1)).toBe(240);
|
|
});
|
|
|
|
it("pathHashesWithinHopFilter respects hop max", () => {
|
|
const pathTable = [
|
|
{ hash: "aa", hops: 1 },
|
|
{ hash: "bb", hops: 4 },
|
|
{ hash: "cc", hops: 5 },
|
|
{ hash: "dd", hops: null },
|
|
];
|
|
expect(pathHashesWithinHopFilterJs(pathTable, 4).sort()).toEqual(["aa", "bb"]);
|
|
expect(pathHashesWithinHopFilter(pathTable, null).sort()).toEqual(["aa", "bb", "cc"]);
|
|
});
|
|
|
|
it("dedupeIconQueueEntries collapses duplicate cache keys", () => {
|
|
const queue = [
|
|
{ nodeId: "n1", cacheKey: "k1", iconName: "a", fg: "#000", bg: "#fff", size: 64, generation: 1 },
|
|
{ nodeId: "n2", cacheKey: "k1", iconName: "a", fg: "#000", bg: "#fff", size: 64, generation: 1 },
|
|
{ nodeId: "n3", cacheKey: "k2", iconName: "b", fg: "#111", bg: "#eee", size: 64, generation: 1 },
|
|
];
|
|
const out = dedupeIconQueueEntriesJs(queue);
|
|
expect(out).toHaveLength(2);
|
|
expect(out.find((x) => x.cacheKey === "k1")?.nodeIds).toEqual(["n1", "n2"]);
|
|
expect(dedupeIconQueueEntries(queue)).toHaveLength(2);
|
|
});
|
|
|
|
it("pickAdaptiveFetchConcurrency returns a positive integer", () => {
|
|
expect(pickAdaptiveFetchConcurrency()).toBeGreaterThanOrEqual(2);
|
|
});
|
|
|
|
it("buildPathGraphJs filters hops and builds nodes/edges", () => {
|
|
const res = buildPathGraphJs({
|
|
path_table: [
|
|
{ hash: "aa", interface: "eth0", hops: 1 },
|
|
{ hash: "bb", interface: "eth0", hops: 9 },
|
|
],
|
|
announces: {
|
|
aa: {
|
|
destination_hash: "aa",
|
|
aspect: "lxmf.delivery",
|
|
display_name: "Alice",
|
|
last_seen: "now",
|
|
},
|
|
bb: {
|
|
destination_hash: "bb",
|
|
aspect: "lxmf.delivery",
|
|
display_name: "Far",
|
|
last_seen: "now",
|
|
},
|
|
},
|
|
positions: { eth0: { x: 10, y: 20 } },
|
|
hop_max: 4,
|
|
dark_mode: false,
|
|
lod: "high",
|
|
});
|
|
expect(res.nodes).toHaveLength(1);
|
|
expect(res.edges).toHaveLength(1);
|
|
expect(res.nodes[0].id).toBe("aa");
|
|
expect(res.edges[0].width).toBe(2.5);
|
|
const dx = res.nodes[0].x - 10;
|
|
const dy = res.nodes[0].y - 20;
|
|
expect(Math.hypot(dx, dy)).toBeGreaterThanOrEqual(140);
|
|
expect(buildPathGraph({ path_table: [], announces: {} }).nodes).toEqual([]);
|
|
});
|
|
|
|
it("computeLodUpdatesJs and lodLevelFromScale work without WASM", () => {
|
|
expect(lodLevelFromScale(0.1)).toBe("low");
|
|
expect(lodLevelFromScale(0.3)).toBe("medium");
|
|
expect(lodLevelFromScale(0.8)).toBe("high");
|
|
const updates = computeLodUpdatesJs(
|
|
[{ id: "n1", shape: "circularImage", size: 25, _originalShape: "circularImage", _originalSize: 25 }],
|
|
"low",
|
|
false
|
|
);
|
|
expect(updates[0].shape).toBe("dot");
|
|
});
|
|
|
|
it("falls back to JS when WASM export throws", () => {
|
|
globalThis.meshchatxVisualiserPathHashes = () => {
|
|
throw new Error("boom");
|
|
};
|
|
globalThis.meshchatxVisualiserBuildPathGraph = () => {
|
|
throw new Error("boom");
|
|
};
|
|
globalThis.meshchatxVisualiserDedupeIcons = () => {
|
|
throw new Error("boom");
|
|
};
|
|
expect(pathHashesWithinHopFilter([{ hash: "aa", hops: 1 }], 4)).toEqual(["aa"]);
|
|
expect(dedupeIconQueueEntries([])).toEqual([]);
|
|
expect(buildPathGraph({ path_table: [], announces: {} }).nodes).toEqual([]);
|
|
});
|
|
});
|