Add low priority avatar decoration to room tile (#30065)
* Add avatar decoration for low priority rooms * Write tests * Remove unnecesasry step in test * Make the vm expose which decoration to render * Fix jest test * Fix broken e2e test
This commit is contained in:
@@ -8,10 +8,14 @@
|
||||
import { renderHook, waitFor } from "jest-matrix-react";
|
||||
import { JoinRule, type MatrixClient, type Room, RoomMember, User } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { useRoomAvatarViewModel } from "../../../../../src/components/viewmodels/avatars/RoomAvatarViewModel";
|
||||
import {
|
||||
AvatarBadgeDecoration,
|
||||
useRoomAvatarViewModel,
|
||||
} from "../../../../../src/components/viewmodels/avatars/RoomAvatarViewModel";
|
||||
import { createTestClient, mkStubRoom } from "../../../../test-utils";
|
||||
import DMRoomMap from "../../../../../src/utils/DMRoomMap";
|
||||
import * as PresenceIndicatorModule from "../../../../../src/components/views/avatars/WithPresenceIndicator";
|
||||
import { DefaultTagID } from "../../../../../src/stores/room-list/models";
|
||||
|
||||
jest.mock("../../../../../src/utils/room/getJoinedNonFunctionalMembers", () => ({
|
||||
getJoinedNonFunctionalMembers: jest.fn().mockReturnValue([]),
|
||||
@@ -32,35 +36,61 @@ describe("RoomAvatarViewModel", () => {
|
||||
jest.spyOn(PresenceIndicatorModule, "usePresence").mockReturnValue(null);
|
||||
});
|
||||
|
||||
it("should has hasDecoration to false", async () => {
|
||||
it("should have badgeDecoration set to LowPriority", () => {
|
||||
room.tags[DefaultTagID.LowPriority] = {};
|
||||
const { result: vm } = renderHook(() => useRoomAvatarViewModel(room));
|
||||
expect(vm.current.hasDecoration).toBe(false);
|
||||
expect(vm.current.badgeDecoration).toBe(AvatarBadgeDecoration.LowPriority);
|
||||
});
|
||||
|
||||
it("should has isVideoRoom set to true", () => {
|
||||
it("should have badgeDecoration set to VideoRoom", () => {
|
||||
jest.spyOn(room, "isCallRoom").mockReturnValue(true);
|
||||
const { result: vm } = renderHook(() => useRoomAvatarViewModel(room));
|
||||
expect(vm.current.isVideoRoom).toBe(true);
|
||||
expect(vm.current.hasDecoration).toBe(true);
|
||||
expect(vm.current.badgeDecoration).toBe(AvatarBadgeDecoration.VideoRoom);
|
||||
});
|
||||
|
||||
it("should has isPublic set to true", () => {
|
||||
it("should have badgeDecoration set to PublicRoom", () => {
|
||||
jest.spyOn(room, "getJoinRule").mockReturnValue(JoinRule.Public);
|
||||
|
||||
const { result: vm } = renderHook(() => useRoomAvatarViewModel(room));
|
||||
expect(vm.current.isPublic).toBe(true);
|
||||
expect(vm.current.hasDecoration).toBe(true);
|
||||
expect(vm.current.badgeDecoration).toBe(AvatarBadgeDecoration.PublicRoom);
|
||||
});
|
||||
|
||||
it("should set badgeDecoration based on priority", () => {
|
||||
// 1. Presence has the least priority
|
||||
const user = User.createUser("userId", matrixClient);
|
||||
const roomMember = new RoomMember(room.roomId, "userId");
|
||||
roomMember.user = user;
|
||||
jest.spyOn(PresenceIndicatorModule, "useDmMember").mockReturnValue(roomMember);
|
||||
jest.spyOn(PresenceIndicatorModule, "usePresence").mockReturnValue(PresenceIndicatorModule.Presence.Online);
|
||||
|
||||
const { result: vm1 } = renderHook(() => useRoomAvatarViewModel(room));
|
||||
expect(vm1.current.badgeDecoration).toBe(AvatarBadgeDecoration.Presence);
|
||||
|
||||
// 2. With presence and public room, presence takes precedence
|
||||
jest.spyOn(room, "getJoinRule").mockReturnValue(JoinRule.Public);
|
||||
// Render again, it's easier than mocking the event emitter.
|
||||
const { result: vm, rerender } = renderHook(() => useRoomAvatarViewModel(room));
|
||||
expect(vm.current.badgeDecoration).toBe(AvatarBadgeDecoration.PublicRoom);
|
||||
|
||||
// 3. With presence, public-room and video room, video room takes precedence
|
||||
jest.spyOn(room, "isCallRoom").mockReturnValue(true);
|
||||
rerender(room);
|
||||
expect(vm.current.badgeDecoration).toBe(AvatarBadgeDecoration.VideoRoom);
|
||||
|
||||
// 4. With presence, public room, video room and low priority, low priority takes precedence
|
||||
room.tags[DefaultTagID.LowPriority] = {};
|
||||
rerender(room);
|
||||
expect(vm.current.badgeDecoration).toBe(AvatarBadgeDecoration.LowPriority);
|
||||
});
|
||||
|
||||
it("should recompute isPublic when room changed", async () => {
|
||||
const { result: vm, rerender } = renderHook((props) => useRoomAvatarViewModel(props), { initialProps: room });
|
||||
expect(vm.current.isPublic).toBe(false);
|
||||
expect(vm.current.badgeDecoration).not.toBe(AvatarBadgeDecoration.PublicRoom);
|
||||
|
||||
const publicRoom = mkStubRoom("roomId2", "roomName2", matrixClient);
|
||||
jest.spyOn(publicRoom, "getJoinRule").mockReturnValue(JoinRule.Public);
|
||||
rerender(publicRoom);
|
||||
|
||||
await waitFor(() => expect(vm.current.isPublic).toBe(true));
|
||||
await waitFor(() => expect(vm.current.badgeDecoration).toBe(AvatarBadgeDecoration.PublicRoom));
|
||||
});
|
||||
|
||||
it("should return presence", async () => {
|
||||
|
||||
@@ -12,6 +12,7 @@ import { mocked } from "jest-mock";
|
||||
import { RoomAvatarView } from "../../../../../src/components/views/avatars/RoomAvatarView";
|
||||
import { mkStubRoom, stubClient } from "../../../../test-utils";
|
||||
import {
|
||||
AvatarBadgeDecoration,
|
||||
type RoomAvatarViewState,
|
||||
useRoomAvatarViewModel,
|
||||
} from "../../../../../src/components/viewmodels/avatars/RoomAvatarViewModel";
|
||||
@@ -19,6 +20,7 @@ import DMRoomMap from "../../../../../src/utils/DMRoomMap";
|
||||
import { Presence } from "../../../../../src/components/views/avatars/WithPresenceIndicator";
|
||||
|
||||
jest.mock("../../../../../src/components/viewmodels/avatars/RoomAvatarViewModel", () => ({
|
||||
...jest.requireActual("../../../../../src/components/viewmodels/avatars/RoomAvatarViewModel"),
|
||||
useRoomAvatarViewModel: jest.fn(),
|
||||
}));
|
||||
|
||||
@@ -33,9 +35,7 @@ describe("<RoomAvatarView />", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
defaultValue = {
|
||||
hasDecoration: true,
|
||||
isPublic: true,
|
||||
isVideoRoom: true,
|
||||
badgeDecoration: undefined,
|
||||
presence: null,
|
||||
};
|
||||
|
||||
@@ -43,13 +43,27 @@ describe("<RoomAvatarView />", () => {
|
||||
});
|
||||
|
||||
it("should not render a decoration", () => {
|
||||
mocked(useRoomAvatarViewModel).mockReturnValue({ ...defaultValue, hasDecoration: false });
|
||||
mocked(useRoomAvatarViewModel).mockReturnValue({ ...defaultValue });
|
||||
const { asFragment } = render(<RoomAvatarView room={room} />);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should render a low priority room decoration", () => {
|
||||
mocked(useRoomAvatarViewModel).mockReturnValue({
|
||||
...defaultValue,
|
||||
badgeDecoration: AvatarBadgeDecoration.LowPriority,
|
||||
});
|
||||
const { asFragment } = render(<RoomAvatarView room={room} />);
|
||||
|
||||
expect(screen.getByLabelText("This is a low priority room")).toBeInTheDocument();
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should render a video room decoration", () => {
|
||||
mocked(useRoomAvatarViewModel).mockReturnValue({ ...defaultValue, hasDecoration: true, isVideoRoom: true });
|
||||
mocked(useRoomAvatarViewModel).mockReturnValue({
|
||||
...defaultValue,
|
||||
badgeDecoration: AvatarBadgeDecoration.VideoRoom,
|
||||
});
|
||||
const { asFragment } = render(<RoomAvatarView room={room} />);
|
||||
|
||||
expect(screen.getByLabelText("This room is a video room")).toBeInTheDocument();
|
||||
@@ -59,9 +73,7 @@ describe("<RoomAvatarView />", () => {
|
||||
it("should render a public room decoration", () => {
|
||||
mocked(useRoomAvatarViewModel).mockReturnValue({
|
||||
...defaultValue,
|
||||
hasDecoration: true,
|
||||
isPublic: true,
|
||||
isVideoRoom: false,
|
||||
badgeDecoration: AvatarBadgeDecoration.PublicRoom,
|
||||
});
|
||||
const { asFragment } = render(<RoomAvatarView room={room} />);
|
||||
|
||||
@@ -69,19 +81,6 @@ describe("<RoomAvatarView />", () => {
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should not render a public room decoration if the room is a video room", () => {
|
||||
mocked(useRoomAvatarViewModel).mockReturnValue({
|
||||
...defaultValue,
|
||||
hasDecoration: true,
|
||||
isPublic: true,
|
||||
isVideoRoom: true,
|
||||
});
|
||||
render(<RoomAvatarView room={room} />);
|
||||
|
||||
expect(screen.getByLabelText("This room is a video room")).toBeInTheDocument();
|
||||
expect(screen.queryByLabelText("This room is public")).toBeNull();
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ presence: Presence.Online, label: "Online" },
|
||||
{ presence: Presence.Offline, label: "Offline" },
|
||||
@@ -90,7 +89,7 @@ describe("<RoomAvatarView />", () => {
|
||||
])("should render the $presence presence", ({ presence, label }) => {
|
||||
mocked(useRoomAvatarViewModel).mockReturnValue({
|
||||
...defaultValue,
|
||||
hasDecoration: true,
|
||||
badgeDecoration: AvatarBadgeDecoration.Presence,
|
||||
presence,
|
||||
});
|
||||
const { asFragment } = render(<RoomAvatarView room={room} />);
|
||||
|
||||
@@ -24,6 +24,48 @@ exports[`<RoomAvatarView /> should not render a decoration 1`] = `
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`<RoomAvatarView /> should render a low priority room decoration 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="mx_RoomAvatarView"
|
||||
>
|
||||
<span
|
||||
aria-label="Avatar"
|
||||
class="_avatar_1qbcf_8 mx_BaseAvatar mx_RoomAvatarView_RoomAvatar mx_RoomAvatarView_RoomAvatar_icon"
|
||||
data-color="1"
|
||||
data-testid="avatar-img"
|
||||
data-type="round"
|
||||
style="--cpd-avatar-size: 32px;"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="_image_1qbcf_41"
|
||||
data-type="round"
|
||||
height="32px"
|
||||
loading="lazy"
|
||||
referrerpolicy="no-referrer"
|
||||
src="http://this.is.a.url/avatar.url/room.png"
|
||||
width="32px"
|
||||
/>
|
||||
</span>
|
||||
<svg
|
||||
aria-label="This is a low priority room"
|
||||
class="mx_RoomAvatarView_icon"
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
fill="currentColor"
|
||||
height="16px"
|
||||
viewBox="0 0 24 24"
|
||||
width="16px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M12 4.5a1 1 0 0 1 1 1v10.586l4.293-4.293a1 1 0 0 1 1.414 1.414l-6 6a1 1 0 0 1-1.414 0l-6-6a1 1 0 1 1 1.414-1.414L11 16.086V5.5a1 1 0 0 1 1-1"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`<RoomAvatarView /> should render a public room decoration 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
@@ -115,7 +157,7 @@ exports[`<RoomAvatarView /> should render the AWAY presence 1`] = `
|
||||
>
|
||||
<span
|
||||
aria-label="Avatar"
|
||||
class="_avatar_1qbcf_8 mx_BaseAvatar mx_RoomAvatarView_RoomAvatar mx_RoomAvatarView_RoomAvatar_icon mx_RoomAvatarView_RoomAvatar_presence"
|
||||
class="_avatar_1qbcf_8 mx_BaseAvatar mx_RoomAvatarView_RoomAvatar mx_RoomAvatarView_RoomAvatar_presence"
|
||||
data-color="1"
|
||||
data-testid="avatar-img"
|
||||
data-type="round"
|
||||
@@ -132,20 +174,6 @@ exports[`<RoomAvatarView /> should render the AWAY presence 1`] = `
|
||||
width="32px"
|
||||
/>
|
||||
</span>
|
||||
<svg
|
||||
aria-label="This room is a video room"
|
||||
class="mx_RoomAvatarView_icon"
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
fill="currentColor"
|
||||
height="16px"
|
||||
viewBox="0 0 24 24"
|
||||
width="16px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M6 4h10a2 2 0 0 1 2 2v4.286l3.35-2.871a1 1 0 0 1 1.65.76v7.65a1 1 0 0 1-1.65.76L18 13.715V18a2 2 0 0 1-2 2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-label="Away"
|
||||
class="mx_RoomAvatarView_PresenceDecoration"
|
||||
@@ -184,7 +212,7 @@ exports[`<RoomAvatarView /> should render the BUSY presence 1`] = `
|
||||
>
|
||||
<span
|
||||
aria-label="Avatar"
|
||||
class="_avatar_1qbcf_8 mx_BaseAvatar mx_RoomAvatarView_RoomAvatar mx_RoomAvatarView_RoomAvatar_icon mx_RoomAvatarView_RoomAvatar_presence"
|
||||
class="_avatar_1qbcf_8 mx_BaseAvatar mx_RoomAvatarView_RoomAvatar mx_RoomAvatarView_RoomAvatar_presence"
|
||||
data-color="1"
|
||||
data-testid="avatar-img"
|
||||
data-type="round"
|
||||
@@ -201,20 +229,6 @@ exports[`<RoomAvatarView /> should render the BUSY presence 1`] = `
|
||||
width="32px"
|
||||
/>
|
||||
</span>
|
||||
<svg
|
||||
aria-label="This room is a video room"
|
||||
class="mx_RoomAvatarView_icon"
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
fill="currentColor"
|
||||
height="16px"
|
||||
viewBox="0 0 24 24"
|
||||
width="16px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M6 4h10a2 2 0 0 1 2 2v4.286l3.35-2.871a1 1 0 0 1 1.65.76v7.65a1 1 0 0 1-1.65.76L18 13.715V18a2 2 0 0 1-2 2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-label="Busy"
|
||||
class="mx_RoomAvatarView_PresenceDecoration"
|
||||
@@ -255,7 +269,7 @@ exports[`<RoomAvatarView /> should render the OFFLINE presence 1`] = `
|
||||
>
|
||||
<span
|
||||
aria-label="Avatar"
|
||||
class="_avatar_1qbcf_8 mx_BaseAvatar mx_RoomAvatarView_RoomAvatar mx_RoomAvatarView_RoomAvatar_icon mx_RoomAvatarView_RoomAvatar_presence"
|
||||
class="_avatar_1qbcf_8 mx_BaseAvatar mx_RoomAvatarView_RoomAvatar mx_RoomAvatarView_RoomAvatar_presence"
|
||||
data-color="1"
|
||||
data-testid="avatar-img"
|
||||
data-type="round"
|
||||
@@ -272,20 +286,6 @@ exports[`<RoomAvatarView /> should render the OFFLINE presence 1`] = `
|
||||
width="32px"
|
||||
/>
|
||||
</span>
|
||||
<svg
|
||||
aria-label="This room is a video room"
|
||||
class="mx_RoomAvatarView_icon"
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
fill="currentColor"
|
||||
height="16px"
|
||||
viewBox="0 0 24 24"
|
||||
width="16px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M6 4h10a2 2 0 0 1 2 2v4.286l3.35-2.871a1 1 0 0 1 1.65.76v7.65a1 1 0 0 1-1.65.76L18 13.715V18a2 2 0 0 1-2 2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-label="Offline"
|
||||
class="mx_RoomAvatarView_PresenceDecoration"
|
||||
@@ -326,7 +326,7 @@ exports[`<RoomAvatarView /> should render the ONLINE presence 1`] = `
|
||||
>
|
||||
<span
|
||||
aria-label="Avatar"
|
||||
class="_avatar_1qbcf_8 mx_BaseAvatar mx_RoomAvatarView_RoomAvatar mx_RoomAvatarView_RoomAvatar_icon mx_RoomAvatarView_RoomAvatar_presence"
|
||||
class="_avatar_1qbcf_8 mx_BaseAvatar mx_RoomAvatarView_RoomAvatar mx_RoomAvatarView_RoomAvatar_presence"
|
||||
data-color="1"
|
||||
data-testid="avatar-img"
|
||||
data-type="round"
|
||||
@@ -343,20 +343,6 @@ exports[`<RoomAvatarView /> should render the ONLINE presence 1`] = `
|
||||
width="32px"
|
||||
/>
|
||||
</span>
|
||||
<svg
|
||||
aria-label="This room is a video room"
|
||||
class="mx_RoomAvatarView_icon"
|
||||
color="var(--cpd-color-icon-tertiary)"
|
||||
fill="currentColor"
|
||||
height="16px"
|
||||
viewBox="0 0 24 24"
|
||||
width="16px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M6 4h10a2 2 0 0 1 2 2v4.286l3.35-2.871a1 1 0 0 1 1.65.76v7.65a1 1 0 0 1-1.65.76L18 13.715V18a2 2 0 0 1-2 2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
aria-label="Online"
|
||||
class="mx_RoomAvatarView_PresenceDecoration"
|
||||
|
||||
Reference in New Issue
Block a user