67ea6bfa53
* Refactor room avatar event to MVVM * Cover room avatar event factory wrapper * Fix prettier * added screenshots
139 lines
4.6 KiB
TypeScript
139 lines
4.6 KiB
TypeScript
/*
|
|
* 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();
|
|
});
|
|
});
|