import React from 'react'; import { mount, ReactWrapper } from 'enzyme'; import { Room, PendingEventOrdering, MatrixEvent, MatrixClient } from 'matrix-js-sdk/src/matrix'; import "../../../skinned-sdk"; import * as TestUtils from '../../../test-utils'; import { MatrixClientPeg } from '../../../../src/MatrixClientPeg'; import DMRoomMap from '../../../../src/utils/DMRoomMap'; import RoomHeader from '../../../../src/components/views/rooms/RoomHeader'; import { SearchScope } from '../../../../src/components/views/rooms/SearchBar'; import { E2EStatus } from '../../../../src/utils/ShieldUtils'; import { PlaceCallType } from '../../../../src/CallHandler'; import { mkEvent } from '../../../test-utils'; import { IRoomState } from "../../../../src/components/structures/RoomView"; import RoomContext from '../../../../src/contexts/RoomContext'; describe('RoomHeader', () => { it('shows the room avatar in a room with only ourselves', () => { // When we render a non-DM room with 1 person in it const room = createRoom({ name: "X Room", isDm: false, userIds: [] }); const rendered = render(room); // Then the room's avatar is the initial of its name const initial = findSpan(rendered, ".mx_BaseAvatar_initial"); expect(initial.text()).toEqual("X"); // And there is no image avatar (because it's not set on this room) const image = findImg(rendered, ".mx_BaseAvatar_image"); expect(image.prop("src")).toEqual("data:image/png;base64,00"); }); it('shows the room avatar in a room with 2 people', () => { // When we render a non-DM room with 2 people in it const room = createRoom( { name: "Y Room", isDm: false, userIds: ["other"] }); const rendered = render(room); // Then the room's avatar is the initial of its name const initial = findSpan(rendered, ".mx_BaseAvatar_initial"); expect(initial.text()).toEqual("Y"); // And there is no image avatar (because it's not set on this room) const image = findImg(rendered, ".mx_BaseAvatar_image"); expect(image.prop("src")).toEqual("data:image/png;base64,00"); }); it('shows the room avatar in a room with >2 people', () => { // When we render a non-DM room with 3 people in it const room = createRoom({ name: "Z Room", isDm: false, userIds: ["other1", "other2"] }); const rendered = render(room); // Then the room's avatar is the initial of its name const initial = findSpan(rendered, ".mx_BaseAvatar_initial"); expect(initial.text()).toEqual("Z"); // And there is no image avatar (because it's not set on this room) const image = findImg(rendered, ".mx_BaseAvatar_image"); expect(image.prop("src")).toEqual("data:image/png;base64,00"); }); it('shows the room avatar in a DM with only ourselves', () => { // When we render a non-DM room with 1 person in it const room = createRoom({ name: "Z Room", isDm: true, userIds: [] }); const rendered = render(room); // Then the room's avatar is the initial of its name const initial = findSpan(rendered, ".mx_BaseAvatar_initial"); expect(initial.text()).toEqual("Z"); // And there is no image avatar (because it's not set on this room) const image = findImg(rendered, ".mx_BaseAvatar_image"); expect(image.prop("src")).toEqual("data:image/png;base64,00"); }); it('shows the user avatar in a DM with 2 people', () => { // Note: this is the interesting case - this is the ONLY // time we should use the user's avatar. // When we render a DM room with only 2 people in it const room = createRoom({ name: "Y Room", isDm: true, userIds: ["other"] }); const rendered = render(room); // Then we use the other user's avatar as our room's image avatar const image = findImg(rendered, ".mx_BaseAvatar_image"); expect(image.prop("src")).toEqual("http://this.is.a.url/example.org/other"); // And there is no initial avatar expect(rendered.find(".mx_BaseAvatar_initial")).toHaveLength(0); }); it('shows the room avatar in a DM with >2 people', () => { // When we render a DM room with 3 people in it const room = createRoom({ name: "Z Room", isDm: true, userIds: ["other1", "other2"] }); const rendered = render(room); // Then the room's avatar is the initial of its name const initial = findSpan(rendered, ".mx_BaseAvatar_initial"); expect(initial.text()).toEqual("Z"); // And there is no image avatar (because it's not set on this room) const image = findImg(rendered, ".mx_BaseAvatar_image"); expect(image.prop("src")).toEqual("data:image/png;base64,00"); }); it("renders call buttons normally", () => { const room = createRoom({ name: "Room", isDm: false, userIds: [] }); const wrapper = render(room); expect(wrapper.find('[aria-label="Voice call"]').hostNodes()).toHaveLength(1); expect(wrapper.find('[aria-label="Video call"]').hostNodes()).toHaveLength(1); }); it("hides call buttons when the room is tombstoned", () => { const room = createRoom({ name: "Room", isDm: false, userIds: [] }); const wrapper = render(room, { tombstone: mkEvent({ event: true, type: "m.room.tombstone", room: room.roomId, user: "@user1:server", skey: "", content: {}, ts: Date.now(), }), }); expect(wrapper.find('[aria-label="Voice call"]').hostNodes()).toHaveLength(0); expect(wrapper.find('[aria-label="Video call"]').hostNodes()).toHaveLength(0); }); }); interface IRoomCreationInfo { name: string; isDm: boolean; userIds: string[]; } function createRoom(info: IRoomCreationInfo) { TestUtils.stubClient(); const client: MatrixClient = MatrixClientPeg.get(); const roomId = '!1234567890:domain'; const userId = client.getUserId(); if (info.isDm) { client.getAccountData = (eventType) => { expect(eventType).toEqual("m.direct"); return mkDirectEvent(roomId, userId, info.userIds); }; } DMRoomMap.makeShared().start(); const room = new Room(roomId, client, userId, { pendingEventOrdering: PendingEventOrdering.Detached, }); const otherJoinEvents = []; for (const otherUserId of info.userIds) { otherJoinEvents.push(mkJoinEvent(roomId, otherUserId)); } room.currentState.setStateEvents([ mkCreationEvent(roomId, userId), mkNameEvent(roomId, userId, info.name), mkJoinEvent(roomId, userId), ...otherJoinEvents, ]); room.recalculate(); return room; } function render(room: Room, roomContext?: Partial): ReactWrapper { return mount(( {}} onForgetClick={() => {}} onCallPlaced={(_type: PlaceCallType) => {}} onAppsClick={() => {}} e2eStatus={E2EStatus.Normal} appsShown={true} searchInfo={{ searchTerm: "", searchScope: SearchScope.Room, searchCount: 0, }} /> )); } function mkCreationEvent(roomId: string, userId: string): MatrixEvent { return mkEvent({ event: true, type: "m.room.create", room: roomId, user: userId, content: { creator: userId, room_version: "5", predecessor: { room_id: "!prevroom", event_id: "$someevent", }, }, }); } function mkNameEvent( roomId: string, userId: string, name: string, ): MatrixEvent { return mkEvent({ event: true, type: "m.room.name", room: roomId, user: userId, content: { name }, }); } function mkJoinEvent(roomId: string, userId: string) { const ret = mkEvent({ event: true, type: "m.room.member", room: roomId, user: userId, content: { "membership": "join", "avatar_url": "mxc://example.org/" + userId, }, }); ret.event.state_key = userId; return ret; } function mkDirectEvent( roomId: string, userId: string, otherUsers: string[], ): MatrixEvent { const content = {}; for (const otherUserId of otherUsers) { content[otherUserId] = [roomId]; } return mkEvent({ event: true, type: "m.direct", room: roomId, user: userId, content, }); } function findSpan(wrapper: ReactWrapper, selector: string): ReactWrapper { const els = wrapper.find(selector).hostNodes(); expect(els).toHaveLength(1); return els.at(0); } function findImg(wrapper: ReactWrapper, selector: string): ReactWrapper { const els = wrapper.find(selector).hostNodes(); expect(els).toHaveLength(1); return els.at(0); }