Files
Netcatty/components/terminal/TerminalConnectionDialog.test.ts
2026-06-09 18:52:30 +08:00

174 lines
4.9 KiB
TypeScript

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 type { Host } from "../../types.ts";
import { TerminalConnectionDialog } from "./TerminalConnectionDialog.tsx";
const host: Host = {
id: "host-1",
label: "10.2.0.32",
hostname: "10.2.0.32",
port: 22,
username: "root",
tags: [],
os: "linux",
protocol: "ssh",
};
const renderDialog = (
props: Partial<React.ComponentProps<typeof TerminalConnectionDialog>> = {},
) => renderToStaticMarkup(
React.createElement(
I18nProvider,
{ locale: "en" },
React.createElement(TerminalConnectionDialog, {
host,
status: "connecting",
error: null,
progressValue: 55,
chainProgress: null,
needsAuth: false,
showLogs: false,
_setShowLogs: () => {},
keys: [],
authProps: {
authMethod: "password",
setAuthMethod: () => {},
authUsername: "root",
setAuthUsername: () => {},
authPassword: "",
setAuthPassword: () => {},
authKeyId: null,
setAuthKeyId: () => {},
authPassphrase: "",
setAuthPassphrase: () => {},
showAuthPassphrase: false,
setShowAuthPassphrase: () => {},
showAuthPassword: false,
setShowAuthPassword: () => {},
authRetryMessage: null,
onSubmit: () => {},
onCancel: () => {},
isValid: true,
},
progressProps: {
timeLeft: 20,
isCancelling: false,
progressLogs: ["Host key verification required for 10.2.0.32."],
onCancelConnect: () => {},
onCloseSession: () => {},
onRetry: () => {},
},
...props,
}),
),
);
test("renders host key confirmation inside the connection dialog", () => {
const markup = renderDialog({
showLogs: true,
hostKeyVerification: {
hostKeyInfo: {
hostname: "10.2.0.32",
port: 22,
keyType: "ssh-ed25519",
fingerprint: "abc123",
status: "unknown",
},
onClose: () => {},
onContinue: () => {},
onAddAndContinue: () => {},
},
});
assert.match(markup, /Confirm this host key/);
assert.match(markup, /abc123/);
assert.match(markup, /Add and continue/);
assert.match(markup, /Host key verification required for 10\.2\.0\.32\./);
assert.equal(markup.includes("Timeout in"), false);
});
test("renders changed host key warning in the same connection dialog", () => {
const markup = renderDialog({
hostKeyVerification: {
hostKeyInfo: {
hostname: "10.2.0.32",
port: 22,
keyType: "ssh-ed25519",
fingerprint: "new-fingerprint",
knownFingerprint: "old-fingerprint",
status: "changed",
},
onClose: () => {},
onContinue: () => {},
onAddAndContinue: () => {},
},
});
assert.match(markup, /Host key changed/);
assert.match(markup, /new-fingerprint/);
assert.match(markup, /Saved fingerprint/);
assert.match(markup, /old-fingerprint/);
assert.match(markup, /Update and continue/);
});
test("keeps the second progress segment parked until the first segment finishes", () => {
const markup = renderDialog({ progressValue: 75 });
assert.match(markup, /style="width:100%"/);
assert.match(markup, /style="width:0%"/);
});
test("fills both progress segments for disconnected states", () => {
const markup = renderDialog({
status: "disconnected",
error: "Connection timed out.",
progressValue: 5,
});
const fullSegments = markup.match(/style="width:100%"/g) ?? [];
assert.equal(fullSegments.length >= 2, true);
});
test("keeps connection log padding inside the scrollable content", () => {
const markup = renderDialog({
status: "disconnected",
error: "Connection timed out.",
showLogs: true,
progressProps: {
timeLeft: 0,
isCancelling: false,
progressLogs: Array.from({ length: 12 }, (_, index) => `Log line ${index + 1}`),
onCancelConnect: () => {},
onCloseSession: () => {},
onRetry: () => {},
},
});
assert.match(markup, /class="[^"]*max-h-44/);
assert.doesNotMatch(markup, /class="[^"]*max-h-44[^"]*p-2\.5/);
assert.match(markup, /class="[^"]*p-2\.5[^"]*pb-4[^"]*pr-4/);
});
test("shows the ET server port (not the SSH port) for an ET host with a custom etPort", () => {
const markup = renderDialog({
host: { ...host, etEnabled: true, port: 22, etPort: 9022 },
});
// ET connectivity hinges on the etserver port, so the dialog must show it.
assert.match(markup, /10\.2\.0\.32:9022/);
assert.equal(markup.includes("10.2.0.32:22"), false);
});
test("defaults the displayed ET port to 2022 when no etPort is set", () => {
const markup = renderDialog({
host: { ...host, etEnabled: true, port: 22 },
});
assert.match(markup, /10\.2\.0\.32:2022/);
assert.equal(markup.includes("10.2.0.32:22"), false);
});