import { describe, expect, it } from "vitest";
import type { HostStatusEntry } from "./host.js";
import {
formatHostPortsMarkdown,
formatHostResourcesMarkdown,
formatHostStatusMarkdown,
} from "./host.js";
describe("host formatters - emoji removal", () => {
describe("formatHostStatusMarkdown", () => {
it("should NOT contain green circle emoji π’", () => {
const status: HostStatusEntry[] = [
{ name: "squirts", connected: true, containerCount: 10, runningCount: 8 },
];
const output = formatHostStatusMarkdown(status);
expect(output).not.toContain("π’");
});
it("should NOT contain red circle emoji π΄", () => {
const status: HostStatusEntry[] = [
{
name: "squirts",
connected: false,
containerCount: 0,
runningCount: 0,
error: "Connection refused",
},
];
const output = formatHostStatusMarkdown(status);
expect(output).not.toContain("π΄");
});
it("should use canonical β for online hosts", () => {
const status: HostStatusEntry[] = [
{ name: "squirts", connected: true, containerCount: 10, runningCount: 8 },
];
const output = formatHostStatusMarkdown(status);
expect(output).toContain("β");
});
it("should use canonical β for offline hosts", () => {
const status: HostStatusEntry[] = [
{
name: "squirts",
connected: false,
containerCount: 0,
runningCount: 0,
error: "Connection refused",
},
];
const output = formatHostStatusMarkdown(status);
expect(output).toContain("β");
});
it("should NOT have markdown ## prefix in title", () => {
const status: HostStatusEntry[] = [
{ name: "squirts", connected: true, containerCount: 10, runningCount: 8 },
];
const output = formatHostStatusMarkdown(status);
// Title should be plain text per STYLE.md 3.1
const lines = output.split("\n");
expect(lines[0]).not.toMatch(/^##/);
});
it("should include summary line with host counts", () => {
const status: HostStatusEntry[] = [
{ name: "squirts", connected: true, containerCount: 10, runningCount: 8 },
{ name: "boops", connected: true, containerCount: 5, runningCount: 4 },
{
name: "nicks",
connected: false,
containerCount: 0,
runningCount: 0,
error: "Timeout",
},
];
const output = formatHostStatusMarkdown(status);
// Should include "Hosts: 3 | Online: 2 | Offline: 1" per STYLE.md 3.2
expect(output).toMatch(/Hosts: 3 \| Online: 2 \| Offline: 1/);
});
it("should include legend for mixed states", () => {
const status: HostStatusEntry[] = [
{ name: "squirts", connected: true, containerCount: 10, runningCount: 8 },
{
name: "boops",
connected: false,
containerCount: 0,
runningCount: 0,
error: "Timeout",
},
];
const output = formatHostStatusMarkdown(status);
// Should include legend per STYLE.md 3.3
expect(output).toContain("Legend:");
expect(output).toContain("β");
expect(output).toContain("β");
});
it("should sort offline hosts first (severity sorting)", () => {
const status: HostStatusEntry[] = [
{ name: "squirts", connected: true, containerCount: 10, runningCount: 8 },
{
name: "boops",
connected: false,
containerCount: 0,
runningCount: 0,
error: "Timeout",
},
{ name: "nicks", connected: true, containerCount: 5, runningCount: 4 },
];
const output = formatHostStatusMarkdown(status);
// Offline hosts should appear first per STYLE.md Section 12
const lines = output.split("\n");
const tableLines = lines.filter((l) => l.startsWith("|") && !l.startsWith("|---"));
// First data row should be "boops" (offline)
expect(tableLines[1]).toContain("boops");
expect(tableLines[1]).toContain("β");
});
});
describe("formatHostResourcesMarkdown", () => {
it("should NOT contain error emoji β", () => {
const results = [
{
host: "squirts",
resources: null,
error: "Connection timeout",
},
];
const output = formatHostResourcesMarkdown(results);
expect(output).not.toContain("β");
});
it("should use canonical β for errors", () => {
const results = [
{
host: "squirts",
resources: null,
error: "Connection timeout",
},
];
const output = formatHostResourcesMarkdown(results);
expect(output).toContain("β");
});
it("should NOT have markdown ## prefix in title", () => {
const results = [
{
host: "squirts",
resources: {
hostname: "squirts.local",
uptime: "10 days",
loadAverage: [1.0, 1.5, 2.0],
cpu: { cores: 8, usagePercent: 45 },
memory: { totalMB: 16384, usedMB: 8192, usagePercent: 50 },
disk: [],
},
},
];
const output = formatHostResourcesMarkdown(results);
const lines = output.split("\n");
expect(lines[0]).not.toMatch(/^##/);
});
it("should include freshness timestamp for volatile resource data", () => {
const results = [
{
host: "squirts",
resources: {
hostname: "squirts.local",
uptime: "10 days",
loadAverage: [1.0, 1.5, 2.0],
cpu: { cores: 8, usagePercent: 45 },
memory: { totalMB: 16384, usedMB: 8192, usagePercent: 50 },
disk: [],
},
},
];
const output = formatHostResourcesMarkdown(results);
expect(output).toMatch(/As of \(EST\): \d{2}:\d{2}:\d{2} \| \d{2}\/\d{2}\/\d{4}/);
});
it("should include warning symbol for CPU usage >90%", () => {
const results = [
{
host: "squirts",
resources: {
hostname: "squirts.local",
uptime: "10 days",
loadAverage: [1.0, 1.5, 2.0],
cpu: { cores: 8, usagePercent: 95 },
memory: { totalMB: 16384, usedMB: 8192, usagePercent: 50 },
disk: [],
},
},
];
const output = formatHostResourcesMarkdown(results);
// Should show β after CPU usage per STYLE.md 10.2
expect(output).toContain("95% β ");
});
it("should include warning symbol for memory usage >90%", () => {
const results = [
{
host: "squirts",
resources: {
hostname: "squirts.local",
uptime: "10 days",
loadAverage: [1.0, 1.5, 2.0],
cpu: { cores: 8, usagePercent: 45 },
memory: { totalMB: 16384, usedMB: 15360, usagePercent: 94 },
disk: [],
},
},
];
const output = formatHostResourcesMarkdown(results);
// Should show β after memory usage
expect(output).toContain("94% β ");
});
it("should include warning symbol for disk usage >85%", () => {
const results = [
{
host: "squirts",
resources: {
hostname: "squirts.local",
uptime: "10 days",
loadAverage: [1.0, 1.5, 2.0],
cpu: { cores: 8, usagePercent: 45 },
memory: { totalMB: 16384, usedMB: 8192, usagePercent: 50 },
disk: [
{
mount: "/",
totalGB: 100,
usedGB: 90,
usagePercent: 90,
},
],
},
},
];
const output = formatHostResourcesMarkdown(results);
// Should show β after disk usage
expect(output).toContain("90% β ");
});
it("should NOT include warning for normal usage levels", () => {
const results = [
{
host: "squirts",
resources: {
hostname: "squirts.local",
uptime: "10 days",
loadAverage: [1.0, 1.5, 2.0],
cpu: { cores: 8, usagePercent: 45 },
memory: { totalMB: 16384, usedMB: 8192, usagePercent: 50 },
disk: [
{
mount: "/",
totalGB: 100,
usedGB: 50,
usagePercent: 50,
},
],
},
},
];
const output = formatHostResourcesMarkdown(results);
// Should NOT show any warnings
expect(output).not.toContain("β ");
});
});
describe("formatHostPortsMarkdown", () => {
it("should NOT contain emoji in port mappings", () => {
const ports = [
{
port: 8080,
protocol: "tcp" as const,
state: "listening" as const,
source: "compose" as const,
containerName: "nginx",
containerPort: 80,
},
];
const output = formatHostPortsMarkdown(ports, "squirts", 1, 0, false);
// Should not contain any emoji
expect(output).not.toContain("π³");
expect(output).not.toContain("π΅");
expect(output).not.toContain("π₯οΈ");
expect(output).not.toContain("π’");
expect(output).not.toContain("βͺ");
});
it("should NOT have markdown ## prefix in title", () => {
const ports = [
{
port: 8080,
protocol: "tcp" as const,
state: "listening" as const,
source: "compose" as const,
containerName: "nginx",
containerPort: 80,
},
];
const output = formatHostPortsMarkdown(ports, "squirts", 1, 0, false);
const lines = output.split("\n");
expect(lines[0]).not.toMatch(/^##/);
});
it("should use standard pagination footer format (not italic)", () => {
const ports = [
{
port: 8080,
protocol: "tcp" as const,
state: "listening" as const,
source: "compose" as const,
containerName: "nginx",
containerPort: 80,
},
];
const output = formatHostPortsMarkdown(ports, "squirts", 10, 0, true);
// Should use standard footer: "Showing 1βN of M | next_offset: N"
// NOT italic: "*More results available...*"
expect(output).toMatch(/Showing \d+β\d+ of \d+ \| next_offset: \d+/);
expect(output).not.toMatch(/\*More results available/);
});
it("should use canonical β for port mapping notation", () => {
const ports = [
{
port: 8080,
protocol: "tcp" as const,
state: "listening" as const,
source: "docker" as const,
containerName: "nginx",
containerPort: 80,
},
];
const output = formatHostPortsMarkdown(ports, "squirts", 1, 0, false);
// Port mapping should show as "8080 β 80" using canonical arrow
expect(output).toContain("β");
});
});
});