Refactor room avatar event to MVVM (#33473)
* Refactor room avatar event to MVVM * Cover room avatar event factory wrapper * Fix prettier * added screenshots
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { EventType, type MatrixClient, MatrixEvent, type Room } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import Modal from "../../../src/Modal";
|
||||
import { RoomAvatarEventViewModel } from "../../../src/viewmodels/room/timeline/event-tile/RoomAvatarEventViewModel";
|
||||
|
||||
describe("RoomAvatarEventViewModel", () => {
|
||||
const roomId = "!room:example.org";
|
||||
let cli: MatrixClient;
|
||||
let room: Room;
|
||||
let mxcUrlToHttp: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
mxcUrlToHttp = jest.fn().mockReturnValue("https://example.org/_matrix/media/v3/download/avatar");
|
||||
room = {
|
||||
name: "General",
|
||||
} as unknown as Room;
|
||||
cli = {
|
||||
getRoom: jest.fn().mockReturnValue(room),
|
||||
mxcUrlToHttp,
|
||||
} as unknown as MatrixClient;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
const createEvent = (
|
||||
url?: string,
|
||||
sender = "@alice:example.org",
|
||||
eventRoomId: string | undefined = roomId,
|
||||
): MatrixEvent =>
|
||||
new MatrixEvent({
|
||||
type: EventType.RoomAvatar,
|
||||
room_id: eventRoomId,
|
||||
state_key: "",
|
||||
sender,
|
||||
content: {
|
||||
url,
|
||||
},
|
||||
});
|
||||
|
||||
it("extracts room avatar event details", () => {
|
||||
const mxEvent = createEvent("mxc://example.org/avatar");
|
||||
mxEvent.sender = { name: "Alice" } as MatrixEvent["sender"];
|
||||
|
||||
const vm = new RoomAvatarEventViewModel({ cli, mxEvent });
|
||||
|
||||
expect(vm.getSnapshot()).toEqual({
|
||||
senderDisplayName: "Alice",
|
||||
roomName: "General",
|
||||
avatarUrl: "mxc://example.org/avatar",
|
||||
lightboxLabel: "Alice changed the avatar for General",
|
||||
isRemoved: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("falls back to the sender ID when no sender member is available", () => {
|
||||
const vm = new RoomAvatarEventViewModel({ cli, mxEvent: createEvent("mxc://example.org/avatar") });
|
||||
|
||||
expect(vm.getSnapshot().senderDisplayName).toBe("@alice:example.org");
|
||||
});
|
||||
|
||||
it("marks the event as removed when no avatar URL is present", () => {
|
||||
const vm = new RoomAvatarEventViewModel({ cli, mxEvent: createEvent("") });
|
||||
|
||||
expect(vm.getSnapshot()).toMatchObject({
|
||||
avatarUrl: undefined,
|
||||
isRemoved: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("updates the snapshot when the event changes", () => {
|
||||
const vm = new RoomAvatarEventViewModel({ cli, mxEvent: createEvent("mxc://example.org/avatar") });
|
||||
const listener = jest.fn();
|
||||
vm.subscribe(listener);
|
||||
|
||||
vm.setEvent(createEvent("mxc://example.org/next", "@bob:example.org"));
|
||||
|
||||
expect(vm.getSnapshot()).toMatchObject({
|
||||
senderDisplayName: "@bob:example.org",
|
||||
avatarUrl: "mxc://example.org/next",
|
||||
isRemoved: false,
|
||||
});
|
||||
expect(listener).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("does not emit when the event-derived snapshot is unchanged", () => {
|
||||
const vm = new RoomAvatarEventViewModel({ cli, mxEvent: createEvent("mxc://example.org/avatar") });
|
||||
const listener = jest.fn();
|
||||
vm.subscribe(listener);
|
||||
|
||||
vm.setEvent(createEvent("mxc://example.org/avatar"));
|
||||
|
||||
expect(listener).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("opens the room avatar in the lightbox", () => {
|
||||
const dialogSpy = jest.spyOn(Modal, "createDialog").mockReturnValue({ close: jest.fn() } as any);
|
||||
const vm = new RoomAvatarEventViewModel({ cli, mxEvent: createEvent("mxc://example.org/avatar") });
|
||||
|
||||
vm.onAvatarClick();
|
||||
|
||||
expect(mxcUrlToHttp).toHaveBeenCalledWith(
|
||||
"mxc://example.org/avatar",
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
false,
|
||||
true,
|
||||
);
|
||||
expect(dialogSpy).toHaveBeenCalledWith(
|
||||
expect.any(Function),
|
||||
{
|
||||
src: "https://example.org/_matrix/media/v3/download/avatar",
|
||||
name: "@alice:example.org changed the avatar for General",
|
||||
},
|
||||
"mx_Dialog_lightbox",
|
||||
undefined,
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
it("does not open the lightbox when the event has no avatar URL", () => {
|
||||
const dialogSpy = jest.spyOn(Modal, "createDialog").mockReturnValue({ close: jest.fn() } as any);
|
||||
const vm = new RoomAvatarEventViewModel({ cli, mxEvent: createEvent("") });
|
||||
|
||||
vm.onAvatarClick();
|
||||
|
||||
expect(dialogSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user