fix automatic DM avatar with functional members (#12157)

* fix automatic DM avatar with functional members

* add tests for functional members

* add snapshot for functional members avatar test

* update snapshot for functional members avatar test

* restore mocks after each functional members avatar test

* refactor DecoratedRoomAvatar-test

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
Co-authored-by: R Midhun Suresh <hi@midhun.dev>
This commit is contained in:
Kim Brose 2024-03-03 12:01:00 +01:00 committed by GitHub
parent 5a0537b7eb
commit 65bfc920a2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 74 additions and 7 deletions

View file

@ -29,6 +29,7 @@ import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import DMRoomMap from "../../../utils/DMRoomMap"; import DMRoomMap from "../../../utils/DMRoomMap";
import { IOOBData } from "../../../stores/ThreepidInviteStore"; import { IOOBData } from "../../../stores/ThreepidInviteStore";
import { getJoinedNonFunctionalMembers } from "../../../utils/room/getJoinedNonFunctionalMembers";
interface IProps { interface IProps {
room: Room; room: Room;
@ -158,7 +159,7 @@ export default class DecoratedRoomAvatar extends React.PureComponent<IProps, ISt
// We look at the DMRoomMap and not the tag here so that we don't exclude DMs in Favourites // We look at the DMRoomMap and not the tag here so that we don't exclude DMs in Favourites
const otherUserId = DMRoomMap.shared().getUserIdForRoomId(this.props.room.roomId); const otherUserId = DMRoomMap.shared().getUserIdForRoomId(this.props.room.roomId);
if (otherUserId && this.props.room.getJoinedMemberCount() === 2) { if (otherUserId && getJoinedNonFunctionalMembers(this.props.room).length === 2) {
// Track presence, if available // Track presence, if available
if (isPresenceEnabled(this.props.room.client)) { if (isPresenceEnabled(this.props.room.client)) {
this.dmUser = MatrixClientPeg.safeGet().getUser(otherUserId); this.dmUser = MatrixClientPeg.safeGet().getUser(otherUserId);

View file

@ -26,12 +26,24 @@ import { stubClient } from "../../../test-utils";
import DecoratedRoomAvatar from "../../../../src/components/views/avatars/DecoratedRoomAvatar"; import DecoratedRoomAvatar from "../../../../src/components/views/avatars/DecoratedRoomAvatar";
import DMRoomMap from "../../../../src/utils/DMRoomMap"; import DMRoomMap from "../../../../src/utils/DMRoomMap";
jest.mock("../../../../src/utils/presence", () => ({ isPresenceEnabled: jest.fn().mockReturnValue(true) }));
jest.mock("../../../../src/utils/room/getJoinedNonFunctionalMembers", () => ({
getJoinedNonFunctionalMembers: jest.fn().mockReturnValue([0, 1]),
}));
describe("DecoratedRoomAvatar", () => { describe("DecoratedRoomAvatar", () => {
const ROOM_ID = "roomId"; const ROOM_ID = "roomId";
let mockClient: MatrixClient; let mockClient: MatrixClient;
let room: Room; let room: Room;
function renderComponent() {
return render(<DecoratedRoomAvatar room={room} size="32px" />, {
wrapper: TooltipProvider,
});
}
beforeEach(() => { beforeEach(() => {
stubClient(); stubClient();
mockClient = mocked(MatrixClientPeg.safeGet()); mockClient = mocked(MatrixClientPeg.safeGet());
@ -39,18 +51,20 @@ describe("DecoratedRoomAvatar", () => {
room = new Room(ROOM_ID, mockClient, mockClient.getUserId() ?? "", { room = new Room(ROOM_ID, mockClient, mockClient.getUserId() ?? "", {
pendingEventOrdering: PendingEventOrdering.Detached, pendingEventOrdering: PendingEventOrdering.Detached,
}); });
});
afterEach(() => {
jest.restoreAllMocks();
});
it("shows an avatar with globe icon and tooltip for public room", async () => {
const dmRoomMap = { const dmRoomMap = {
getUserIdForRoomId: jest.fn(), getUserIdForRoomId: jest.fn(),
} as unknown as DMRoomMap; } as unknown as DMRoomMap;
jest.spyOn(DMRoomMap, "shared").mockReturnValue(dmRoomMap); jest.spyOn(DMRoomMap, "shared").mockReturnValue(dmRoomMap);
});
it("shows an avatar with globe icon and tooltip for public room", async () => {
room.getJoinRule = jest.fn().mockReturnValue(JoinRule.Public); room.getJoinRule = jest.fn().mockReturnValue(JoinRule.Public);
const { container, asFragment } = render(<DecoratedRoomAvatar room={room} size="32px" />, {
wrapper: TooltipProvider, const { container, asFragment } = renderComponent();
});
const globe = container.querySelector(".mx_DecoratedRoomAvatar_icon_globe")!; const globe = container.querySelector(".mx_DecoratedRoomAvatar_icon_globe")!;
expect(globe).toBeVisible(); expect(globe).toBeVisible();
@ -66,4 +80,31 @@ describe("DecoratedRoomAvatar", () => {
expect(asFragment()).toMatchSnapshot(); expect(asFragment()).toMatchSnapshot();
}); });
it("shows the presence indicator in a DM room that also has functional members", async () => {
const DM_USER_ID = "@bob:foo.bar";
const dmRoomMap = {
getUserIdForRoomId: () => {
return DM_USER_ID;
},
} as unknown as DMRoomMap;
jest.spyOn(DMRoomMap, "shared").mockReturnValue(dmRoomMap);
jest.spyOn(DecoratedRoomAvatar.prototype as any, "getPresenceIcon").mockImplementation(() => "ONLINE");
const { container, asFragment } = renderComponent();
const presence = container.querySelector(".mx_DecoratedRoomAvatar_icon")!;
expect(presence).toBeVisible();
await userEvent.hover(presence!);
// wait for the tooltip to open
const tooltip = await waitFor(() => {
const tooltip = document.getElementById(presence.getAttribute("aria-describedby")!);
expect(tooltip).toBeVisible();
return tooltip;
});
expect(tooltip).toHaveTextContent("Online");
expect(asFragment()).toMatchSnapshot();
});
}); });

View file

@ -24,3 +24,28 @@ exports[`DecoratedRoomAvatar shows an avatar with globe icon and tooltip for pub
</div> </div>
</DocumentFragment> </DocumentFragment>
`; `;
exports[`DecoratedRoomAvatar shows the presence indicator in a DM room that also has functional members 1`] = `
<DocumentFragment>
<div
class="mx_DecoratedRoomAvatar mx_DecoratedRoomAvatar_cutout"
>
<span
class="_avatar_k41ul_17 mx_BaseAvatar _avatar-imageless_k41ul_60"
data-color="5"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 32px;"
>
r
</span>
<div
aria-describedby="radix-1"
class="mx_DecoratedRoomAvatar_icon mx_DecoratedRoomAvatar_icon_online"
data-state="delayed-open"
tabindex="0"
/>
</div>
</DocumentFragment>
`;