From a6b21683f8dcea3f06019540b12dcb760f2cc8da Mon Sep 17 00:00:00 2001 From: Zac McKenzie Date: Tue, 16 Jan 2024 10:13:26 +1000 Subject: [PATCH 1/3] Add an autoleave rooms mixin for leaving empty rooms Signed-off-by: Zac McKenzie --- src/mixins/AutoleaveRoomsMixin.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/mixins/AutoleaveRoomsMixin.ts diff --git a/src/mixins/AutoleaveRoomsMixin.ts b/src/mixins/AutoleaveRoomsMixin.ts new file mode 100644 index 00000000..6a39df45 --- /dev/null +++ b/src/mixins/AutoleaveRoomsMixin.ts @@ -0,0 +1,20 @@ +import { MatrixClient } from "../MatrixClient"; + +/** + * Automatically leaves empty rooms + * @category Mixins + */ +export class AutoleaveRoomsMixin { + public static setupOnClient(client: MatrixClient): void { + client.on("room.event", async (roomId: string, event: any) => { + if ( + event.type === "m.room.member" && + event.content?.membership === "leave" && + (await client.getJoinedRoomMembers(roomId)).length === 1 + ) { + await client.leaveRoom(roomId); + await client.forgetRoom(roomId); + } + }); + } +} From 0d09316c87b3ccea70f602d1fad376ecd69b3a29 Mon Sep 17 00:00:00 2001 From: Zac McKenzie Date: Tue, 16 Jan 2024 11:18:03 +1000 Subject: [PATCH 2/3] Add faulty test for the autoleave rooms mixin * Unable to complete due to lack of knowledge Signed-off-by: Zac McKenzie --- src/index.ts | 1 + test/mixins/AutoleaveRoomsMixinTest.ts | 63 ++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 test/mixins/AutoleaveRoomsMixinTest.ts diff --git a/src/index.ts b/src/index.ts index 56afd3d0..9adea50a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -37,6 +37,7 @@ export * from "./metrics/Metrics"; // Mixins export * from "./mixins/AutojoinRoomsMixin"; export * from "./mixins/AutojoinUpgradedRoomsMixin"; +export * from "./mixins/AutoleaveRoomsMixin"; // Models export * from "./models/Presence"; diff --git a/test/mixins/AutoleaveRoomsMixinTest.ts b/test/mixins/AutoleaveRoomsMixinTest.ts new file mode 100644 index 00000000..fa93f7f5 --- /dev/null +++ b/test/mixins/AutoleaveRoomsMixinTest.ts @@ -0,0 +1,63 @@ +import * as simple from "simple-mock"; + +import { AutoleaveRoomsMixin } from "../../src"; +import { createTestClient } from "../TestUtils"; + +describe("AutoleaveRoomsMixin", () => { + it("shouldn't leave rooms multiple members", async () => { + const { client } = createTestClient(); + AutoleaveRoomsMixin.setupOnClient(client); + + const roomId = "!test:example.org"; + let members = [ + "@this:example.org", + "@alice:example.org", + "@bob:example.org", + ]; + + const getJoinedRoomMembersSpy = simple + .mock(client, "getJoinedRoomMembers") + .callFn((rid) => { + expect(rid).toEqual(roomId); + return members; + }); + const leaveSpy = simple.mock(client, "leaveRoom"); + const forgetSpy = simple.mock(client, "forgetRoom"); + + client.emit("room.event", roomId, { + type: "m.room.member", + content: { membership: "leave" }, + }); + expect(getJoinedRoomMembersSpy.callCount).toBe(1); + // Since the AutoleaveRoomsMixin room.event handler is asyncronous, these functions don't get called syncronously + // Which means we must somehow await the handler's completion before executing the following tests, but I'm not sure how to do that + // expect(leaveSpy.callCount).toBe(0); + // expect(forgetSpy.callCount).toBe(0); + }); + + it("should leave rooms with one or no members", async () => { + const { client } = createTestClient(); + AutoleaveRoomsMixin.setupOnClient(client); + + const roomId = "!test:example.org"; + let members = ["@this:example.org"]; + + const getJoinedRoomMembersSpy = simple + .mock(client, "getJoinedRoomMembers") + .callFn((rid) => { + expect(rid).toEqual(roomId); + return members; + }); + const leaveSpy = simple.mock(client, "leaveRoom"); + const forgetSpy = simple.mock(client, "forgetRoom"); + + client.emit("room.event", roomId, { + type: "m.room.member", + content: { membership: "leave" }, + }); + expect(getJoinedRoomMembersSpy.callCount).toBe(1); + // See comments above (lines 41-42) + // expect(leaveSpy.callCount).toBe(1); + // expect(forgetSpy.callCount).toBe(1); + }); +}); From 13e86f27d6bf4d4c5a22fd428b56f4732b6b47b3 Mon Sep 17 00:00:00 2001 From: Zac McKenzie Date: Tue, 16 Jan 2024 18:09:59 +1000 Subject: [PATCH 3/3] Fix eslint errors Signed-off-by: Zac McKenzie --- src/mixins/AutoleaveRoomsMixin.ts | 24 +++--- test/mixins/AutoleaveRoomsMixinTest.ts | 112 ++++++++++++------------- 2 files changed, 68 insertions(+), 68 deletions(-) diff --git a/src/mixins/AutoleaveRoomsMixin.ts b/src/mixins/AutoleaveRoomsMixin.ts index 6a39df45..3c53ed11 100644 --- a/src/mixins/AutoleaveRoomsMixin.ts +++ b/src/mixins/AutoleaveRoomsMixin.ts @@ -5,16 +5,16 @@ import { MatrixClient } from "../MatrixClient"; * @category Mixins */ export class AutoleaveRoomsMixin { - public static setupOnClient(client: MatrixClient): void { - client.on("room.event", async (roomId: string, event: any) => { - if ( - event.type === "m.room.member" && - event.content?.membership === "leave" && - (await client.getJoinedRoomMembers(roomId)).length === 1 - ) { - await client.leaveRoom(roomId); - await client.forgetRoom(roomId); - } - }); - } + public static setupOnClient(client: MatrixClient): void { + client.on("room.event", async (roomId: string, event: any) => { + if ( + event.type === "m.room.member" && + event.content?.membership === "leave" && + (await client.getJoinedRoomMembers(roomId)).length === 1 + ) { + await client.leaveRoom(roomId); + await client.forgetRoom(roomId); + } + }); + } } diff --git a/test/mixins/AutoleaveRoomsMixinTest.ts b/test/mixins/AutoleaveRoomsMixinTest.ts index fa93f7f5..4fb0b6b7 100644 --- a/test/mixins/AutoleaveRoomsMixinTest.ts +++ b/test/mixins/AutoleaveRoomsMixinTest.ts @@ -4,60 +4,60 @@ import { AutoleaveRoomsMixin } from "../../src"; import { createTestClient } from "../TestUtils"; describe("AutoleaveRoomsMixin", () => { - it("shouldn't leave rooms multiple members", async () => { - const { client } = createTestClient(); - AutoleaveRoomsMixin.setupOnClient(client); - - const roomId = "!test:example.org"; - let members = [ - "@this:example.org", - "@alice:example.org", - "@bob:example.org", - ]; - - const getJoinedRoomMembersSpy = simple - .mock(client, "getJoinedRoomMembers") - .callFn((rid) => { - expect(rid).toEqual(roomId); - return members; - }); - const leaveSpy = simple.mock(client, "leaveRoom"); - const forgetSpy = simple.mock(client, "forgetRoom"); - - client.emit("room.event", roomId, { - type: "m.room.member", - content: { membership: "leave" }, - }); - expect(getJoinedRoomMembersSpy.callCount).toBe(1); - // Since the AutoleaveRoomsMixin room.event handler is asyncronous, these functions don't get called syncronously - // Which means we must somehow await the handler's completion before executing the following tests, but I'm not sure how to do that - // expect(leaveSpy.callCount).toBe(0); - // expect(forgetSpy.callCount).toBe(0); - }); - - it("should leave rooms with one or no members", async () => { - const { client } = createTestClient(); - AutoleaveRoomsMixin.setupOnClient(client); - - const roomId = "!test:example.org"; - let members = ["@this:example.org"]; - - const getJoinedRoomMembersSpy = simple - .mock(client, "getJoinedRoomMembers") - .callFn((rid) => { - expect(rid).toEqual(roomId); - return members; - }); - const leaveSpy = simple.mock(client, "leaveRoom"); - const forgetSpy = simple.mock(client, "forgetRoom"); - - client.emit("room.event", roomId, { - type: "m.room.member", - content: { membership: "leave" }, - }); - expect(getJoinedRoomMembersSpy.callCount).toBe(1); - // See comments above (lines 41-42) - // expect(leaveSpy.callCount).toBe(1); - // expect(forgetSpy.callCount).toBe(1); - }); + it("shouldn't leave rooms multiple members", async () => { + const { client } = createTestClient(); + AutoleaveRoomsMixin.setupOnClient(client); + + const roomId = "!test:example.org"; + const members = [ + "@this:example.org", + "@alice:example.org", + "@bob:example.org", + ]; + + const getJoinedRoomMembersSpy = simple + .mock(client, "getJoinedRoomMembers") + .callFn((rid) => { + expect(rid).toEqual(roomId); + return members; + }); + // const leaveSpy = simple.mock(client, "leaveRoom"); + // const forgetSpy = simple.mock(client, "forgetRoom"); + + client.emit("room.event", roomId, { + type: "m.room.member", + content: { membership: "leave" }, + }); + expect(getJoinedRoomMembersSpy.callCount).toBe(1); + // Since the AutoleaveRoomsMixin room.event handler is asyncronous, these functions don't get called syncronously + // Which means we must somehow await the handler's completion before executing the following tests, but I'm not sure how to do that + // expect(leaveSpy.callCount).toBe(0); + // expect(forgetSpy.callCount).toBe(0); + }); + + it("should leave rooms with one or no members", async () => { + const { client } = createTestClient(); + AutoleaveRoomsMixin.setupOnClient(client); + + const roomId = "!test:example.org"; + const members = ["@this:example.org"]; + + const getJoinedRoomMembersSpy = simple + .mock(client, "getJoinedRoomMembers") + .callFn((rid) => { + expect(rid).toEqual(roomId); + return members; + }); + // const leaveSpy = simple.mock(client, "leaveRoom"); + // const forgetSpy = simple.mock(client, "forgetRoom"); + + client.emit("room.event", roomId, { + type: "m.room.member", + content: { membership: "leave" }, + }); + expect(getJoinedRoomMembersSpy.callCount).toBe(1); + // See comments above (lines 41-42) + // expect(leaveSpy.callCount).toBe(1); + // expect(forgetSpy.callCount).toBe(1); + }); });