Files
Moltbot/ui/src/ui/controllers/control-ui-bootstrap.test.ts
Sid 3a6b412f00 fix(gateway): pass actual version to Control UI client instead of dev (#35230)
* fix(gateway): pass actual version to Control UI client instead of "dev"

The GatewayClient, CLI WS client, and browser Control UI all sent
"dev" as their clientVersion during handshake, making it impossible
to distinguish builds in gateway logs and health snapshots.

- GatewayClient and CLI WS client now use the resolved VERSION constant
- Control UI reads serverVersion from the bootstrap endpoint and
  forwards it when connecting
- Bootstrap contract extended with serverVersion field

Closes #35209

* Gateway: fix control-ui version version-reporting consistency

* Control UI: guard deferred bootstrap connect after disconnect

* fix(ui): accept same-origin http and relative gateway URLs for client version

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-03-05 00:01:34 -06:00

88 lines
2.5 KiB
TypeScript

/* @vitest-environment jsdom */
import { describe, expect, it, vi } from "vitest";
import { CONTROL_UI_BOOTSTRAP_CONFIG_PATH } from "../../../../src/gateway/control-ui-contract.js";
import { loadControlUiBootstrapConfig } from "./control-ui-bootstrap.ts";
describe("loadControlUiBootstrapConfig", () => {
it("loads assistant identity from the bootstrap endpoint", async () => {
const fetchMock = vi.fn().mockResolvedValue({
ok: true,
json: async () => ({
basePath: "/openclaw",
assistantName: "Ops",
assistantAvatar: "O",
assistantAgentId: "main",
serverVersion: "2026.3.2",
}),
});
vi.stubGlobal("fetch", fetchMock as unknown as typeof fetch);
const state = {
basePath: "/openclaw",
assistantName: "Assistant",
assistantAvatar: null,
assistantAgentId: null,
serverVersion: null,
};
await loadControlUiBootstrapConfig(state);
expect(fetchMock).toHaveBeenCalledWith(
`/openclaw${CONTROL_UI_BOOTSTRAP_CONFIG_PATH}`,
expect.objectContaining({ method: "GET" }),
);
expect(state.assistantName).toBe("Ops");
expect(state.assistantAvatar).toBe("O");
expect(state.assistantAgentId).toBe("main");
expect(state.serverVersion).toBe("2026.3.2");
vi.unstubAllGlobals();
});
it("ignores failures", async () => {
const fetchMock = vi.fn().mockResolvedValue({ ok: false });
vi.stubGlobal("fetch", fetchMock as unknown as typeof fetch);
const state = {
basePath: "",
assistantName: "Assistant",
assistantAvatar: null,
assistantAgentId: null,
serverVersion: null,
};
await loadControlUiBootstrapConfig(state);
expect(fetchMock).toHaveBeenCalledWith(
CONTROL_UI_BOOTSTRAP_CONFIG_PATH,
expect.objectContaining({ method: "GET" }),
);
expect(state.assistantName).toBe("Assistant");
vi.unstubAllGlobals();
});
it("normalizes trailing slash basePath for bootstrap fetch path", async () => {
const fetchMock = vi.fn().mockResolvedValue({ ok: false });
vi.stubGlobal("fetch", fetchMock as unknown as typeof fetch);
const state = {
basePath: "/openclaw/",
assistantName: "Assistant",
assistantAvatar: null,
assistantAgentId: null,
serverVersion: null,
};
await loadControlUiBootstrapConfig(state);
expect(fetchMock).toHaveBeenCalledWith(
`/openclaw${CONTROL_UI_BOOTSTRAP_CONFIG_PATH}`,
expect.objectContaining({ method: "GET" }),
);
vi.unstubAllGlobals();
});
});