openclaw/src/cli/profile.test.ts
kumarabhirup 54ee12e759
Ironclaw rename: update CLI binary references, fix Next.js invocation, harden package resolution
Comprehensive update to complete the openclaw → ironclaw CLI rename across the
codebase, fix build/runtime issues, and add test coverage for infra modules.

CLI binary rename (openclaw → ironclaw):
- Update DEFAULT_CLI_NAME and all argv parsing to recognize "ironclaw" binary
- Extend package name sets (CORE_PACKAGE_NAMES, ALL_PACKAGE_NAMES) to include
  both "ironclaw" and "openclaw" for backward compatibility
- Update NPM registry URL to fetch from ironclaw package
- Update gateway lock detection, port listener classification, and launchd/systemd
  service scanning to recognize ironclaw-prefixed services and binaries
- Update daemon inspect markers and legacy detection for ironclaw
- Update voice-call extension core-bridge to resolve ironclaw package root
- Fix install instructions in embeddings error messages (npm i -g ironclaw@latest)

Web app / Next.js fixes:
- Replace fragile `npx next` invocations with direct `node next-bin` resolution
  to avoid broken pnpm virtual-store symlinks in global installs
- Add resolveNextBin() helper that resolves apps/web/node_modules/next directly

Infra hardening:
- Workspace templates: compute both source and dist fallback paths for template
  directory resolution (fixes templates not found in bundled builds)
- Control UI assets: recognize both "openclaw" and "ironclaw" package names
- Update-check, update-runner, update-cli: normalize ironclaw@ tag prefixes

New tests:
- Add openclaw-root.test.ts, ports-format.test.ts, update-global.test.ts
- Add workspace-templates.test.ts and control-ui-assets.test.ts coverage
- Add argv.test.ts coverage for ironclaw binary detection

Test fixes (28 failures → 0):
- Update all test assertions expecting "openclaw" CLI command output to "ironclaw"
- Fix version.test.ts package name from "openclaw" to "ironclaw"
- Fix camera/canvas temp path patterns in nodes-camera and program.nodes-media tests
- Fix pairing message, telegram bot, channels, daemon, onboard, gateway tool,
  status, and profile test expectations

Version: 2026.2.10-1.2 (published to npm as ironclaw@2026.2.10-1.2)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 12:19:49 -08:00

164 lines
5.4 KiB
TypeScript

