mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-22 06:08:11 +00:00
fix: add browser error passthrough regression coverage (#26380) (thanks @TarasShyn)
This commit is contained in:
@@ -62,6 +62,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Browser/Extension relay shutdown: flush pending extension-request timers/rejections during relay `stop()` before socket/server teardown so in-flight extension waits do not survive shutdown windows. Landed from contributor PR #24142 by @kevinWangSheng.
|
||||
- Browser/Extension relay reconnect resilience: keep CDP clients alive across brief MV3 extension disconnect windows, wait briefly for extension reconnect before failing in-flight CDP commands, and only tear down relay target/client state after reconnect grace expires. Landed from contributor PR #27617 by @davidemanuelDEV.
|
||||
- Browser/Route decode hardening: guard malformed percent-encoding in relay target action routes and browser route-param decoding so crafted `%` paths return `400` instead of crashing/unhandled URI decode failures. Landed from contributor PR #11880 by @Yida-Dev.
|
||||
- Browser/Error visibility: preserve browser-control application error messages (HTTP 4xx/5xx) instead of rewriting them as generic reachability failures. Landed from contributor PR #26380 by @TarasShyn.
|
||||
- Feishu/Permission error dispatch: merge sender-name permission notices into the main inbound dispatch so one user message produces one agent turn/reply (instead of a duplicate permission-notice turn), with regression coverage. (#27381) thanks @byungsker.
|
||||
- Feishu/Inbound message metadata: include inbound `message_id` in `BodyForAgent` on a dedicated metadata line so agents can reliably correlate and act on media/message operations that require message IDs, with regression coverage. (#27253) thanks @xss925175263.
|
||||
- Feishu/Doc tools: route `feishu_doc` and `feishu_app_scopes` through the active agent account context (with explicit `accountId` override support) so multi-account agents no longer default to the first configured app, with regression coverage for context routing and explicit override behavior. (#27338) thanks @AaronL725.
|
||||
|
||||
@@ -8,6 +8,10 @@ const mocks = vi.hoisted(() => ({
|
||||
},
|
||||
},
|
||||
})),
|
||||
dispatch: vi.fn<() => Promise<{ status: number; body: unknown }>>(async () => ({
|
||||
status: 200,
|
||||
body: { ok: true },
|
||||
})),
|
||||
}));
|
||||
|
||||
vi.mock("../config/config.js", async (importOriginal) => {
|
||||
@@ -25,7 +29,7 @@ vi.mock("./control-service.js", () => ({
|
||||
|
||||
vi.mock("./routes/dispatcher.js", () => ({
|
||||
createBrowserRouteDispatcher: vi.fn(() => ({
|
||||
dispatch: vi.fn(async () => ({ status: 200, body: { ok: true } })),
|
||||
dispatch: mocks.dispatch,
|
||||
})),
|
||||
}));
|
||||
|
||||
@@ -47,6 +51,8 @@ describe("fetchBrowserJson loopback auth", () => {
|
||||
beforeEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
mocks.loadConfig.mockClear();
|
||||
mocks.dispatch.mockClear();
|
||||
mocks.dispatch.mockResolvedValue({ status: 200, body: { ok: true } });
|
||||
mocks.loadConfig.mockReturnValue({
|
||||
gateway: {
|
||||
auth: {
|
||||
@@ -60,6 +66,15 @@ describe("fetchBrowserJson loopback auth", () => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
async function expectServiceError(promise: Promise<unknown>, expectedMessage: string) {
|
||||
await expect(promise).rejects.toThrow(expectedMessage);
|
||||
try {
|
||||
await promise;
|
||||
} catch (error) {
|
||||
expect(String(error)).not.toContain("Can't reach the OpenClaw browser control service");
|
||||
}
|
||||
}
|
||||
|
||||
it("adds bearer auth for loopback absolute HTTP URLs", async () => {
|
||||
const fetchMock = stubJsonFetchOk();
|
||||
|
||||
@@ -114,4 +129,29 @@ describe("fetchBrowserJson loopback auth", () => {
|
||||
const headers = new Headers(init?.headers);
|
||||
expect(headers.get("authorization")).toBe("Bearer loopback-token");
|
||||
});
|
||||
|
||||
it("keeps absolute HTTP service errors unwrapped", async () => {
|
||||
const fetchMock = vi.fn<(input: RequestInfo | URL, init?: RequestInit) => Promise<Response>>(
|
||||
async () =>
|
||||
new Response("browser route failed", {
|
||||
status: 502,
|
||||
headers: { "Content-Type": "text/plain" },
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
|
||||
await expectServiceError(
|
||||
fetchBrowserJson<{ ok: boolean }>("http://example.com/"),
|
||||
"browser route failed",
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps local dispatcher service errors unwrapped", async () => {
|
||||
mocks.dispatch.mockResolvedValueOnce({
|
||||
status: 500,
|
||||
body: { error: "target unavailable" },
|
||||
});
|
||||
|
||||
await expectServiceError(fetchBrowserJson<{ ok: boolean }>("/json/list"), "target unavailable");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user