mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-19 09:01:39 -06:00
a8b7290f34
* feat(gateway): durable user profiles with email aliases and avatars * fix(gateway): compress merge tombstones, content-hash avatar ETags, users CLI json output * fix(gateway): lean profile listing, scoped avatar routing, typed email validation * fix(gateway): protocol-complete profile payloads and consistent store reads * fix(gateway): mark profile schema ensured only after commit * fix(gateway): avatar endpoint HEAD support and RFC If-None-Match * fix(gateway): profiles CI conformance — bindings, lint, knip, sql boundary * feat(gateway): self-service profile edits for authenticated users * fix(gateway): users.self bootstrap, tombstone-aware ownership, escaped CLI output * fix(gateway): raw-DDL allowlist entry and lean profile exports
75 lines
2.0 KiB
TypeScript
75 lines
2.0 KiB
TypeScript
import { Command } from "commander";
|
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import { registerUsersCli, testApi } from "./users-cli.js";
|
|
|
|
const callGatewayFromCli = vi.hoisted(() => vi.fn());
|
|
vi.mock("./gateway-rpc.js", () => ({ callGatewayFromCli }));
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
callGatewayFromCli.mockReset();
|
|
});
|
|
|
|
describe("registerUsersCli", () => {
|
|
it("routes link-email through the admin gateway method", async () => {
|
|
const program = new Command().exitOverride();
|
|
registerUsersCli(program);
|
|
|
|
await program.parseAsync([
|
|
"node",
|
|
"openclaw",
|
|
"users",
|
|
"link-email",
|
|
"Ada@example.com",
|
|
"--to",
|
|
"p-1",
|
|
]);
|
|
|
|
expect(callGatewayFromCli).toHaveBeenCalledWith(
|
|
"users.linkEmail",
|
|
expect.objectContaining({ to: "p-1" }),
|
|
{ email: "Ada@example.com", targetProfileId: "p-1" },
|
|
{ scopes: ["operator.admin"] },
|
|
);
|
|
});
|
|
|
|
it("prints the link result as JSON when requested", async () => {
|
|
const output = vi.spyOn(process.stdout, "write").mockImplementation(() => true);
|
|
callGatewayFromCli.mockResolvedValue({ profile: { id: "p-1" } });
|
|
const program = new Command().exitOverride();
|
|
registerUsersCli(program);
|
|
|
|
await program.parseAsync([
|
|
"node",
|
|
"openclaw",
|
|
"users",
|
|
"link-email",
|
|
"Ada@example.com",
|
|
"--to",
|
|
"p-1",
|
|
"--json",
|
|
]);
|
|
|
|
expect(output).toHaveBeenCalledWith('{\n "profile": {\n "id": "p-1"\n }\n}\n');
|
|
});
|
|
|
|
it("escapes untrusted profile fields in human list output", () => {
|
|
const output = vi.spyOn(process.stdout, "write").mockImplementation(() => true);
|
|
|
|
testApi.writeUsersList(
|
|
{
|
|
profiles: [
|
|
{
|
|
id: "p-1",
|
|
displayName: "Ada\n\t\u001b[2J\u0007",
|
|
emails: ["ada@example.com\nnext@example.com"],
|
|
},
|
|
],
|
|
},
|
|
false,
|
|
);
|
|
|
|
expect(output).toHaveBeenCalledWith("p-1\tAda\\n\\t\tada@example.com\\nnext@example.com\n");
|
|
});
|
|
});
|