FN-5812: add onboard autolaunch backcompat guard coverage
Protect onboarding autolaunch behavior so legacy projects and agent-run commands are not blocked. - add end-to-end CLI test coverage for onboarding autolaunch backcompat guard behavior - document the onboarding autolaunch compatibility behavior in the CLI reference - add a patch changeset for @runfusion/fusion release tracking Files changed: .changeset/fn-5812-onboard-backcompat-guard.md | 5 + docs/cli-reference.md | 6 + packages/cli/src/commands/__tests__/onboard-autolaunch-backcompat-e2e.test.ts | 161 +++++++++++++++++++++ 3 files changed, 172 insertions(+) Fusion-Task-Id: FN-5812 Fusion-Task-Lineage: d735ef0e-1abc-4c22-bd11-07c2de69ace1
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { maybeAutoLaunchOnboarding } from "../onboard-autolaunch.js";
|
||||
|
||||
describe("maybeAutoLaunchOnboarding backward-compat e2e guard", () => {
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("does not prompt onboarded interactive users with central and project DB present", async () => {
|
||||
const runOnboard = vi.fn();
|
||||
const pathExists = vi.fn((path: string) =>
|
||||
path === "/virtual/central.db" || path.endsWith("/.fusion/fusion.db"),
|
||||
);
|
||||
|
||||
await expect(
|
||||
maybeAutoLaunchOnboarding({
|
||||
command: "task",
|
||||
args: ["task", "list"],
|
||||
centralDbPath: "/virtual/central.db",
|
||||
cwd: "/repo/demo",
|
||||
isTTY: true,
|
||||
pathExists,
|
||||
runOnboard,
|
||||
}),
|
||||
).resolves.toBeUndefined();
|
||||
|
||||
expect(runOnboard).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("never blocks agent-run non-TTY task commands when nothing is initialized", async () => {
|
||||
const runOnboard = vi.fn();
|
||||
|
||||
await expect(
|
||||
maybeAutoLaunchOnboarding({
|
||||
command: "task",
|
||||
args: ["task", "list"],
|
||||
centralDbPath: "/virtual/central.db",
|
||||
isTTY: false,
|
||||
pathExists: () => false,
|
||||
runOnboard,
|
||||
}),
|
||||
).resolves.toBeUndefined();
|
||||
|
||||
expect(runOnboard).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("skips serve and daemon commands even with missing DB", async () => {
|
||||
for (const command of ["serve", "daemon"]) {
|
||||
const runOnboard = vi.fn();
|
||||
|
||||
await expect(
|
||||
maybeAutoLaunchOnboarding({
|
||||
command,
|
||||
args: [command],
|
||||
centralDbPath: "/virtual/central.db",
|
||||
isTTY: true,
|
||||
pathExists: () => false,
|
||||
runOnboard,
|
||||
}),
|
||||
).resolves.toBeUndefined();
|
||||
|
||||
expect(runOnboard).not.toHaveBeenCalled();
|
||||
}
|
||||
});
|
||||
|
||||
it("honors --skip-onboarding end-to-end", async () => {
|
||||
const runOnboard = vi.fn();
|
||||
|
||||
await expect(
|
||||
maybeAutoLaunchOnboarding({
|
||||
command: "task",
|
||||
args: ["task", "list", "--skip-onboarding"],
|
||||
centralDbPath: "/virtual/central.db",
|
||||
isTTY: true,
|
||||
pathExists: () => false,
|
||||
runOnboard,
|
||||
}),
|
||||
).resolves.toBeUndefined();
|
||||
|
||||
expect(runOnboard).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("honors FUSION_SKIP_ONBOARDING end-to-end", async () => {
|
||||
const runOnboard = vi.fn();
|
||||
|
||||
await expect(
|
||||
maybeAutoLaunchOnboarding({
|
||||
command: "task",
|
||||
args: ["task", "list"],
|
||||
centralDbPath: "/virtual/central.db",
|
||||
isTTY: true,
|
||||
env: { FUSION_SKIP_ONBOARDING: "true" },
|
||||
pathExists: () => false,
|
||||
runOnboard,
|
||||
}),
|
||||
).resolves.toBeUndefined();
|
||||
|
||||
expect(runOnboard).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("isolates runOnboard failures as non-fatal with one diagnostic", async () => {
|
||||
const runOnboard = vi.fn().mockRejectedValue(new Error("boom"));
|
||||
const errorSpy = vi.spyOn(console, "error").mockImplementation(() => undefined);
|
||||
|
||||
await expect(
|
||||
maybeAutoLaunchOnboarding({
|
||||
command: "task",
|
||||
args: ["task", "list"],
|
||||
centralDbPath: "/virtual/central.db",
|
||||
isTTY: true,
|
||||
pathExists: () => false,
|
||||
runOnboard,
|
||||
}),
|
||||
).resolves.toBeUndefined();
|
||||
|
||||
expect(errorSpy).toHaveBeenCalledTimes(1);
|
||||
expect(errorSpy).toHaveBeenCalledWith(
|
||||
expect.stringContaining("[onboard-autolaunch] non-fatal onboard launch failure: boom"),
|
||||
);
|
||||
});
|
||||
|
||||
it("launches onboarding once for legitimate first-run interactive commands", async () => {
|
||||
const runOnboard = vi.fn();
|
||||
|
||||
await expect(
|
||||
maybeAutoLaunchOnboarding({
|
||||
command: "task",
|
||||
args: ["task", "list"],
|
||||
centralDbPath: "/virtual/central.db",
|
||||
isTTY: true,
|
||||
pathExists: () => false,
|
||||
runOnboard,
|
||||
}),
|
||||
).resolves.toBeUndefined();
|
||||
|
||||
expect(runOnboard).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("derives projectInitialized from cwd/pathExists seam without real filesystem", async () => {
|
||||
const runOnboard = vi.fn();
|
||||
const pathExists = vi.fn((path: string) =>
|
||||
path === "/virtual/central.db" || path === "/workspace/demo/.fusion/fusion.db",
|
||||
);
|
||||
|
||||
await expect(
|
||||
maybeAutoLaunchOnboarding({
|
||||
command: "task",
|
||||
args: ["task", "list"],
|
||||
centralDbPath: "/virtual/central.db",
|
||||
cwd: "/workspace/demo",
|
||||
isTTY: true,
|
||||
pathExists,
|
||||
runOnboard,
|
||||
}),
|
||||
).resolves.toBeUndefined();
|
||||
|
||||
expect(pathExists).toHaveBeenCalledWith("/workspace/demo/.fusion/fusion.db");
|
||||
expect(runOnboard).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user