diff --git a/__tests__/coder-plugin.test.js b/__tests__/coder-plugin.test.js new file mode 100644 index 000000000..439d49e29 --- /dev/null +++ b/__tests__/coder-plugin.test.js @@ -0,0 +1,73 @@ +const fs = require("fs") +const os = require("os") +const path = require("path") +const { execSync } = require("child_process") + +const CLI = path.join(__dirname, "..", "cli", "supercli.js") + +function runNoServer(args, options = {}) { + try { + const env = { ...process.env } + delete env.SUPERCLI_SERVER + const out = execSync(`node ${CLI} ${args}`, { + encoding: "utf-8", + timeout: 15000, + env: { ...env, ...(options.env || {}) } + }) + return { ok: true, output: out.trim(), code: 0 } + } catch (err) { + return { + ok: false, + output: (err.stdout || "").trim(), + stderr: (err.stderr || "").trim(), + code: err.status + } + } +} + +function writeFakeCoderBinary(dir) { + const bin = path.join(dir, "coder") + fs.writeFileSync(bin, [ + "#!/usr/bin/env node", + "const args = process.argv.slice(2);", + "if (args[0] === '--version') { console.log('coder v2.18.0-test'); process.exit(0); }", + "console.log(JSON.stringify({ ok: true, args }));" + ].join("\n"), "utf-8") + fs.chmodSync(bin, 0o755) + return bin +} + +describe("coder plugin", () => { + const fakeDir = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-coder-")) + const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-home-coder-")) + writeFakeCoderBinary(fakeDir) + const env = { ...process.env, PATH: `${fakeDir}:${process.env.PATH || ""}`, SUPERCLI_HOME: tempHome } + + beforeAll(() => { + runNoServer("plugins install ./plugins/coder --on-conflict replace --json", { env }) + }) + + afterAll(() => { + runNoServer("plugins remove coder --json", { env }) + fs.rmSync(fakeDir, { recursive: true, force: true }) + fs.rmSync(tempHome, { recursive: true, force: true }) + }) + + test("supports namespace passthrough", () => { + const r = runNoServer("coder templates list --json", { env }) + expect(r.ok).toBe(true) + const data = JSON.parse(r.output) + expect(data.command).toBe("coder.passthrough") + expect(data.data.args).toContain("templates") + expect(data.data.args).toContain("list") + expect(data.data.args).toContain("--json") + }) + + test("doctor reports coder dependency as healthy", () => { + const r = runNoServer("plugins doctor coder --json", { env }) + expect(r.ok).toBe(true) + const data = JSON.parse(r.output) + expect(data.ok).toBe(true) + expect(data.checks.some(c => c.type === "binary" && c.binary === "coder" && c.ok === true)).toBe(true) + }) +}) diff --git a/__tests__/pkl-plugin.test.js b/__tests__/pkl-plugin.test.js new file mode 100644 index 000000000..e21087307 --- /dev/null +++ b/__tests__/pkl-plugin.test.js @@ -0,0 +1,73 @@ +const fs = require("fs") +const os = require("os") +const path = require("path") +const { execSync } = require("child_process") + +const CLI = path.join(__dirname, "..", "cli", "supercli.js") + +function runNoServer(args, options = {}) { + try { + const env = { ...process.env } + delete env.SUPERCLI_SERVER + const out = execSync(`node ${CLI} ${args}`, { + encoding: "utf-8", + timeout: 15000, + env: { ...env, ...(options.env || {}) } + }) + return { ok: true, output: out.trim(), code: 0 } + } catch (err) { + return { + ok: false, + output: (err.stdout || "").trim(), + stderr: (err.stderr || "").trim(), + code: err.status + } + } +} + +function writeFakePklBinary(dir) { + const bin = path.join(dir, "pkl") + fs.writeFileSync(bin, [ + "#!/usr/bin/env node", + "const args = process.argv.slice(2);", + "if (args[0] === '--version') { console.log('pkl 0.27.2-test'); process.exit(0); }", + "console.log(JSON.stringify({ ok: true, args }));" + ].join("\n"), "utf-8") + fs.chmodSync(bin, 0o755) + return bin +} + +describe("pkl plugin", () => { + const fakeDir = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-pkl-")) + const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-home-pkl-")) + writeFakePklBinary(fakeDir) + const env = { ...process.env, PATH: `${fakeDir}:${process.env.PATH || ""}`, SUPERCLI_HOME: tempHome } + + beforeAll(() => { + runNoServer("plugins install ./plugins/pkl --on-conflict replace --json", { env }) + }) + + afterAll(() => { + runNoServer("plugins remove pkl --json", { env }) + fs.rmSync(fakeDir, { recursive: true, force: true }) + fs.rmSync(tempHome, { recursive: true, force: true }) + }) + + test("supports namespace passthrough", () => { + const r = runNoServer("pkl eval config.pkl --json", { env }) + expect(r.ok).toBe(true) + const data = JSON.parse(r.output) + expect(data.command).toBe("pkl.passthrough") + expect(data.data.args).toContain("eval") + expect(data.data.args).toContain("config.pkl") + expect(data.data.args).toContain("--json") + }) + + test("doctor reports pkl dependency as healthy", () => { + const r = runNoServer("plugins doctor pkl --json", { env }) + expect(r.ok).toBe(true) + const data = JSON.parse(r.output) + expect(data.ok).toBe(true) + expect(data.checks.some(c => c.type === "binary" && c.binary === "pkl" && c.ok === true)).toBe(true) + }) +}) diff --git a/__tests__/rbspy-plugin.test.js b/__tests__/rbspy-plugin.test.js new file mode 100644 index 000000000..ad02ffb58 --- /dev/null +++ b/__tests__/rbspy-plugin.test.js @@ -0,0 +1,74 @@ +const fs = require("fs") +const os = require("os") +const path = require("path") +const { execSync } = require("child_process") + +const CLI = path.join(__dirname, "..", "cli", "supercli.js") + +function runNoServer(args, options = {}) { + try { + const env = { ...process.env } + delete env.SUPERCLI_SERVER + const out = execSync(`node ${CLI} ${args}`, { + encoding: "utf-8", + timeout: 15000, + env: { ...env, ...(options.env || {}) } + }) + return { ok: true, output: out.trim(), code: 0 } + } catch (err) { + return { + ok: false, + output: (err.stdout || "").trim(), + stderr: (err.stderr || "").trim(), + code: err.status + } + } +} + +function writeFakeRbspyBinary(dir) { + const bin = path.join(dir, "rbspy") + fs.writeFileSync(bin, [ + "#!/usr/bin/env node", + "const args = process.argv.slice(2);", + "if (args[0] === '--version') { console.log('rbspy 0.18.1-test'); process.exit(0); }", + "console.log(JSON.stringify({ ok: true, args }));" + ].join("\n"), "utf-8") + fs.chmodSync(bin, 0o755) + return bin +} + +describe("rbspy plugin", () => { + const fakeDir = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-rbspy-")) + const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "dcli-home-rbspy-")) + writeFakeRbspyBinary(fakeDir) + const env = { ...process.env, PATH: `${fakeDir}:${process.env.PATH || ""}`, SUPERCLI_HOME: tempHome } + + beforeAll(() => { + runNoServer("plugins install ./plugins/rbspy --on-conflict replace --json", { env }) + }) + + afterAll(() => { + runNoServer("plugins remove rbspy --json", { env }) + fs.rmSync(fakeDir, { recursive: true, force: true }) + fs.rmSync(tempHome, { recursive: true, force: true }) + }) + + test("supports namespace passthrough", () => { + const r = runNoServer("rbspy record --pid 1234 --json", { env }) + expect(r.ok).toBe(true) + const data = JSON.parse(r.output) + expect(data.command).toBe("rbspy.passthrough") + expect(data.data.args).toContain("record") + expect(data.data.args).toContain("--pid") + expect(data.data.args).toContain("1234") + expect(data.data.args).toContain("--json") + }) + + test("doctor reports rbspy dependency as healthy", () => { + const r = runNoServer("plugins doctor rbspy --json", { env }) + expect(r.ok).toBe(true) + const data = JSON.parse(r.output) + expect(data.ok).toBe(true) + expect(data.checks.some(c => c.type === "binary" && c.binary === "rbspy" && c.ok === true)).toBe(true) + }) +})