mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
test: remove obsolete QR dashboard integration suite (#123819)
This commit is contained in:
committed by
GitHub
parent
dc8facb060
commit
ae385f3c6b
@@ -1,218 +0,0 @@
|
||||
// QR dashboard integration tests cover QR dashboard command wiring and rendered output.
|
||||
import { Command } from "commander";
|
||||
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { captureEnv } from "../test-utils/env.js";
|
||||
import { createCliRuntimeCapture } from "./test-runtime-capture.js";
|
||||
|
||||
const loadConfigMock = vi.hoisted(() => vi.fn());
|
||||
const readConfigFileSnapshotMock = vi.hoisted(() => vi.fn());
|
||||
const resolveGatewayPortMock = vi.hoisted(() => vi.fn(() => 18789));
|
||||
const copyToClipboardMock = vi.hoisted(() => vi.fn(async () => false));
|
||||
const ensureGatewayReadyForOperationMock = vi.hoisted(() => vi.fn());
|
||||
const {
|
||||
runtimeLogs,
|
||||
runtimeErrors,
|
||||
defaultRuntime: runtime,
|
||||
resetRuntimeCapture,
|
||||
} = createCliRuntimeCapture();
|
||||
const runtimeExit = runtime.exit;
|
||||
|
||||
vi.mock("../config/config.js", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("../config/config.js")>();
|
||||
return {
|
||||
...actual,
|
||||
getRuntimeConfig: loadConfigMock,
|
||||
loadConfig: loadConfigMock,
|
||||
readConfigFileSnapshot: readConfigFileSnapshotMock,
|
||||
resolveGatewayPort: resolveGatewayPortMock,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../infra/clipboard.js", () => ({
|
||||
copyToClipboard: copyToClipboardMock,
|
||||
}));
|
||||
|
||||
vi.mock("../commands/gateway-readiness.js", () => ({
|
||||
ensureGatewayReadyForOperation: ensureGatewayReadyForOperationMock,
|
||||
}));
|
||||
|
||||
vi.mock("../commands/control-ui-handoff.js", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("../commands/control-ui-handoff.js")>()),
|
||||
waitForControlUiDocument: vi.fn(async () => ({ ready: true })),
|
||||
}));
|
||||
|
||||
vi.mock("../infra/device-bootstrap.js", () => ({
|
||||
issueDeviceBootstrapToken: vi.fn(async () => ({
|
||||
token: "bootstrap-123",
|
||||
expiresAtMs: 123,
|
||||
})),
|
||||
issueDevicePairSetupBootstrapToken: vi.fn(async () => ({
|
||||
token: "bootstrap-123",
|
||||
expiresAtMs: 123,
|
||||
setupId: "setup-123",
|
||||
})),
|
||||
}));
|
||||
|
||||
vi.mock("../runtime.js", () => ({
|
||||
defaultRuntime: runtime,
|
||||
}));
|
||||
|
||||
const { dashboardCommand } = await import("../commands/dashboard.js");
|
||||
const { registerQrCli } = await import("./qr-cli.js");
|
||||
|
||||
function createGatewayTokenRefFixture() {
|
||||
return {
|
||||
secrets: {
|
||||
providers: {
|
||||
default: {
|
||||
source: "env",
|
||||
},
|
||||
},
|
||||
defaults: {
|
||||
env: "default",
|
||||
},
|
||||
},
|
||||
gateway: {
|
||||
bind: "custom",
|
||||
customBindHost: "127.0.0.1",
|
||||
port: 18789,
|
||||
auth: {
|
||||
mode: "token",
|
||||
token: {
|
||||
source: "env",
|
||||
provider: "default",
|
||||
id: "SHARED_GATEWAY_TOKEN",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function decodeSetupCode(setupCode: string): {
|
||||
url?: string;
|
||||
bootstrapToken?: string;
|
||||
} {
|
||||
const padded = setupCode.replace(/-/g, "+").replace(/_/g, "/");
|
||||
const padLength = (4 - (padded.length % 4)) % 4;
|
||||
const normalized = padded + "=".repeat(padLength);
|
||||
const json = Buffer.from(normalized, "base64").toString("utf8");
|
||||
return JSON.parse(json) as {
|
||||
url?: string;
|
||||
bootstrapToken?: string;
|
||||
};
|
||||
}
|
||||
|
||||
function findSetupCodeLogLine(lines: string[]): string | undefined {
|
||||
for (const line of lines) {
|
||||
try {
|
||||
const payload = decodeSetupCode(line);
|
||||
if (payload.url || payload.bootstrapToken) {
|
||||
return line;
|
||||
}
|
||||
} catch {
|
||||
// Ignore non-setup-code log lines.
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async function runCli(args: string[]): Promise<void> {
|
||||
const program = new Command();
|
||||
registerQrCli(program);
|
||||
await program.parseAsync(args, { from: "user" });
|
||||
}
|
||||
|
||||
describe("cli integration: qr + dashboard token SecretRef", () => {
|
||||
let envSnapshot: ReturnType<typeof captureEnv>;
|
||||
|
||||
beforeAll(() => {
|
||||
envSnapshot = captureEnv([
|
||||
"SHARED_GATEWAY_TOKEN",
|
||||
"OPENCLAW_GATEWAY_TOKEN",
|
||||
"OPENCLAW_GATEWAY_PASSWORD",
|
||||
]);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
resetRuntimeCapture();
|
||||
vi.clearAllMocks();
|
||||
ensureGatewayReadyForOperationMock.mockResolvedValue({
|
||||
ready: true,
|
||||
status: {},
|
||||
recovered: false,
|
||||
});
|
||||
runtimeExit.mockImplementation(() => {});
|
||||
delete process.env.OPENCLAW_GATEWAY_TOKEN;
|
||||
delete process.env.OPENCLAW_GATEWAY_PASSWORD;
|
||||
delete process.env.SHARED_GATEWAY_TOKEN;
|
||||
});
|
||||
|
||||
it("uses the same resolved token SecretRef for qr auth validation and dashboard commands", async () => {
|
||||
const fixture = createGatewayTokenRefFixture();
|
||||
process.env.SHARED_GATEWAY_TOKEN = "shared-token-123";
|
||||
loadConfigMock.mockReturnValue(fixture);
|
||||
readConfigFileSnapshotMock.mockResolvedValue({
|
||||
path: "/tmp/openclaw.json",
|
||||
exists: true,
|
||||
valid: true,
|
||||
issues: [],
|
||||
config: fixture,
|
||||
});
|
||||
|
||||
await runCli(["qr", "--setup-code-only"]);
|
||||
const setupCode = findSetupCodeLogLine(runtimeLogs);
|
||||
if (!setupCode) {
|
||||
throw new Error("expected QR setup code log line");
|
||||
}
|
||||
const payload = decodeSetupCode(setupCode);
|
||||
expect(payload.url).toBe("ws://127.0.0.1:18789");
|
||||
expect(payload.bootstrapToken).toBe("bootstrap-123");
|
||||
expect(runtimeErrors).toStrictEqual([]);
|
||||
|
||||
runtimeLogs.length = 0;
|
||||
runtimeErrors.length = 0;
|
||||
await dashboardCommand(runtime, { noOpen: true });
|
||||
const joined = runtimeLogs.join("\n");
|
||||
expect(joined).toContain("Dashboard URL: http://127.0.0.1:18789/");
|
||||
expect(joined).not.toContain("#token=");
|
||||
expect(joined).toContain("One-time pairing URL not delivered");
|
||||
expect(joined).toContain("openclaw dashboard --json");
|
||||
expect(joined).toContain("browserUrl");
|
||||
expect(joined).not.toContain("Token auto-auth is disabled");
|
||||
expect(joined).not.toContain("Token auto-auth unavailable");
|
||||
expect(runtimeErrors).toStrictEqual([]);
|
||||
});
|
||||
|
||||
it("fails qr but keeps dashboard actionable when the shared token SecretRef is unresolved", async () => {
|
||||
const fixture = createGatewayTokenRefFixture();
|
||||
loadConfigMock.mockReturnValue(fixture);
|
||||
readConfigFileSnapshotMock.mockResolvedValue({
|
||||
path: "/tmp/openclaw.json",
|
||||
exists: true,
|
||||
valid: true,
|
||||
issues: [],
|
||||
config: fixture,
|
||||
});
|
||||
|
||||
await runCli(["qr", "--setup-code-only"]);
|
||||
expect(runtime.exit).toHaveBeenCalledWith(1);
|
||||
expect(runtimeErrors.join("\n")).toMatch(/SHARED_GATEWAY_TOKEN/);
|
||||
|
||||
runtimeLogs.length = 0;
|
||||
runtimeErrors.length = 0;
|
||||
await dashboardCommand(runtime, { noOpen: true });
|
||||
const joined = runtimeLogs.join("\n");
|
||||
expect(joined).toContain("Dashboard URL: http://127.0.0.1:18789/");
|
||||
expect(joined).not.toContain("#token=");
|
||||
expect(joined).toContain("One-time pairing URL not delivered");
|
||||
expect(joined).toContain("openclaw dashboard --json");
|
||||
expect(joined).toContain("browserUrl");
|
||||
expect(joined).not.toContain("Token auto-auth unavailable");
|
||||
expect(joined).not.toContain("Set OPENCLAW_GATEWAY_TOKEN");
|
||||
expect(runtimeErrors).toStrictEqual([]);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
envSnapshot.restore();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user