From e75ae8b3db13e6241082510122f4261b7c796c1e Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 20 Apr 2026 16:22:01 +0100 Subject: [PATCH] test: share matrix event fixtures --- .../src/matrix/sdk/event-helpers.test.ts | 59 +++----- .../matrix/src/matrix/send/targets.test.ts | 143 ++++++++++-------- 2 files changed, 99 insertions(+), 103 deletions(-) diff --git a/extensions/matrix/src/matrix/sdk/event-helpers.test.ts b/extensions/matrix/src/matrix/sdk/event-helpers.test.ts index 9020b1e8b7b..c432a9c601b 100644 --- a/extensions/matrix/src/matrix/sdk/event-helpers.test.ts +++ b/extensions/matrix/src/matrix/sdk/event-helpers.test.ts @@ -2,6 +2,25 @@ import type { MatrixEvent } from "matrix-js-sdk/lib/matrix.js"; import { describe, expect, it } from "vitest"; import { buildHttpError, matrixEventToRaw, parseMxc } from "./event-helpers.js"; +const makeEditedMessageEvent = (): MatrixEvent => + ({ + getId: () => "$root", + getSender: () => "@alice:example.org", + getType: () => "m.room.message", + getTs: () => 1000, + getOriginalContent: () => ({ body: "original", msgtype: "m.text" }), + getContent: () => ({ + body: "@bot edited", + "m.mentions": { user_ids: ["@bot:example.org"] }, + msgtype: "m.text", + }), + getUnsigned: () => ({ + "m.relations": { + "m.replace": { event_id: "$edit" }, + }, + }), + }) as unknown as MatrixEvent; + describe("event-helpers", () => { it("parses mxc URIs", () => { expect(parseMxc("mxc://server.example/media-id")).toEqual({ @@ -59,25 +78,7 @@ describe("event-helpers", () => { }); it("serializes current content by default for read APIs", () => { - const event = { - getId: () => "$root", - getSender: () => "@alice:example.org", - getType: () => "m.room.message", - getTs: () => 1000, - getOriginalContent: () => ({ body: "original", msgtype: "m.text" }), - getContent: () => ({ - body: "@bot edited", - "m.mentions": { user_ids: ["@bot:example.org"] }, - msgtype: "m.text", - }), - getUnsigned: () => ({ - "m.relations": { - "m.replace": { event_id: "$edit" }, - }, - }), - } as unknown as MatrixEvent; - - expect(matrixEventToRaw(event)).toMatchObject({ + expect(matrixEventToRaw(makeEditedMessageEvent())).toMatchObject({ content: { body: "@bot edited", "m.mentions": { user_ids: ["@bot:example.org"] }, @@ -87,25 +88,7 @@ describe("event-helpers", () => { }); it("can serialize original content for inbound trigger filtering", () => { - const event = { - getId: () => "$root", - getSender: () => "@alice:example.org", - getType: () => "m.room.message", - getTs: () => 1000, - getOriginalContent: () => ({ body: "original", msgtype: "m.text" }), - getContent: () => ({ - body: "@bot edited", - "m.mentions": { user_ids: ["@bot:example.org"] }, - msgtype: "m.text", - }), - getUnsigned: () => ({ - "m.relations": { - "m.replace": { event_id: "$edit" }, - }, - }), - } as unknown as MatrixEvent; - - expect(matrixEventToRaw(event, { contentMode: "original" })).toMatchObject({ + expect(matrixEventToRaw(makeEditedMessageEvent(), { contentMode: "original" })).toMatchObject({ content: { body: "original", msgtype: "m.text" }, unsigned: { "m.relations": { diff --git a/extensions/matrix/src/matrix/send/targets.test.ts b/extensions/matrix/src/matrix/send/targets.test.ts index 0db4281d669..b58bf2e783d 100644 --- a/extensions/matrix/src/matrix/send/targets.test.ts +++ b/extensions/matrix/src/matrix/send/targets.test.ts @@ -4,6 +4,43 @@ import { EventType } from "./types.js"; const { resolveMatrixRoomId, normalizeThreadId } = await import("./targets.js"); +const BOT_USER_ID = "@bot:example.org"; + +const makeMappedDirectClient = (params: { + userId: string; + roomId: string; + botId?: string; + extra?: Record; +}) => + ({ + getAccountData: vi.fn().mockResolvedValue({ + [params.userId]: [params.roomId], + }), + getUserId: vi.fn().mockResolvedValue(params.botId ?? BOT_USER_ID), + getJoinedRooms: vi.fn(), + getJoinedRoomMembers: vi.fn().mockResolvedValue([params.botId ?? BOT_USER_ID, params.userId]), + setAccountData: vi.fn(), + ...params.extra, + }) as unknown as MatrixClient; + +const makeFallbackDirectClient = (params: { + userId: string; + roomIds: string[]; + botId?: string; + members?: string[]; + extra?: Record; +}) => + ({ + getAccountData: vi.fn().mockRejectedValue(new Error("nope")), + getUserId: vi.fn().mockResolvedValue(params.botId ?? BOT_USER_ID), + getJoinedRooms: vi.fn().mockResolvedValue(params.roomIds), + getJoinedRoomMembers: vi + .fn() + .mockResolvedValue(params.members ?? [params.botId ?? BOT_USER_ID, params.userId]), + setAccountData: vi.fn().mockResolvedValue(undefined), + ...params.extra, + }) as unknown as MatrixClient; + beforeEach(() => { vi.clearAllMocks(); }); @@ -11,15 +48,7 @@ beforeEach(() => { describe("resolveMatrixRoomId", () => { it("uses m.direct when available", async () => { const userId = "@user:example.org"; - const client = { - getAccountData: vi.fn().mockResolvedValue({ - [userId]: ["!room:example.org"], - }), - getUserId: vi.fn().mockResolvedValue("@bot:example.org"), - getJoinedRooms: vi.fn(), - getJoinedRoomMembers: vi.fn().mockResolvedValue(["@bot:example.org", userId]), - setAccountData: vi.fn(), - } as unknown as MatrixClient; + const client = makeMappedDirectClient({ userId, roomId: "!room:example.org" }); const roomId = await resolveMatrixRoomId(client, userId); @@ -31,19 +60,12 @@ describe("resolveMatrixRoomId", () => { it("falls back to joined rooms and persists m.direct", async () => { const userId = "@fallback:example.org"; const roomId = "!room:example.org"; - const setAccountData = vi.fn().mockResolvedValue(undefined); - const client = { - getAccountData: vi.fn().mockRejectedValue(new Error("nope")), - getUserId: vi.fn().mockResolvedValue("@bot:example.org"), - getJoinedRooms: vi.fn().mockResolvedValue([roomId]), - getJoinedRoomMembers: vi.fn().mockResolvedValue(["@bot:example.org", userId]), - setAccountData, - } as unknown as MatrixClient; + const client = makeFallbackDirectClient({ userId, roomIds: [roomId] }); const resolved = await resolveMatrixRoomId(client, userId); expect(resolved).toBe(roomId); - expect(setAccountData).toHaveBeenCalledWith( + expect(client.setAccountData).toHaveBeenCalledWith( EventType.Direct, expect.objectContaining({ [userId]: [roomId] }), ); @@ -51,20 +73,19 @@ describe("resolveMatrixRoomId", () => { it("prefers joined rooms marked direct in local member state over plain strict rooms", async () => { const userId = "@fallback:example.org"; - const client = { - getAccountData: vi.fn().mockRejectedValue(new Error("nope")), - getUserId: vi.fn().mockResolvedValue("@bot:example.org"), - getJoinedRooms: vi.fn().mockResolvedValue(["!fallback:example.org", "!explicit:example.org"]), - getJoinedRoomMembers: vi.fn().mockResolvedValue(["@bot:example.org", userId]), - getRoomStateEvent: vi - .fn() - .mockImplementation(async (roomId: string, _eventType: string, stateKey: string) => - roomId === "!explicit:example.org" && stateKey === "@bot:example.org" - ? { is_direct: true } - : {}, - ), - setAccountData: vi.fn().mockResolvedValue(undefined), - } as unknown as MatrixClient; + const client = makeFallbackDirectClient({ + userId, + roomIds: ["!fallback:example.org", "!explicit:example.org"], + extra: { + getRoomStateEvent: vi + .fn() + .mockImplementation(async (roomId: string, _eventType: string, stateKey: string) => + roomId === "!explicit:example.org" && stateKey === BOT_USER_ID + ? { is_direct: true } + : {}, + ), + }, + }); const resolved = await resolveMatrixRoomId(client, userId); @@ -77,20 +98,19 @@ describe("resolveMatrixRoomId", () => { it("ignores remote member-state direct flags when resolving a direct room", async () => { const userId = "@fallback:example.org"; - const client = { - getAccountData: vi.fn().mockRejectedValue(new Error("nope")), - getUserId: vi.fn().mockResolvedValue("@bot:example.org"), - getJoinedRooms: vi - .fn() - .mockResolvedValue(["!fallback:example.org", "!remote-marked:example.org"]), - getJoinedRoomMembers: vi.fn().mockResolvedValue(["@bot:example.org", userId]), - getRoomStateEvent: vi - .fn() - .mockImplementation(async (roomId: string, _eventType: string, stateKey: string) => - roomId === "!remote-marked:example.org" && stateKey === userId ? { is_direct: true } : {}, - ), - setAccountData: vi.fn().mockResolvedValue(undefined), - } as unknown as MatrixClient; + const client = makeFallbackDirectClient({ + userId, + roomIds: ["!fallback:example.org", "!remote-marked:example.org"], + extra: { + getRoomStateEvent: vi + .fn() + .mockImplementation(async (roomId: string, _eventType: string, stateKey: string) => + roomId === "!remote-marked:example.org" && stateKey === userId + ? { is_direct: true } + : {}, + ), + }, + }); const resolved = await resolveMatrixRoomId(client, userId); @@ -126,15 +146,11 @@ describe("resolveMatrixRoomId", () => { it("does not fall back to larger shared rooms for direct-user sends", async () => { const userId = "@group:example.org"; const roomId = "!group:example.org"; - const client = { - getAccountData: vi.fn().mockRejectedValue(new Error("nope")), - getUserId: vi.fn().mockResolvedValue("@bot:example.org"), - getJoinedRooms: vi.fn().mockResolvedValue([roomId]), - getJoinedRoomMembers: vi - .fn() - .mockResolvedValue(["@bot:example.org", userId, "@extra:example.org"]), - setAccountData: vi.fn().mockResolvedValue(undefined), - } as unknown as MatrixClient; + const client = makeFallbackDirectClient({ + userId, + roomIds: [roomId], + members: [BOT_USER_ID, userId, "@extra:example.org"], + }); await expect(resolveMatrixRoomId(client, userId)).rejects.toThrow( `No direct room found for ${userId} (m.direct missing)`, @@ -145,16 +161,13 @@ describe("resolveMatrixRoomId", () => { it("accepts nested Matrix user target prefixes", async () => { const userId = "@prefixed:example.org"; const roomId = "!prefixed-room:example.org"; - const client = { - getAccountData: vi.fn().mockResolvedValue({ - [userId]: [roomId], - }), - getUserId: vi.fn().mockResolvedValue("@bot:example.org"), - getJoinedRooms: vi.fn(), - getJoinedRoomMembers: vi.fn().mockResolvedValue(["@bot:example.org", userId]), - setAccountData: vi.fn(), - resolveRoom: vi.fn(), - } as unknown as MatrixClient; + const client = makeMappedDirectClient({ + userId, + roomId, + extra: { + resolveRoom: vi.fn(), + }, + }); const resolved = await resolveMatrixRoomId(client, `matrix:user:${userId}`);