import test from "node:test"; import assert from "node:assert/strict"; import React from "react"; import { renderToStaticMarkup } from "react-dom/server"; import { I18nProvider } from "../application/i18n/I18nProvider.tsx"; import { STORAGE_KEY_VAULT_HOSTS_SORT_MODE } from "../infrastructure/config/storageKeys.ts"; import type { Host, SSHKey } from "../types.ts"; import { VaultView } from "./VaultView.tsx"; import { TooltipProvider } from "./ui/tooltip.tsx"; const installStorageStub = (sortMode: string | null) => { const values = new Map(); if (sortMode !== null) { values.set(STORAGE_KEY_VAULT_HOSTS_SORT_MODE, sortMode); } Object.defineProperty(globalThis, "localStorage", { configurable: true, value: { getItem: (key: string) => values.get(key) ?? null, setItem: (key: string, value: string) => { values.set(key, value); }, removeItem: (key: string) => { values.delete(key); }, }, }); }; const host = (id: string, label: string, createdAt: number, group = ""): Host => ({ id, label, hostname: `${id}.example.com`, username: "root", tags: [], os: "linux", port: 22, protocol: "ssh", authMethod: "password", createdAt, group, }); const fallbackKey: SSHKey = { id: "key-1", label: "Fallback key", type: "ED25519", privateKey: "", source: "generated", category: "key", created: 1, }; const renderVault = (sortMode: string | null, hosts: Host[]) => { installStorageStub(sortMode); const noop = () => {}; return renderToStaticMarkup( React.createElement( I18nProvider, { locale: "en", children: React.createElement( TooltipProvider, null, React.createElement(VaultView, { hosts, keys: [], identities: [], proxyProfiles: [], snippets: [], snippetPackages: [], customGroups: [], knownHosts: [], managedSources: [], sessionCount: 0, hotkeyScheme: "mac", keyBindings: [], terminalThemeId: "default", terminalFontSize: 14, onOpenSettings: noop, onOpenQuickSwitcher: noop, onCreateLocalTerminal: noop, onDeleteHost: noop, onConnect: noop, onUpdateHosts: noop, onUpdateKeys: noop, onImportOrReuseKey: () => fallbackKey, onUpdateIdentities: noop, onUpdateProxyProfiles: noop, onUpdateSnippets: noop, onUpdateSnippetPackages: noop, onUpdateCustomGroups: noop, onUpdateKnownHosts: noop, onUpdateManagedSources: noop, onReadPersistedHosts: async () => hosts, onReadPersistedManagedSources: () => [], onCommitPluginImporterData: async () => 0, onCommitVaultImportTransaction: async () => ({ status: "persisted" as const, groups: [], sources: [], groupConfigs: [], }), onCommitVaultGroupMutation: async (mutate) => mutate({ groups: [], configs: [], hosts, managedSources: [], snippets: [], }), onConvertKnownHost: noop, onOpenLogView: noop, groupConfigs: [], onUpdateGroupConfigs: noop, showRecentHosts: false, showOnlyUngroupedHostsInRoot: false, }), ), }, ), ); }; test("Hosts sort mode is restored from storage", () => { const markup = renderVault("za", [ host("alpha", "Alpha Host", 1), host("zulu", "Zulu Host", 2), ]); assert.ok(markup.indexOf("Zulu Host") < markup.indexOf("Alpha Host")); }); test("Hosts grouped sort mode is restored from storage", () => { const markup = renderVault("group", [ host("beta", "Beta Host", 1, "Beta Group"), host("alpha", "Alpha Host", 2, "Alpha Group"), ]); assert.match( markup, /Alpha Group<\/span>\(1\)<\/span>/, ); }); test("Hosts sort mode falls back safely when storage contains an invalid value", () => { const markup = renderVault("unknown-sort", [ { ...host("zulu", "Zulu Host", 2), order: 1000 }, { ...host("alpha", "Alpha Host", 1), order: 2000 }, ]); assert.ok(markup.indexOf("Zulu Host") < markup.indexOf("Alpha Host")); }); test("Hosts manual sort mode uses saved order", () => { const markup = renderVault("manual", [ { ...host("alpha", "Alpha Host", 1), order: 2000 }, { ...host("zulu", "Zulu Host", 2), order: 1000 }, ]); assert.ok(markup.indexOf("Zulu Host") < markup.indexOf("Alpha Host")); });