refactor: dedupe test helpers and script warning filter

This commit is contained in:
Peter Steinberger
2026-04-08 14:12:50 +01:00
parent 6276530dc2
commit 3dd19a1705
5 changed files with 115 additions and 190 deletions

View File

@@ -0,0 +1,32 @@
const warningFilterKey = Symbol.for("openclaw.warning-filter");
export function installProcessWarningFilter() {
if (globalThis[warningFilterKey]?.installed) {
return;
}
const originalEmitWarning = process.emitWarning.bind(process);
process.emitWarning = (...args) => {
const [warningArg, secondArg, thirdArg] = args;
const warning =
warningArg instanceof Error
? {
name: warningArg.name,
message: warningArg.message,
code: warningArg.code,
}
: {
name: typeof secondArg === "string" ? secondArg : secondArg?.type,
message: typeof warningArg === "string" ? warningArg : undefined,
code: typeof thirdArg === "string" ? thirdArg : secondArg?.code,
};
if (warning.code === "DEP0040" && warning.message?.includes("punycode")) {
return;
}
return Reflect.apply(originalEmitWarning, process, args);
};
globalThis[warningFilterKey] = { installed: true };
}

View File

@@ -2,39 +2,7 @@ import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
const warningFilterKey = Symbol.for("openclaw.warning-filter");
function installProcessWarningFilter() {
if (globalThis[warningFilterKey]?.installed) {
return;
}
const originalEmitWarning = process.emitWarning.bind(process);
process.emitWarning = (...args) => {
const [warningArg, secondArg, thirdArg] = args;
const warning =
warningArg instanceof Error
? {
name: warningArg.name,
message: warningArg.message,
code: warningArg.code,
}
: {
name: typeof secondArg === "string" ? secondArg : secondArg?.type,
message: typeof warningArg === "string" ? warningArg : undefined,
code: typeof thirdArg === "string" ? thirdArg : secondArg?.code,
};
if (warning.code === "DEP0040" && warning.message?.includes("punycode")) {
return;
}
return Reflect.apply(originalEmitWarning, process, args);
};
globalThis[warningFilterKey] = { installed: true };
}
import { installProcessWarningFilter } from "./process-warning-filter.mjs";
installProcessWarningFilter();

View File

@@ -3,41 +3,9 @@ import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { installProcessWarningFilter } from "./process-warning-filter.mjs";
import { stageBundledPluginRuntime } from "./stage-bundled-plugin-runtime.mjs";
const warningFilterKey = Symbol.for("openclaw.warning-filter");
function installProcessWarningFilter() {
if (globalThis[warningFilterKey]?.installed) {
return;
}
const originalEmitWarning = process.emitWarning.bind(process);
process.emitWarning = (...args) => {
const [warningArg, secondArg, thirdArg] = args;
const warning =
warningArg instanceof Error
? {
name: warningArg.name,
message: warningArg.message,
code: warningArg.code,
}
: {
name: typeof secondArg === "string" ? secondArg : secondArg?.type,
message: typeof warningArg === "string" ? warningArg : undefined,
code: typeof thirdArg === "string" ? thirdArg : secondArg?.code,
};
if (warning.code === "DEP0040" && warning.message?.includes("punycode")) {
return;
}
return Reflect.apply(originalEmitWarning, process, args);
};
globalThis[warningFilterKey] = { installed: true };
}
installProcessWarningFilter();
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");

View File

