fix(e2e): preserve null rpc results · openclaw/openclaw@7d5d625
vincentkoc
·
2026-06-02
·
via Recent Commits to openclaw:main
File tree
lib/bundled-plugin-install-uninstall
| Original file line number | Diff line number | Diff line change |
|---|
@@ -404,11 +404,27 @@ function findBalancedJsonObjectEnd(text, startIndex) {
|
404 | 404 | return -1; |
405 | 405 | } |
406 | 406 | |
407 | | -function unwrapRpcPayload(raw) { |
| 407 | +function hasOwnPayloadField(raw, field) { |
| 408 | +return ( |
| 409 | +((typeof raw === "object" && raw !== null) || typeof raw === "function") && |
| 410 | +Object.hasOwn(raw, field) |
| 411 | +); |
| 412 | +} |
| 413 | + |
| 414 | +export function unwrapRpcPayload(raw) { |
408 | 415 | if (raw?.ok === false) { |
409 | 416 | throw new Error(`gateway RPC failed: ${JSON.stringify(raw.error ?? raw)}`); |
410 | 417 | } |
411 | | -return raw?.result ?? raw?.payload ?? raw?.data ?? raw; |
| 418 | +if (hasOwnPayloadField(raw, "result")) { |
| 419 | +return raw.result; |
| 420 | +} |
| 421 | +if (hasOwnPayloadField(raw, "payload")) { |
| 422 | +return raw.payload; |
| 423 | +} |
| 424 | +if (hasOwnPayloadField(raw, "data")) { |
| 425 | +return raw.data; |
| 426 | +} |
| 427 | +return raw; |
412 | 428 | } |
413 | 429 | |
414 | 430 | async function rpcCall(method, params, options) { |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -830,11 +830,27 @@ function parseJsonOutput(stdout) {
|
830 | 830 | } |
831 | 831 | } |
832 | 832 | |
833 | | -function unwrapRpcPayload(raw) { |
| 833 | +function hasOwnPayloadField(raw, field) { |
| 834 | +return ( |
| 835 | +((typeof raw === "object" && raw !== null) || typeof raw === "function") && |
| 836 | +Object.hasOwn(raw, field) |
| 837 | +); |
| 838 | +} |
| 839 | + |
| 840 | +export function unwrapRpcPayload(raw) { |
834 | 841 | if (raw?.ok === false) { |
835 | 842 | throw new Error(`gateway RPC failed: ${JSON.stringify(raw.error ?? raw)}`); |
836 | 843 | } |
837 | | -return raw?.result ?? raw?.payload ?? raw?.data ?? raw; |
| 844 | +if (hasOwnPayloadField(raw, "result")) { |
| 845 | +return raw.result; |
| 846 | +} |
| 847 | +if (hasOwnPayloadField(raw, "payload")) { |
| 848 | +return raw.payload; |
| 849 | +} |
| 850 | +if (hasOwnPayloadField(raw, "data")) { |
| 851 | +return raw.data; |
| 852 | +} |
| 853 | +return raw; |
838 | 854 | } |
839 | 855 | |
840 | 856 | async function smokePlugin(pluginId, pluginDir, requiresConfig, pluginIndex, pluginRoot) { |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -220,6 +220,14 @@ describe("bundled plugin install/uninstall probe", () => {
|
220 | 220 | expect(second).toEqual({ text: "fghij", truncatedChars: 5 }); |
221 | 221 | }); |
222 | 222 | |
| 223 | +it("preserves explicit nullish runtime RPC result fields", async () => { |
| 224 | +const runtimeSmoke = await import(pathToFileURL(runtimeSmokePath).href); |
| 225 | + |
| 226 | +expect(runtimeSmoke.unwrapRpcPayload({ jsonrpc: "2.0", result: null })).toBeNull(); |
| 227 | +expect(runtimeSmoke.unwrapRpcPayload({ jsonrpc: "2.0", result: undefined })).toBeUndefined(); |
| 228 | +expect(runtimeSmoke.unwrapRpcPayload({ payload: null, data: { stale: true } })).toBeNull(); |
| 229 | +}); |
| 230 | + |
223 | 231 | it("caps noisy runtime gateway logs", async () => { |
224 | 232 | const runtimeSmoke = await importRuntimeSmokeWithEnv({ |
225 | 233 | OPENCLAW_BUNDLED_PLUGIN_RUNTIME_GATEWAY_LOG_BYTES: "64", |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -32,6 +32,7 @@ import {
|
32 | 32 | stopGateway, |
33 | 33 | summarizeProcessSamples, |
34 | 34 | tailFile, |
| 35 | +unwrapRpcPayload, |
35 | 36 | usesBuiltOpenClawEntry, |
36 | 37 | waitForGatewayReady, |
37 | 38 | } from "../../scripts/e2e/kitchen-sink-rpc-walk.mjs"; |
@@ -447,6 +448,19 @@ describe("kitchen-sink RPC caller loading", () => {
|
447 | 448 | }); |
448 | 449 | }); |
449 | 450 | |
| 451 | +describe("kitchen-sink RPC payload unwrapping", () => { |
| 452 | +it("preserves explicit nullish JSON-RPC result fields", () => { |
| 453 | +expect(unwrapRpcPayload({ jsonrpc: "2.0", result: null })).toBeNull(); |
| 454 | +expect(unwrapRpcPayload({ jsonrpc: "2.0", result: undefined })).toBeUndefined(); |
| 455 | +}); |
| 456 | + |
| 457 | +it("prefers result before legacy payload and data envelopes", () => { |
| 458 | +expect(unwrapRpcPayload({ result: false, payload: { stale: true } })).toBe(false); |
| 459 | +expect(unwrapRpcPayload({ payload: null, data: { stale: true } })).toBeNull(); |
| 460 | +expect(unwrapRpcPayload({ data: 0 })).toBe(0); |
| 461 | +}); |
| 462 | +}); |
| 463 | + |
450 | 464 | describe("kitchen-sink RPC command catalog assertions", () => { |
451 | 465 | it("keeps plugin commands and deduplicates aliases", () => { |
452 | 466 | expect( |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。