Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
267 changes: 267 additions & 0 deletions src/lib/onboard-command.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

import { describe, expect, it, vi } from "vitest";

import {
parseOnboardArgs,
runDeprecatedOnboardAliasCommand,
runOnboardCommand,
} from "../../dist/lib/onboard-command";
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved

describe("onboard command", () => {
it("parses onboard flags", () => {
expect(
parseOnboardArgs(
["--non-interactive", "--resume", "--yes-i-accept-third-party-software"],
"--yes-i-accept-third-party-software",
"NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE",
{
env: {},
error: () => {},
exit: ((code: number) => {
throw new Error(String(code));
}) as never,
},
),
).toEqual({
nonInteractive: true,
resume: true,
recreateSandbox: false,
fromDockerfile: null,
acceptThirdPartySoftware: true,
agent: null,
dangerouslySkipPermissions: false,
});
});

it("accepts the env-based third-party notice acknowledgement", () => {
expect(
parseOnboardArgs(
[],
"--yes-i-accept-third-party-software",
"NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE",
{
env: { NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE: "1" },
error: () => {},
exit: ((code: number) => {
throw new Error(String(code));
}) as never,
},
),
).toEqual({
nonInteractive: false,
resume: false,
recreateSandbox: false,
fromDockerfile: null,
acceptThirdPartySoftware: true,
agent: null,
dangerouslySkipPermissions: false,
});
});

it("runs onboard with parsed options", async () => {
const runOnboard = vi.fn(async () => {});
await runOnboardCommand({
args: ["--resume"],
noticeAcceptFlag: "--yes-i-accept-third-party-software",
noticeAcceptEnv: "NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE",
env: {},
runOnboard,
error: () => {},
exit: ((code: number) => {
throw new Error(String(code));
}) as never,
});
expect(runOnboard).toHaveBeenCalledWith({
nonInteractive: false,
resume: true,
recreateSandbox: false,
fromDockerfile: null,
acceptThirdPartySoftware: false,
agent: null,
dangerouslySkipPermissions: false,
});
});

it("prints usage and skips onboarding for --help", async () => {
const runOnboard = vi.fn(async () => {});
const lines: string[] = [];
await runOnboardCommand({
args: ["--help"],
noticeAcceptFlag: "--yes-i-accept-third-party-software",
noticeAcceptEnv: "NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE",
env: {},
runOnboard,
log: (message = "") => lines.push(message),
error: () => {},
exit: ((code: number) => {
throw new Error(String(code));
}) as never,
});
expect(runOnboard).not.toHaveBeenCalled();
expect(lines.join("\n")).toContain("Usage: nemoclaw onboard");
expect(lines.join("\n")).toContain("--from <Dockerfile>");
expect(lines.join("\n")).toContain("--agent <name>");
expect(lines.join("\n")).toContain("--dangerously-skip-permissions");
});

it("parses --from <Dockerfile>", () => {
expect(
parseOnboardArgs(
["--resume", "--from", "/tmp/Custom.Dockerfile"],
"--yes-i-accept-third-party-software",
"NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE",
{
env: {},
error: () => {},
exit: ((code: number) => {
throw new Error(String(code));
}) as never,
},
),
).toEqual({
nonInteractive: false,
resume: true,
recreateSandbox: false,
fromDockerfile: "/tmp/Custom.Dockerfile",
acceptThirdPartySoftware: false,
agent: null,
dangerouslySkipPermissions: false,
});
});

it("exits when --from is missing its Dockerfile path", () => {
expect(() =>
parseOnboardArgs(
["--from"],
"--yes-i-accept-third-party-software",
"NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE",
{
env: {},
error: () => {},
exit: ((code: number) => {
throw new Error(`exit:${code}`);
}) as never,
},
),
).toThrow("exit:1");
});

it("exits with usage on unknown args", () => {
const errors: string[] = [];
expect(() =>
parseOnboardArgs(
["--bad-flag"],
"--yes-i-accept-third-party-software",
"NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE",
{
env: {},
error: (message = "") => errors.push(message),
exit: ((code: number) => {
throw new Error(`exit:${code}`);
}) as never,
},
),
).toThrow("exit:1");
expect(errors.join("\n")).toContain("Unknown onboard option(s): --bad-flag");
expect(errors.join("\n")).toContain("Usage: nemoclaw onboard");
});

it("parses --agent and --dangerously-skip-permissions", () => {
expect(
parseOnboardArgs(
["--agent", "openclaw", "--dangerously-skip-permissions"],
"--yes-i-accept-third-party-software",
"NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE",
{
env: {},
listAgents: () => ["openclaw", "hermes"],
error: () => {},
exit: ((code: number) => {
throw new Error(String(code));
}) as never,
},
),
).toEqual({
nonInteractive: false,
resume: false,
recreateSandbox: false,
fromDockerfile: null,
acceptThirdPartySoftware: false,
agent: "openclaw",
dangerouslySkipPermissions: true,
});
});

it("rejects unknown --agent values", () => {
const errors: string[] = [];
expect(() =>
parseOnboardArgs(
["--agent", "bogus"],
"--yes-i-accept-third-party-software",
"NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE",
{
env: {},
listAgents: () => ["openclaw", "hermes"],
error: (message = "") => errors.push(message),
exit: ((code: number) => {
throw new Error(`exit:${code}`);
}) as never,
},
),
).toThrow("exit:1");
expect(errors.join("\n")).toContain("Unknown agent 'bogus'");
});

it("prints the setup-spark deprecation text before delegating", async () => {
const lines: string[] = [];
const runOnboard = vi.fn(async () => {});
await runDeprecatedOnboardAliasCommand({
kind: "setup-spark",
args: [],
noticeAcceptFlag: "--yes-i-accept-third-party-software",
noticeAcceptEnv: "NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE",
env: {},
runOnboard,
log: (message = "") => lines.push(message),
error: () => {},
exit: ((code: number) => {
throw new Error(String(code));
}) as never,
});
expect(lines.join("\n")).toContain("setup-spark` is deprecated");
expect(lines.join("\n")).toContain("Use `nemoclaw onboard` instead");
expect(runOnboard).toHaveBeenCalledTimes(1);
expect(runOnboard).toHaveBeenCalledWith({
nonInteractive: false,
resume: false,
recreateSandbox: false,
fromDockerfile: null,
acceptThirdPartySoftware: false,
agent: null,
dangerouslySkipPermissions: false,
});
});

it("prints the setup deprecation text before delegating", async () => {
const lines: string[] = [];
const runOnboard = vi.fn(async () => {});
await runDeprecatedOnboardAliasCommand({
kind: "setup",
args: [],
noticeAcceptFlag: "--yes-i-accept-third-party-software",
noticeAcceptEnv: "NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE",
env: {},
runOnboard,
log: (message = "") => lines.push(message),
error: () => {},
exit: ((code: number) => {
throw new Error(String(code));
}) as never,
});
expect(lines.join("\n")).toContain("`nemoclaw setup` is deprecated");
expect(lines.join("\n")).toContain("Use `nemoclaw onboard` instead");
expect(runOnboard).toHaveBeenCalledTimes(1);
});
});
Loading
Loading