@@ -60,6 +60,38 @@ function createBackendEntry(params: {
};
}
function createClaudeCliOverrideConfig(config: CliBackendConfig): OpenClawConfig {
return {
agents: {
defaults: {
cliBackends: {
"claude-cli": config,
},
},
},
} satisfies OpenClawConfig;
}
const NORMALIZED_CLAUDE_FALLBACK_ARGS = [
"-p",
"--output-format",
"stream-json",
"--setting-sources",
"user",
"--permission-mode",
"bypassPermissions",
];
const NORMALIZED_CLAUDE_FALLBACK_RESUME_ARGS = [
"-p",
"--resume",
"{sessionId}",
"--setting-sources",
"user",
"--permission-mode",
"bypassPermissions",
];
beforeAll(async () => {
vi.doUnmock("../plugins/setup-registry.js");
vi.doUnmock("../plugins/cli-backends.runtime.js");
@@ -449,79 +481,31 @@ describe("resolveCliBackendConfig claude-cli defaults", () => {
});
it("falls back to user-only setting sources when a custom override leaves the flag without a value", () => {
const cfg = {
agents: {
defaults: {
cliBackends: {
"claude-cli": {
command: "claude",
args: ["-p", "--setting-sources", "--output-format", "stream-json"],
resumeArgs: ["-p", "--setting-sources", "--resume", "{sessionId}"],
},
},
},
},
} satisfies OpenClawConfig;
const cfg = createClaudeCliOverrideConfig({
command: "claude",
args: ["-p", "--setting-sources", "--output-format", "stream-json"],
resumeArgs: ["-p", "--setting-sources", "--resume", "{sessionId}"],
});
const resolved = resolveCliBackendConfig("claude-cli", cfg);
expect(resolved).not.toBeNull();
expect(resolved?.config.args).toEqual([
"-p",
"--output-format",
"stream-json",
"--setting-sources",
"user",
"--permission-mode",
"bypassPermissions",
]);
expect(resolved?.config.resumeArgs).toEqual([
"-p",
"--resume",
"{sessionId}",
"--setting-sources",
"user",
"--permission-mode",
"bypassPermissions",
]);
expect(resolved?.config.args).toEqual(NORMALIZED_CLAUDE_FALLBACK_ARGS);
expect(resolved?.config.resumeArgs).toEqual(NORMALIZED_CLAUDE_FALLBACK_RESUME_ARGS);
});
it("falls back to bypassPermissions when a custom override leaves permission-mode without a value", () => {
const cfg = {
agents: {
defaults: {
cliBackends: {
"claude-cli": {
command: "claude",
args: ["-p", "--permission-mode", "--output-format", "stream-json"],
resumeArgs: ["-p", "--permission-mode", "--resume", "{sessionId}"],
},
},
},
},
} satisfies OpenClawConfig;
const cfg = createClaudeCliOverrideConfig({
command: "claude",
args: ["-p", "--permission-mode", "--output-format", "stream-json"],
resumeArgs: ["-p", "--permission-mode", "--resume", "{sessionId}"],
});
const resolved = resolveCliBackendConfig("claude-cli", cfg);
expect(resolved).not.toBeNull();
expect(resolved?.config.args).toEqual([
"-p",
"--output-format",
"stream-json",
"--setting-sources",
"user",
"--permission-mode",
"bypassPermissions",
]);
expect(resolved?.config.resumeArgs).toEqual([
"-p",
"--resume",
"{sessionId}",
"--setting-sources",
"user",
"--permission-mode",
"bypassPermissions",
]);
expect(resolved?.config.args).toEqual(NORMALIZED_CLAUDE_FALLBACK_ARGS);
expect(resolved?.config.resumeArgs).toEqual(NORMALIZED_CLAUDE_FALLBACK_RESUME_ARGS);
});
it("injects bypassPermissions when custom args omit any permission flag", () => {

View File

@@ -60,6 +60,36 @@ function createOptions(
} as unknown as GatewayRequestHandlerOptions;
}
function mockPairedOperatorDevice(): void {
getPairedDeviceMock.mockResolvedValue({
deviceId: "device-1",
role: "operator",
roles: ["operator"],
scopes: ["operator.pairing"],
tokens: {
operator: {
token: "old-token",
role: "operator",
scopes: ["operator.pairing"],
createdAtMs: 123,
},
},
});
}
function mockRotateOperatorTokenSuccess(): void {
rotateDeviceTokenMock.mockResolvedValue({
ok: true,
entry: {
token: "new-token",
role: "operator",
scopes: ["operator.pairing"],
createdAtMs: 456,
rotatedAtMs: 789,
},
});
}
describe("deviceHandlers", () => {
beforeEach(() => {
vi.clearAllMocks();
@@ -197,30 +227,8 @@ describe("deviceHandlers", () => {
});
it("disconnects active clients after rotating a device token", async () => {
getPairedDeviceMock.mockResolvedValue({
deviceId: "device-1",
role: "operator",
roles: ["operator"],
scopes: ["operator.pairing"],
tokens: {
operator: {
token: "old-token",
role: "operator",
scopes: ["operator.pairing"],
createdAtMs: 123,
},
},
});
rotateDeviceTokenMock.mockResolvedValue({
ok: true,
entry: {
token: "new-token",
role: "operator",
scopes: ["operator.pairing"],
createdAtMs: 456,
rotatedAtMs: 789,
},
});
mockPairedOperatorDevice();
mockRotateOperatorTokenSuccess();
const opts = createOptions(
"device.token.rotate",
{
@@ -262,30 +270,8 @@ describe("deviceHandlers", () => {
});
it("treats normalized device ids as self-owned for token rotation", async () => {
getPairedDeviceMock.mockResolvedValue({
deviceId: "device-1",
role: "operator",
roles: ["operator"],
scopes: ["operator.pairing"],
tokens: {
operator: {
token: "old-token",
role: "operator",
scopes: ["operator.pairing"],
createdAtMs: 123,
},
},
});
rotateDeviceTokenMock.mockResolvedValue({
ok: true,
entry: {
token: "new-token",
role: "operator",
scopes: ["operator.pairing"],
createdAtMs: 456,
rotatedAtMs: 789,
},
});
mockPairedOperatorDevice();
mockRotateOperatorTokenSuccess();
const opts = createOptions(
"device.token.rotate",
{
@@ -317,20 +303,7 @@ describe("deviceHandlers", () => {
});
it("rejects rotating a token for a role that was never approved", async () => {
getPairedDeviceMock.mockResolvedValue({
deviceId: "device-1",
role: "operator",
roles: ["operator"],
scopes: ["operator.pairing"],
tokens: {
operator: {
token: "old-token",
role: "operator",
scopes: ["operator.pairing"],
createdAtMs: 123,
},
},
});
mockPairedOperatorDevice();
const opts = createOptions(
"device.token.rotate",
{