import path from "node:path";
import { describe, expect, it } from "vitest";
import { formatCliCommand } from "./command-format.js";
import { applyCliProfileEnv, parseCliProfileArgs } from "./profile.js";
describe("parseCliProfileArgs", () => {
it("leaves gateway --dev for subcommands", () => {
const res = parseCliProfileArgs([
"node",
"ironclaw",
"gateway",
"--dev",
"--allow-unconfigured",
]);
if (!res.ok) {
throw new Error(res.error);
}
expect(res.profile).toBeNull();
expect(res.argv).toEqual(["node", "ironclaw", "gateway", "--dev", "--allow-unconfigured"]);
});
it("still accepts global --dev before subcommand", () => {
const res = parseCliProfileArgs(["node", "ironclaw", "--dev", "gateway"]);
if (!res.ok) {
throw new Error(res.error);
}
expect(res.profile).toBe("dev");
expect(res.argv).toEqual(["node", "ironclaw", "gateway"]);
});
it("parses --profile value and strips it", () => {
const res = parseCliProfileArgs(["node", "ironclaw", "--profile", "work", "status"]);
if (!res.ok) {
throw new Error(res.error);
}
expect(res.profile).toBe("work");
expect(res.argv).toEqual(["node", "ironclaw", "status"]);
});
it("rejects missing profile value", () => {
const res = parseCliProfileArgs(["node", "ironclaw", "--profile"]);
expect(res.ok).toBe(false);
});
it("rejects combining --dev with --profile (dev first)", () => {
const res = parseCliProfileArgs(["node", "ironclaw", "--dev", "--profile", "work", "status"]);
expect(res.ok).toBe(false);
});
it("rejects combining --dev with --profile (profile first)", () => {
const res = parseCliProfileArgs(["node", "ironclaw", "--profile", "work", "--dev", "status"]);
expect(res.ok).toBe(false);
});
});
describe("applyCliProfileEnv", () => {
it("fills env defaults for dev profile", () => {
const env: Record<string, string | undefined> = {};
applyCliProfileEnv({
profile: "dev",
env,
homedir: () => "/home/peter",
});
const expectedStateDir = path.join(path.resolve("/home/peter"), ".openclaw-dev");
expect(env.OPENCLAW_PROFILE).toBe("dev");
expect(env.OPENCLAW_STATE_DIR).toBe(expectedStateDir);
expect(env.OPENCLAW_CONFIG_PATH).toBe(path.join(expectedStateDir, "openclaw.json"));
expect(env.OPENCLAW_GATEWAY_PORT).toBe("19001");
});
it("does not override explicit env values", () => {
const env: Record<string, string | undefined> = {
OPENCLAW_STATE_DIR: "/custom",
OPENCLAW_GATEWAY_PORT: "19099",
};
applyCliProfileEnv({
profile: "dev",
env,
homedir: () => "/home/peter",
});
expect(env.OPENCLAW_STATE_DIR).toBe("/custom");
expect(env.OPENCLAW_GATEWAY_PORT).toBe("19099");
expect(env.OPENCLAW_CONFIG_PATH).toBe(path.join("/custom", "openclaw.json"));
});
it("uses OPENCLAW_HOME when deriving profile state dir", () => {
const env: Record<string, string | undefined> = {
OPENCLAW_HOME: "/srv/openclaw-home",
HOME: "/home/other",
};
applyCliProfileEnv({
profile: "work",
env,
homedir: () => "/home/fallback",
});
const resolvedHome = path.resolve("/srv/openclaw-home");
expect(env.OPENCLAW_STATE_DIR).toBe(path.join(resolvedHome, ".openclaw-work"));
expect(env.OPENCLAW_CONFIG_PATH).toBe(
path.join(resolvedHome, ".openclaw-work", "openclaw.json"),
);
});
});
describe("formatCliCommand", () => {
it("returns command unchanged when no profile is set", () => {
expect(formatCliCommand("ironclaw doctor --fix", {})).toBe("ironclaw doctor --fix");
});
it("returns command unchanged when profile is default", () => {
expect(formatCliCommand("ironclaw doctor --fix", { OPENCLAW_PROFILE: "default" })).toBe(
"ironclaw doctor --fix",
);
});
it("returns command unchanged when profile is Default (case-insensitive)", () => {
expect(formatCliCommand("ironclaw doctor --fix", { OPENCLAW_PROFILE: "Default" })).toBe(
"ironclaw doctor --fix",
);
});
it("returns command unchanged when profile is invalid", () => {
expect(formatCliCommand("ironclaw doctor --fix", { OPENCLAW_PROFILE: "bad profile" })).toBe(
"ironclaw doctor --fix",
);
});
it("returns command unchanged when --profile is already present", () => {
expect(
formatCliCommand("ironclaw --profile work doctor --fix", { OPENCLAW_PROFILE: "work" }),
).toBe("ironclaw --profile work doctor --fix");
});
it("returns command unchanged when --dev is already present", () => {
expect(formatCliCommand("ironclaw --dev doctor", { OPENCLAW_PROFILE: "dev" })).toBe(
"ironclaw --dev doctor",
);
});
it("inserts --profile flag when profile is set", () => {
expect(formatCliCommand("ironclaw doctor --fix", { OPENCLAW_PROFILE: "work" })).toBe(
"ironclaw --profile work doctor --fix",
);
});
it("trims whitespace from profile", () => {
expect(formatCliCommand("ironclaw doctor --fix", { OPENCLAW_PROFILE: " jbopenclaw " })).toBe(
"ironclaw --profile jbopenclaw doctor --fix",
);
});
it("handles command with no args after ironclaw", () => {
expect(formatCliCommand("ironclaw", { OPENCLAW_PROFILE: "test" })).toBe(
"ironclaw --profile test",
);
});
it("handles pnpm wrapper", () => {
expect(formatCliCommand("pnpm ironclaw doctor", { OPENCLAW_PROFILE: "work" })).toBe(
"pnpm ironclaw --profile work doctor",
);
});
});