Files
truthmark/tests/cli/platform-selection.test.ts
e3edcc8afa feat: v2.3.0 add interactive platform selection to init (#38)
* feat: add interactive platform selection to init

* chore: remove completed OpenSpec artifacts

* chore: remove implemented design note

* fix: protect init lifecycle from unsafe config paths

* fix: support clearing init platforms from CLI

* docs: retire config command from repository rules

* docs: align init lifecycle and clear-platform contracts

* docs: keep repository guidance current-state focused

* docs: limit cleanup to repository-native documents

* docs: preserve historical version notes

---------

Co-authored-by: MerlinH <merlinh221@gmail.com>
2026-07-31 18:54:10 +10:00

85 lines
2.4 KiB
TypeScript

import { PassThrough, Readable, Writable } from "node:stream";
import { describe, it } from "node:test";
import { expect } from "expect";
import {
parsePlatformSelection,
promptForPlatforms,
renderPlatformChoices,
} from "../../src/cli/platform-selection.js";
describe("interactive platform selection", () => {
it("renders the authoritative catalog in stable order", () => {
const output = renderPlatformChoices(["opencode", "cursor"]);
expect(output).toContain("1. Codex [codex]");
expect(output).toContain("2. OpenCode [opencode] (selected)");
expect(output).toContain("6. Cursor [cursor] (selected)");
});
it("parses, deduplicates, and normalizes numbered choices", () => {
expect(parsePlatformSelection("6, 1, 6", [])).toEqual([
"codex",
"cursor",
]);
});
it("keeps defaults on blank input", () => {
expect(parsePlatformSelection("", ["cursor", "codex"])).toEqual([
"codex",
"cursor",
]);
});
it("supports an explicit host-neutral selection", () => {
expect(parsePlatformSelection("none", ["codex"])).toEqual([]);
});
it("supports cancellation", () => {
expect(parsePlatformSelection("q", ["codex"])).toBeNull();
});
it("rejects unsupported choice numbers", () => {
expect(() => parsePlatformSelection("1,7", [])).toThrow(
"Unsupported platform choice: 7",
);
});
it("re-prompts after invalid interactive input", async () => {
let output = "";
const input = new PassThrough();
setImmediate(() => input.write("9\n"));
setTimeout(() => input.end("1\n"), 10);
const selected = await promptForPlatforms({
defaults: [],
input,
output: new Writable({
write(chunk, _encoding, callback) {
output += chunk.toString();
callback();
},
}),
});
expect(selected).toEqual(["codex"]);
expect(output).toContain("Unsupported platform choice: 9");
});
it("prompts through injected streams", async () => {
let output = "";
const selected = await promptForPlatforms({
defaults: [],
input: Readable.from(["2,5\n"]),
output: new Writable({
write(chunk, _encoding, callback) {
output += chunk.toString();
callback();
},
}),
});
expect(selected).toEqual(["opencode", "antigravity"]);
expect(output).toContain("Select platforms");
});
});