Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions __tests__/help.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
"use strict"

const {
displayJsonHelp,
renderTopLevelHelp,
} = require("../cli/help")

// ──────────────────────────────────────────────────────────────────────────────
// displayJsonHelp
// ──────────────────────────────────────────────────────────────────────────────

describe("displayJsonHelp", () => {
const help = displayJsonHelp()

test("returns core identity fields", () => {
expect(help.name).toBe("SuperCLI")
expect(help.repository).toBe("https://github.com/javimosch/supercli")
expect(typeof help.description).toBe("string")
})

test("advertises the documented output modes", () => {
const modes = help.output_modes.join(" ")
expect(modes).toContain("--json")
expect(modes).toContain("--human")
expect(modes).toContain("--compact")
})

test("exposes exit codes as {code, description} pairs", () => {
expect(Array.isArray(help.exit_codes)).toBe(true)
for (const entry of help.exit_codes) {
expect(typeof entry.code).toBe("number")
expect(typeof entry.description).toBe("string")
}
})

test("includes the success exit code (0)", () => {
const success = help.exit_codes.find((e) => e.code === 0)
expect(success).toBeDefined()
expect(success.description).toBe("success")
})
})

// ──────────────────────────────────────────────────────────────────────────────
// renderTopLevelHelp (JSON / non-human path)
// ──────────────────────────────────────────────────────────────────────────────

describe("renderTopLevelHelp", () => {
const config = {
commands: [
{ namespace: "aws", resource: "cfn", action: "deploy" },
{ namespace: "aws", resource: "cfn", action: "delete" },
{ namespace: "aws", resource: "s3", action: "sync" },
{ namespace: "git", resource: "repo", action: "clone" },
],
}

function render() {
let captured
renderTopLevelHelp(config, {
humanMode: false,
output: (payload) => {
captured = payload
},
hasServer: false,
})
return captured
}

test("groups commands by namespace without duplicates", () => {
const out = render()
expect(out.namespaces.map((n) => n.name)).toEqual(["aws", "git"])
})

test("nests resources and their actions under each namespace", () => {
const out = render()
const aws = out.namespaces.find((n) => n.name === "aws")
const cfn = aws.resources.find((r) => r.name === "cfn")
expect(cfn.actions).toEqual(["deploy", "delete"])
expect(aws.resources.map((r) => r.name)).toEqual(["cfn", "s3"])
})

test("does not throw and returns nothing in human mode", () => {
const logSpy = jest.spyOn(console, "log").mockImplementation(() => {})
try {
const result = renderTopLevelHelp(config, {
humanMode: true,
output: () => {},
hasServer: true,
})
expect(result).toBeUndefined()
expect(logSpy).toHaveBeenCalled()
} finally {
logSpy.mockRestore()
}
})
})
62 changes: 62 additions & 0 deletions __tests__/mcp-diagnostics.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"use strict"

const {
commandBinary,
checkCommandAvailable,
} = require("../cli/mcp-diagnostics")

// ──────────────────────────────────────────────────────────────────────────────
// commandBinary — extracts the executable name from a command string
// ──────────────────────────────────────────────────────────────────────────────

describe("commandBinary", () => {
test("returns the first token of a command", () => {
expect(commandBinary("npx some-mcp-server --flag")).toBe("npx")
})

test("collapses leading/inner whitespace", () => {
expect(commandBinary(" node server.js ")).toBe("node")
})

test("handles a bare binary with no args", () => {
expect(commandBinary("docker")).toBe("docker")
})

test("returns empty string for empty / whitespace input", () => {
expect(commandBinary("")).toBe("")
expect(commandBinary(" ")).toBe("")
})

test("returns empty string for null/undefined", () => {
expect(commandBinary(null)).toBe("")
expect(commandBinary(undefined)).toBe("")
})

test("coerces non-string input via String()", () => {
expect(commandBinary(123)).toBe("123")
})
})

// ──────────────────────────────────────────────────────────────────────────────
// checkCommandAvailable — the no-binary short-circuit (no process spawned)
// ──────────────────────────────────────────────────────────────────────────────

describe("checkCommandAvailable", () => {
test("reports failure for an empty command without probing PATH", () => {
const result = checkCommandAvailable("")
expect(result.ok).toBe(false)
expect(result.message).toBe("Missing command")
})

test("finds a binary that exists in PATH (sh)", () => {
const result = checkCommandAvailable("sh -c 'echo hi'")
expect(result.ok).toBe(true)
expect(result.message).toContain("sh")
})

test("reports a clear message for a binary that does not exist", () => {
const result = checkCommandAvailable("definitely-not-a-real-binary-xyz")
expect(result.ok).toBe(false)
expect(result.message).toContain("not found in PATH")
})
})
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "superacli",
"version": "1.31.5",
"description": "5,000+ tools. One CLI. Zero configuration.",
"description": "10,000+ tools. One CLI. Zero configuration.",
"license": "MIT",
"main": "server/app.js",
"bin": {
Expand Down
Loading