mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 15:20:44 +00:00
test: share devices cli fixtures
This commit is contained in:
@@ -69,6 +69,55 @@ function readRuntimeCallText(call: unknown[] | undefined): string {
|
||||
return typeof value === "string" ? value : "";
|
||||
}
|
||||
|
||||
function readRuntimeOutput(): string {
|
||||
return runtime.log.mock.calls.map((entry) => readRuntimeCallText(entry)).join("\n");
|
||||
}
|
||||
|
||||
function pendingDevice(overrides: Record<string, unknown> = {}) {
|
||||
return {
|
||||
requestId: "req-1",
|
||||
deviceId: "device-1",
|
||||
displayName: "Device One",
|
||||
role: "operator",
|
||||
scopes: ["operator.admin"],
|
||||
ts: 1,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function pairedDevice(overrides: Record<string, unknown> = {}) {
|
||||
return {
|
||||
deviceId: "device-1",
|
||||
displayName: "Device One",
|
||||
roles: ["operator"],
|
||||
scopes: ["operator.read"],
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function mockGatewayPairingList(
|
||||
pendingOverrides: Record<string, unknown> = {},
|
||||
pairedOverrides: Record<string, unknown> = {},
|
||||
) {
|
||||
callGateway.mockResolvedValueOnce({
|
||||
pending: [pendingDevice(pendingOverrides)],
|
||||
paired: [pairedDevice(pairedOverrides)],
|
||||
});
|
||||
}
|
||||
|
||||
function rejectGatewayForLocalFallback(message = "gateway closed (1008): pairing required") {
|
||||
callGateway.mockRejectedValueOnce(new Error(message));
|
||||
}
|
||||
|
||||
function mockLocalPairingFallback(message?: string) {
|
||||
rejectGatewayForLocalFallback(message);
|
||||
listDevicePairing.mockResolvedValueOnce({
|
||||
pending: [{ requestId: "req-1", deviceId: "device-1", publicKey: "pk", ts: 1 }],
|
||||
paired: [],
|
||||
});
|
||||
summarizeDeviceTokens.mockReturnValue(undefined);
|
||||
}
|
||||
|
||||
describe("devices cli approve", () => {
|
||||
it("approves an explicit request id without listing", async () => {
|
||||
callGateway.mockResolvedValueOnce({ device: { deviceId: "device-1" } });
|
||||
@@ -401,12 +450,7 @@ describe("devices cli local fallback", () => {
|
||||
const fallbackNotice = "Direct scope access failed; using local fallback.";
|
||||
|
||||
it("falls back to local pairing list when gateway returns pairing required on loopback", async () => {
|
||||
callGateway.mockRejectedValueOnce(new Error("gateway closed (1008): pairing required"));
|
||||
listDevicePairing.mockResolvedValueOnce({
|
||||
pending: [{ requestId: "req-1", deviceId: "device-1", publicKey: "pk", ts: 1 }],
|
||||
paired: [],
|
||||
});
|
||||
summarizeDeviceTokens.mockReturnValue(undefined);
|
||||
mockLocalPairingFallback();
|
||||
|
||||
await runDevicesCommand(["list"]);
|
||||
|
||||
@@ -418,7 +462,7 @@ describe("devices cli local fallback", () => {
|
||||
});
|
||||
|
||||
it("falls back to local approve when gateway returns pairing required on loopback", async () => {
|
||||
callGateway.mockRejectedValueOnce(new Error("gateway closed (1008): pairing required"));
|
||||
rejectGatewayForLocalFallback();
|
||||
approveDevicePairing.mockResolvedValueOnce({
|
||||
requestId: "req-latest",
|
||||
device: {
|
||||
@@ -440,14 +484,7 @@ describe("devices cli local fallback", () => {
|
||||
});
|
||||
|
||||
it("falls back to local pairing list when gateway returns a scope upgrade message on loopback", async () => {
|
||||
callGateway.mockRejectedValueOnce(
|
||||
new Error("scope upgrade pending approval (requestId: req-123)"),
|
||||
);
|
||||
listDevicePairing.mockResolvedValueOnce({
|
||||
pending: [{ requestId: "req-1", deviceId: "device-1", publicKey: "pk", ts: 1 }],
|
||||
paired: [],
|
||||
});
|
||||
summarizeDeviceTokens.mockReturnValue(undefined);
|
||||
mockLocalPairingFallback("scope upgrade pending approval (requestId: req-123)");
|
||||
|
||||
await runDevicesCommand(["list"]);
|
||||
|
||||
@@ -456,7 +493,7 @@ describe("devices cli local fallback", () => {
|
||||
});
|
||||
|
||||
it("does not use local fallback when an explicit --url is provided", async () => {
|
||||
callGateway.mockRejectedValueOnce(new Error("gateway closed (1008): pairing required"));
|
||||
rejectGatewayForLocalFallback();
|
||||
|
||||
await expect(
|
||||
runDevicesCommand(["list", "--json", "--url", "ws://127.0.0.1:18789"]),
|
||||
@@ -467,30 +504,11 @@ describe("devices cli local fallback", () => {
|
||||
|
||||
describe("devices cli list", () => {
|
||||
it("renders requested versus approved access for pending upgrades", async () => {
|
||||
callGateway.mockResolvedValueOnce({
|
||||
pending: [
|
||||
{
|
||||
requestId: "req-1",
|
||||
deviceId: "device-1",
|
||||
displayName: "Device One",
|
||||
role: "operator",
|
||||
scopes: ["operator.admin", "operator.read"],
|
||||
ts: 1,
|
||||
},
|
||||
],
|
||||
paired: [
|
||||
{
|
||||
deviceId: "device-1",
|
||||
displayName: "Device One",
|
||||
roles: ["operator"],
|
||||
scopes: ["operator.read"],
|
||||
},
|
||||
],
|
||||
});
|
||||
mockGatewayPairingList({ scopes: ["operator.admin", "operator.read"] });
|
||||
|
||||
await runDevicesCommand(["list"]);
|
||||
|
||||
const output = runtime.log.mock.calls.map((entry) => readRuntimeCallText(entry)).join("\n");
|
||||
const output = readRuntimeOutput();
|
||||
expect(output).toContain("Requested");
|
||||
expect(output).toContain("Approved");
|
||||
expect(output).toContain("operator.write");
|
||||
@@ -499,61 +517,21 @@ describe("devices cli list", () => {
|
||||
});
|
||||
|
||||
it("normalizes pending device ids before matching paired approvals", async () => {
|
||||
callGateway.mockResolvedValueOnce({
|
||||
pending: [
|
||||
{
|
||||
requestId: "req-1",
|
||||
deviceId: " device-1 ",
|
||||
displayName: "Device One",
|
||||
role: "operator",
|
||||
scopes: ["operator.admin"],
|
||||
ts: 1,
|
||||
},
|
||||
],
|
||||
paired: [
|
||||
{
|
||||
deviceId: "device-1",
|
||||
displayName: "Device One",
|
||||
roles: ["operator"],
|
||||
scopes: ["operator.read"],
|
||||
},
|
||||
],
|
||||
});
|
||||
mockGatewayPairingList({ deviceId: " device-1 " });
|
||||
|
||||
await runDevicesCommand(["list"]);
|
||||
|
||||
const output = runtime.log.mock.calls.map((entry) => readRuntimeCallText(entry)).join("\n");
|
||||
const output = readRuntimeOutput();
|
||||
expect(output).toContain("scope upgrade");
|
||||
expect(output).toContain("operator.read");
|
||||
});
|
||||
|
||||
it("does not show upgrade context for key-mismatched pending requests", async () => {
|
||||
callGateway.mockResolvedValueOnce({
|
||||
pending: [
|
||||
{
|
||||
requestId: "req-1",
|
||||
deviceId: "device-1",
|
||||
publicKey: "new-key",
|
||||
displayName: "Device One",
|
||||
role: "operator",
|
||||
scopes: ["operator.admin"],
|
||||
ts: 1,
|
||||
},
|
||||
],
|
||||
paired: [
|
||||
{
|
||||
deviceId: "device-1",
|
||||
publicKey: "old-key",
|
||||
displayName: "Device One",
|
||||
roles: ["operator"],
|
||||
scopes: ["operator.read"],
|
||||
},
|
||||
],
|
||||
});
|
||||
mockGatewayPairingList({ publicKey: "new-key" }, { publicKey: "old-key" });
|
||||
|
||||
await runDevicesCommand(["list"]);
|
||||
|
||||
const output = runtime.log.mock.calls.map((entry) => readRuntimeCallText(entry)).join("\n");
|
||||
const output = readRuntimeOutput();
|
||||
expect(output).toContain("new pairing");
|
||||
expect(output).not.toContain("scope upgrade");
|
||||
expect(output).not.toContain("roles: operator; scopes: operator.read");
|
||||
@@ -585,7 +563,7 @@ describe("devices cli list", () => {
|
||||
|
||||
await runDevicesCommand(["list"]);
|
||||
|
||||
const output = runtime.log.mock.calls.map((entry) => readRuntimeCallText(entry)).join("\n");
|
||||
const output = readRuntimeOutput();
|
||||
expect(output).not.toContain("\u001b");
|
||||
expect(output).not.toContain("\r");
|
||||
expect(output).toContain("BadName");
|
||||
|
||||
Reference in New Issue
Block a user