Files
dbx/apps/desktop/src/lib/__tests__/sidebar/sidebarTreeItemLayout.spec.ts
T

110 lines
6.3 KiB
TypeScript
Vendored

import { describe, expect, it } from "vitest";
import { alignedCommentLeadingWidth, alignedSidebarCommentLabelWidths, canTreeNodeShowExpander, sidebarTreeNaturalContentWidth, sidebarTreeNodeComment, trailingCommentAvailableWidth, treeItemPaddingLeft, treeLabelWidthClass, usesFullWidthTreeLabel } from "@/lib/sidebar/sidebarTreeItemLayout";
import type { TreeNode } from "@/types/database";
describe("sidebar tree item layout", () => {
it("keeps a table row constrained when it displays a comment", () => {
expect(usesFullWidthTreeLabel("table", true)).toBe(true);
expect(usesFullWidthTreeLabel("table", true, true)).toBe(false);
});
it("shows connection notes only after the user opts in", () => {
const connection: TreeNode = { id: "connection-1", label: "MySQL", type: "connection", comment: "Production" };
expect(sidebarTreeNodeComment(connection, false)).toBeNull();
expect(sidebarTreeNodeComment(connection, true)).toBe("Production");
});
it("lets a table name consume the available row width before truncating when aligned", () => {
expect(treeLabelWidthClass({ fullWidth: false, hasTrailingComment: true, alignLeading: true })).toBe("min-w-0 flex-1 truncate");
// inline/right 模式 label 不撑满,让 comment 紧跟
expect(treeLabelWidthClass({ fullWidth: false, hasTrailingComment: true, alignLeading: false })).toBe("min-w-0 shrink truncate");
});
it("keeps a pinned action next to the name while preserving the aligned comment column", () => {
expect(treeLabelWidthClass({ fullWidth: false, hasTrailingComment: true, hasInlineAction: true })).toBe("min-w-0 shrink truncate");
expect(alignedCommentLeadingWidth(100, true)).toBe(124);
expect(alignedCommentLeadingWidth(100, false)).toBe(100);
expect(alignedCommentLeadingWidth(undefined, true)).toBeUndefined();
});
it("renders navigation leaf actions without expanders", () => {
expect(canTreeNodeShowExpander({ type: "dynamodb-table", childCount: 0 })).toBe(false);
expect(canTreeNodeShowExpander({ type: "nacos-namespace", childCount: 0 })).toBe(false);
expect(canTreeNodeShowExpander({ type: "nacos-access-control", childCount: 0 })).toBe(false);
expect(canTreeNodeShowExpander({ type: "etcd-root", childCount: 0 })).toBe(false);
expect(canTreeNodeShowExpander({ type: "etcd-dashboard", childCount: 0 })).toBe(false);
expect(canTreeNodeShowExpander({ type: "etcd-access-control", childCount: 0 })).toBe(false);
expect(canTreeNodeShowExpander({ type: "consul-overview", childCount: 0 })).toBe(false);
});
it("shows an expander only for package nodes explicitly marked as containers", () => {
expect(canTreeNodeShowExpander({ type: "package", childCount: 0 })).toBe(false);
expect(canTreeNodeShowExpander({ type: "package", childCount: 0, explicitContainer: true })).toBe(true);
expect(canTreeNodeShowExpander({ type: "package-body", childCount: 0, explicitContainer: true })).toBe(false);
expect(canTreeNodeShowExpander({ type: "procedure", childCount: 0, explicitContainer: true })).toBe(false);
});
it("allows only an explicitly marked Xugu type specification to expand", () => {
expect(canTreeNodeShowExpander({ type: "type", childCount: 0, explicitContainer: true })).toBe(true);
expect(canTreeNodeShowExpander({ type: "type", childCount: 0 })).toBe(false);
expect(canTreeNodeShowExpander({ type: "type-body", childCount: 0, explicitContainer: true })).toBe(false);
});
it("shows an expander only while a custom type may still load children", () => {
expect(canTreeNodeShowExpander({ type: "type", childCount: undefined })).toBe(true);
expect(canTreeNodeShowExpander({ type: "type", childCount: 2 })).toBe(true);
expect(canTreeNodeShowExpander({ type: "type", childCount: 0 })).toBe(false);
expect(canTreeNodeShowExpander({ type: "type-member", childCount: undefined })).toBe(false);
});
it("aligns comments to the longest sibling name without crossing parent groups", () => {
const widths = alignedSidebarCommentLabelWidths([
{ id: "tables", depth: 1, alignable: false, hasComment: false, labelWidth: 0 },
{ id: "short", depth: 2, alignable: true, hasComment: true, labelWidth: 48 },
{ id: "long", depth: 2, alignable: true, hasComment: false, labelWidth: 136 },
{ id: "views", depth: 1, alignable: false, hasComment: false, labelWidth: 0 },
{ id: "view", depth: 2, alignable: true, hasComment: true, labelWidth: 72 },
]);
expect(widths.get("short")).toBe(136);
expect(widths.has("long")).toBe(false);
expect(widths.get("view")).toBe(72);
});
it("limits right-aligned comments to the space after the complete name and gap", () => {
expect(trailingCommentAvailableWidth(260, 100)).toBe(152);
expect(trailingCommentAvailableWidth(108, 100)).toBe(0);
expect(trailingCommentAvailableWidth(100, 100)).toBe(0);
expect(trailingCommentAvailableWidth(99, 100)).toBe(0);
});
it("keeps the natural width of the widest node in the complete virtual tree", () => {
const width = sidebarTreeNaturalContentWidth(
[
{ depth: 1, label: "visible", usesNaturalWidth: true },
{ depth: 4, label: "widest-node-outside-the-mounted-window", usesNaturalWidth: true, trailingWidth: 20 },
{ depth: 8, label: "constrained metadata row", usesNaturalWidth: false },
],
(text) => text.length * 7,
);
expect(width).toBe(4 * 16 + 8 + 54 + "widest-node-outside-the-mounted-window".length * 7 + 20);
});
it("returns zero when no tree row uses natural width", () => {
expect(sidebarTreeNaturalContentWidth([{ depth: 2, label: "commented", usesNaturalWidth: false }], (text) => text.length * 7)).toBe(0);
});
it("applies a configurable per-depth indent to rows and natural-width measurement", () => {
// Default keeps the historical 16px per level.
expect(treeItemPaddingLeft(2)).toBe("40px");
expect(treeItemPaddingLeft(2, 24)).toBe("56px");
expect(treeItemPaddingLeft(0, 24)).toBe("8px");
const items = [{ depth: 4, label: "nested", usesNaturalWidth: true, trailingWidth: 20 }];
const measure = (text: string) => text.length * 7;
expect(sidebarTreeNaturalContentWidth(items, measure, 16)).toBe(4 * 16 + 8 + 54 + "nested".length * 7 + 20);
expect(sidebarTreeNaturalContentWidth(items, measure, 32)).toBe(4 * 32 + 8 + 54 + "nested".length * 7 + 20);
});
});