import { describe, expect, it, vi } from "vitest"; import { createCliPathTextInput, createDelegatedSetupWizardStatusResolvers, createDelegatedTextInputShouldPrompt, createDetectedBinaryStatus, } from "./setup-wizard-binary.js"; import type { ChannelSetupWizard } from "./setup-wizard.js"; describe("createDetectedBinaryStatus", () => { it("builds status lines, hint, and score from binary detection", async () => { const resolveConfigured = vi.fn(() => true); const resolveBinaryPath = vi.fn(() => "/usr/local/bin/signal-cli"); const status = createDetectedBinaryStatus({ channelLabel: "Signal", binaryLabel: "signal-cli", configuredLabel: "configured", unconfiguredLabel: "needs setup", configuredHint: "signal-cli found", unconfiguredHint: "signal-cli missing", configuredScore: 1, unconfiguredScore: 0, resolveConfigured, resolveBinaryPath, detectBinary: vi.fn(async () => true), }); expect(await status.resolveConfigured({ cfg: {}, accountId: "work" })).toBe(true); expect(resolveConfigured).toHaveBeenCalledWith({ cfg: {}, accountId: "work" }); expect(await status.resolveStatusLines?.({ cfg: {}, configured: true })).toEqual([ "Signal: configured", "signal-cli: found (/usr/local/bin/signal-cli)", ]); expect(resolveBinaryPath).toHaveBeenCalledWith({ cfg: {}, accountId: undefined }); expect(await status.resolveSelectionHint?.({ cfg: {}, configured: true })).toBe( "signal-cli found", ); expect(await status.resolveQuickstartScore?.({ cfg: {}, configured: true })).toBe(1); }); it("passes accountId into binary path resolution", async () => { const resolveBinaryPath = vi.fn(({ accountId }: { accountId?: string }) => accountId === "work" ? "/opt/work-signal-cli" : "/usr/local/bin/signal-cli", ); const status = createDetectedBinaryStatus({ channelLabel: "Signal", binaryLabel: "signal-cli", configuredLabel: "configured", unconfiguredLabel: "needs setup", configuredHint: "signal-cli found", unconfiguredHint: "signal-cli missing", configuredScore: 1, unconfiguredScore: 0, resolveConfigured: () => true, resolveBinaryPath, detectBinary: vi.fn(async () => false), }); expect( await status.resolveStatusLines?.({ cfg: {}, accountId: "work", configured: false }), ).toEqual(["Signal: needs setup", "signal-cli: missing (/opt/work-signal-cli)"]); expect(resolveBinaryPath).toHaveBeenCalledWith({ cfg: {}, accountId: "work" }); }); }); describe("createCliPathTextInput", () => { it("reuses the same path resolver for current and initial values", async () => { const textInput = createCliPathTextInput({ inputKey: "cliPath", message: "CLI path", resolvePath: () => "imsg", shouldPrompt: async () => false, helpTitle: "iMessage", helpLines: ["help"], }); expect( await textInput.currentValue?.({ cfg: {}, accountId: "default", credentialValues: {} }), ).toBe("imsg"); expect( await textInput.initialValue?.({ cfg: {}, accountId: "default", credentialValues: {} }), ).toBe("imsg"); expect(textInput.helpTitle).toBe("iMessage"); expect(textInput.helpLines).toEqual(["help"]); }); }); describe("createDelegatedSetupWizardStatusResolvers", () => { it("forwards optional status resolvers to the loaded wizard", async () => { const loadWizard = vi.fn( async (): Promise => ({ channel: "demo", status: { configuredLabel: "configured", unconfiguredLabel: "needs setup", resolveConfigured: () => true, resolveStatusLines: async () => ["line"], resolveSelectionHint: async () => "hint", resolveQuickstartScore: async () => 7, }, credentials: [], }), ); const status = createDelegatedSetupWizardStatusResolvers(loadWizard); expect(await status.resolveStatusLines?.({ cfg: {}, configured: true })).toEqual(["line"]); expect(await status.resolveSelectionHint?.({ cfg: {}, configured: true })).toBe("hint"); expect(await status.resolveQuickstartScore?.({ cfg: {}, configured: true })).toBe(7); }); }); describe("createDelegatedTextInputShouldPrompt", () => { it("forwards shouldPrompt for the requested input key", async () => { const loadWizard = vi.fn( async (): Promise => ({ channel: "demo", status: { configuredLabel: "configured", unconfiguredLabel: "needs setup", resolveConfigured: () => true, }, credentials: [], textInputs: [ { inputKey: "cliPath", message: "CLI path", shouldPrompt: async ({ currentValue }) => currentValue !== "imsg", }, ], }), ); const shouldPrompt = createDelegatedTextInputShouldPrompt({ loadWizard, inputKey: "cliPath", }); expect( await shouldPrompt({ cfg: {}, accountId: "default", credentialValues: {}, currentValue: "imsg", }), ).toBe(false); expect( await shouldPrompt({ cfg: {}, accountId: "default", credentialValues: {}, currentValue: "other", }), ).toBe(true); }); });