refactor: share matrix monitor test helpers

This commit is contained in:
Peter Steinberger 2026-03-13 20:43:36 +00:00
parent 67f7d1e65f
commit 65cf2cea9d
2 changed files with 35 additions and 41 deletions

View File

@ -7,6 +7,8 @@ import { createDirectRoomTracker } from "./direct.js";
type StateEvent = Record<string, unknown>;
type DmMap = Record<string, boolean>;
const brokenDmRoomId = "!broken-dm:example.org";
const defaultBrokenDmMembers = ["@alice:example.org", "@bot:example.org"];
function createMockClient(opts: {
dmRooms?: DmMap;
@ -50,6 +52,21 @@ function createMockClient(opts: {
};
}
function createBrokenDmClient(roomNameEvent?: StateEvent) {
return createMockClient({
dmRooms: {},
membersByRoom: {
[brokenDmRoomId]: defaultBrokenDmMembers,
},
stateEvents: {
// is_direct not set on either member (e.g. Continuwuity bug)
[`${brokenDmRoomId}|m.room.member|@alice:example.org`]: {},
[`${brokenDmRoomId}|m.room.member|@bot:example.org`]: {},
...(roomNameEvent ? { [`${brokenDmRoomId}|m.room.name|`]: roomNameEvent } : {}),
},
});
}
// ---------------------------------------------------------------------------
// Tests -- isDirectMessage
// ---------------------------------------------------------------------------
@ -131,22 +148,11 @@ describe("createDirectRoomTracker", () => {
describe("conservative fallback (memberCount + room name)", () => {
it("returns true for 2-member room WITHOUT a room name (broken flags)", async () => {
const client = createMockClient({
dmRooms: {},
membersByRoom: {
"!broken-dm:example.org": ["@alice:example.org", "@bot:example.org"],
},
stateEvents: {
// is_direct not set on either member (e.g. Continuwuity bug)
"!broken-dm:example.org|m.room.member|@alice:example.org": {},
"!broken-dm:example.org|m.room.member|@bot:example.org": {},
// No m.room.name -> getRoomStateEvent will throw (event not found)
},
});
const client = createBrokenDmClient();
const tracker = createDirectRoomTracker(client as never);
const result = await tracker.isDirectMessage({
roomId: "!broken-dm:example.org",
roomId: brokenDmRoomId,
senderId: "@alice:example.org",
});
@ -154,21 +160,11 @@ describe("createDirectRoomTracker", () => {
});
it("returns true for 2-member room with empty room name", async () => {
const client = createMockClient({
dmRooms: {},
membersByRoom: {
"!broken-dm:example.org": ["@alice:example.org", "@bot:example.org"],
},
stateEvents: {
"!broken-dm:example.org|m.room.member|@alice:example.org": {},
"!broken-dm:example.org|m.room.member|@bot:example.org": {},
"!broken-dm:example.org|m.room.name|": { name: "" },
},
});
const client = createBrokenDmClient({ name: "" });
const tracker = createDirectRoomTracker(client as never);
const result = await tracker.isDirectMessage({
roomId: "!broken-dm:example.org",
roomId: brokenDmRoomId,
senderId: "@alice:example.org",
});

View File

@ -12,6 +12,8 @@ vi.mock("../send.js", () => ({
}));
describe("registerMatrixMonitorEvents", () => {
const roomId = "!room:example.org";
beforeEach(() => {
sendReadReceiptMatrixMock.mockClear();
});
@ -53,6 +55,16 @@ describe("registerMatrixMonitorEvents", () => {
return { client, getUserId, onRoomMessage, roomMessageHandler, logVerboseMessage };
}
async function expectForwardedWithoutReadReceipt(event: MatrixRawEvent) {
const { onRoomMessage, roomMessageHandler } = createHarness();
roomMessageHandler(roomId, event);
await vi.waitFor(() => {
expect(onRoomMessage).toHaveBeenCalledWith(roomId, event);
});
expect(sendReadReceiptMatrixMock).not.toHaveBeenCalled();
}
it("sends read receipt immediately for non-self messages", async () => {
const { client, onRoomMessage, roomMessageHandler } = createHarness();
const event = {
@ -69,30 +81,16 @@ describe("registerMatrixMonitorEvents", () => {
});
it("does not send read receipts for self messages", async () => {
const { onRoomMessage, roomMessageHandler } = createHarness();
const event = {
await expectForwardedWithoutReadReceipt({
event_id: "$e2",
sender: "@bot:example.org",
} as MatrixRawEvent;
roomMessageHandler("!room:example.org", event);
await vi.waitFor(() => {
expect(onRoomMessage).toHaveBeenCalledWith("!room:example.org", event);
});
expect(sendReadReceiptMatrixMock).not.toHaveBeenCalled();
});
it("skips receipt when message lacks sender or event id", async () => {
const { onRoomMessage, roomMessageHandler } = createHarness();
const event = {
await expectForwardedWithoutReadReceipt({
sender: "@alice:example.org",
} as MatrixRawEvent;
roomMessageHandler("!room:example.org", event);
await vi.waitFor(() => {
expect(onRoomMessage).toHaveBeenCalledWith("!room:example.org", event);
});
expect(sendReadReceiptMatrixMock).not.toHaveBeenCalled();
});
it("caches self user id across messages", async () => {