From 9f4cb3bbcd0efa5bc0f7afb6aa2370b1bff77cfa Mon Sep 17 00:00:00 2001 From: Gustavo Madeira Santana Date: Mon, 9 Mar 2026 05:33:36 -0400 Subject: [PATCH] Matrix: add profile action coverage --- .../matrix/src/matrix/actions/profile.test.ts | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 extensions/matrix/src/matrix/actions/profile.test.ts diff --git a/extensions/matrix/src/matrix/actions/profile.test.ts b/extensions/matrix/src/matrix/actions/profile.test.ts new file mode 100644 index 00000000000..ce8ec0087c4 --- /dev/null +++ b/extensions/matrix/src/matrix/actions/profile.test.ts @@ -0,0 +1,108 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const loadWebMediaMock = vi.fn(); +const syncMatrixOwnProfileMock = vi.fn(); +const withResolvedActionClientMock = vi.fn(); + +vi.mock("../../runtime.js", () => ({ + getMatrixRuntime: () => ({ + media: { + loadWebMedia: (...args: unknown[]) => loadWebMediaMock(...args), + }, + }), +})); + +vi.mock("../profile.js", () => ({ + syncMatrixOwnProfile: (...args: unknown[]) => syncMatrixOwnProfileMock(...args), +})); + +vi.mock("./client.js", () => ({ + withResolvedActionClient: (...args: unknown[]) => withResolvedActionClientMock(...args), +})); + +let updateMatrixOwnProfile: typeof import("./profile.js").updateMatrixOwnProfile; + +describe("matrix profile actions", () => { + beforeEach(async () => { + vi.resetModules(); + vi.clearAllMocks(); + loadWebMediaMock.mockResolvedValue({ + buffer: Buffer.from("avatar"), + contentType: "image/png", + fileName: "avatar.png", + }); + syncMatrixOwnProfileMock.mockResolvedValue({ + skipped: false, + displayNameUpdated: true, + avatarUpdated: true, + resolvedAvatarUrl: "mxc://example/avatar", + convertedAvatarFromHttp: true, + uploadedAvatarSource: "http", + }); + ({ updateMatrixOwnProfile } = await import("./profile.js")); + }); + + it("trims profile fields and persists through the action client wrapper", async () => { + withResolvedActionClientMock.mockImplementation(async (_opts, run) => { + return await run({ + getUserId: vi.fn(async () => "@bot:example.org"), + }); + }); + + await updateMatrixOwnProfile({ + accountId: "ops", + displayName: " Ops Bot ", + avatarUrl: " mxc://example/avatar ", + avatarPath: " /tmp/avatar.png ", + }); + + expect(withResolvedActionClientMock).toHaveBeenCalledWith( + { + accountId: "ops", + displayName: " Ops Bot ", + avatarUrl: " mxc://example/avatar ", + avatarPath: " /tmp/avatar.png ", + }, + expect.any(Function), + "persist", + ); + expect(syncMatrixOwnProfileMock).toHaveBeenCalledWith( + expect.objectContaining({ + userId: "@bot:example.org", + displayName: "Ops Bot", + avatarUrl: "mxc://example/avatar", + avatarPath: "/tmp/avatar.png", + }), + ); + }); + + it("bridges avatar loaders through Matrix runtime media helpers", async () => { + withResolvedActionClientMock.mockImplementation(async (_opts, run) => { + return await run({ + getUserId: vi.fn(async () => "@bot:example.org"), + }); + }); + + await updateMatrixOwnProfile({ + avatarUrl: "https://cdn.example.org/avatar.png", + avatarPath: "/tmp/avatar.png", + }); + + const call = syncMatrixOwnProfileMock.mock.calls[0]?.[0] as + | { + loadAvatarFromUrl: (url: string, maxBytes: number) => Promise; + loadAvatarFromPath: (path: string, maxBytes: number) => Promise; + } + | undefined; + + if (!call) { + throw new Error("syncMatrixOwnProfile was not called"); + } + + await call.loadAvatarFromUrl("https://cdn.example.org/avatar.png", 123); + await call.loadAvatarFromPath("/tmp/avatar.png", 456); + + expect(loadWebMediaMock).toHaveBeenNthCalledWith(1, "https://cdn.example.org/avatar.png", 123); + expect(loadWebMediaMock).toHaveBeenNthCalledWith(2, "/tmp/avatar.png", 456); + }); +});