Wire local room logic (#9078)
* Wire local room logic * Migrate to testling-lib; update test descriptions
This commit is contained in:
parent
66f7c9f564
commit
fa1bff67cf
14 changed files with 494 additions and 12 deletions
|
@ -22,6 +22,7 @@ import { split } from "lodash";
|
||||||
|
|
||||||
import DMRoomMap from './utils/DMRoomMap';
|
import DMRoomMap from './utils/DMRoomMap';
|
||||||
import { mediaFromMxc } from "./customisations/Media";
|
import { mediaFromMxc } from "./customisations/Media";
|
||||||
|
import { isLocalRoom } from "./utils/localRoom/isLocalRoom";
|
||||||
|
|
||||||
// Not to be used for BaseAvatar urls as that has similar default avatar fallback already
|
// Not to be used for BaseAvatar urls as that has similar default avatar fallback already
|
||||||
export function avatarUrlForMember(
|
export function avatarUrlForMember(
|
||||||
|
@ -142,7 +143,12 @@ export function avatarUrlForRoom(room: Room, width: number, height: number, resi
|
||||||
if (room.isSpaceRoom()) return null;
|
if (room.isSpaceRoom()) return null;
|
||||||
|
|
||||||
// If the room is not a DM don't fallback to a member avatar
|
// If the room is not a DM don't fallback to a member avatar
|
||||||
if (!DMRoomMap.shared().getUserIdForRoomId(room.roomId)) return null;
|
if (
|
||||||
|
!DMRoomMap.shared().getUserIdForRoomId(room.roomId)
|
||||||
|
&& !(isLocalRoom(room))
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// If there are only two members in the DM use the avatar of the other member
|
// If there are only two members in the DM use the avatar of the other member
|
||||||
const otherMember = room.getAvatarFallbackMember();
|
const otherMember = room.getAvatarFallbackMember();
|
||||||
|
|
|
@ -132,6 +132,7 @@ import VideoChannelStore from "../../stores/VideoChannelStore";
|
||||||
import { IRoomStateEventsActionPayload } from "../../actions/MatrixActionCreators";
|
import { IRoomStateEventsActionPayload } from "../../actions/MatrixActionCreators";
|
||||||
import { UseCaseSelection } from '../views/elements/UseCaseSelection';
|
import { UseCaseSelection } from '../views/elements/UseCaseSelection';
|
||||||
import { ValidatedServerConfig } from '../../utils/ValidatedServerConfig';
|
import { ValidatedServerConfig } from '../../utils/ValidatedServerConfig';
|
||||||
|
import { isLocalRoom } from '../../utils/localRoom/isLocalRoom';
|
||||||
|
|
||||||
// legacy export
|
// legacy export
|
||||||
export { default as Views } from "../../Views";
|
export { default as Views } from "../../Views";
|
||||||
|
@ -890,7 +891,12 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are redirecting to a Room Alias and it is for the room we already showing then replace history item
|
// If we are redirecting to a Room Alias and it is for the room we already showing then replace history item
|
||||||
const replaceLast = presentedId[0] === "#" && roomInfo.room_id === this.state.currentRoomId;
|
let replaceLast = presentedId[0] === "#" && roomInfo.room_id === this.state.currentRoomId;
|
||||||
|
|
||||||
|
if (isLocalRoom(this.state.currentRoomId)) {
|
||||||
|
// Replace local room history items
|
||||||
|
replaceLast = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (roomInfo.room_id === this.state.currentRoomId) {
|
if (roomInfo.room_id === this.state.currentRoomId) {
|
||||||
// if we are re-viewing the same room then copy any state we already know
|
// if we are re-viewing the same room then copy any state we already know
|
||||||
|
|
|
@ -91,6 +91,7 @@ import { PublicRoomResultDetails } from "./PublicRoomResultDetails";
|
||||||
import { RoomResultContextMenus } from "./RoomResultContextMenus";
|
import { RoomResultContextMenus } from "./RoomResultContextMenus";
|
||||||
import { RoomContextDetails } from "../../rooms/RoomContextDetails";
|
import { RoomContextDetails } from "../../rooms/RoomContextDetails";
|
||||||
import { TooltipOption } from "./TooltipOption";
|
import { TooltipOption } from "./TooltipOption";
|
||||||
|
import { isLocalRoom } from "../../../../utils/localRoom/isLocalRoom";
|
||||||
|
|
||||||
const MAX_RECENT_SEARCHES = 10;
|
const MAX_RECENT_SEARCHES = 10;
|
||||||
const SECTION_LIMIT = 50; // only show 50 results per section for performance reasons
|
const SECTION_LIMIT = 50; // only show 50 results per section for performance reasons
|
||||||
|
@ -243,6 +244,9 @@ export const useWebSearchMetrics = (numResults: number, queryLength: number, via
|
||||||
|
|
||||||
const findVisibleRooms = (cli: MatrixClient) => {
|
const findVisibleRooms = (cli: MatrixClient) => {
|
||||||
return cli.getVisibleRooms().filter(room => {
|
return cli.getVisibleRooms().filter(room => {
|
||||||
|
// Do not show local rooms
|
||||||
|
if (isLocalRoom(room)) return false;
|
||||||
|
|
||||||
// TODO we may want to put invites in their own list
|
// TODO we may want to put invites in their own list
|
||||||
return room.getMyMembership() === "join" || room.getMyMembership() == "invite";
|
return room.getMyMembership() === "join" || room.getMyMembership() == "invite";
|
||||||
});
|
});
|
||||||
|
@ -395,7 +399,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
|
||||||
|
|
||||||
possibleResults.forEach(entry => {
|
possibleResults.forEach(entry => {
|
||||||
if (isRoomResult(entry)) {
|
if (isRoomResult(entry)) {
|
||||||
if (!entry.room.normalizedName.includes(normalizedQuery) &&
|
if (!entry.room.normalizedName?.includes(normalizedQuery) &&
|
||||||
!entry.room.getCanonicalAlias()?.toLowerCase().includes(lcQuery) &&
|
!entry.room.getCanonicalAlias()?.toLowerCase().includes(lcQuery) &&
|
||||||
!entry.query?.some(q => q.includes(lcQuery))
|
!entry.query?.some(q => q.includes(lcQuery))
|
||||||
) return; // bail, does not match query
|
) return; // bail, does not match query
|
||||||
|
|
|
@ -24,6 +24,7 @@ import EventTileBubble from "./EventTileBubble";
|
||||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||||
import DMRoomMap from "../../../utils/DMRoomMap";
|
import DMRoomMap from "../../../utils/DMRoomMap";
|
||||||
import { objectHasDiff } from "../../../utils/objects";
|
import { objectHasDiff } from "../../../utils/objects";
|
||||||
|
import { isLocalRoom } from '../../../utils/localRoom/isLocalRoom';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
mxEvent: MatrixEvent;
|
mxEvent: MatrixEvent;
|
||||||
|
@ -46,12 +47,15 @@ const EncryptionEvent = forwardRef<HTMLDivElement, IProps>(({ mxEvent, timestamp
|
||||||
if (content.algorithm === ALGORITHM && isRoomEncrypted) {
|
if (content.algorithm === ALGORITHM && isRoomEncrypted) {
|
||||||
let subtitle: string;
|
let subtitle: string;
|
||||||
const dmPartner = DMRoomMap.shared().getUserIdForRoomId(roomId);
|
const dmPartner = DMRoomMap.shared().getUserIdForRoomId(roomId);
|
||||||
|
const room = cli?.getRoom(roomId);
|
||||||
if (prevContent.algorithm === ALGORITHM) {
|
if (prevContent.algorithm === ALGORITHM) {
|
||||||
subtitle = _t("Some encryption parameters have been changed.");
|
subtitle = _t("Some encryption parameters have been changed.");
|
||||||
} else if (dmPartner) {
|
} else if (dmPartner) {
|
||||||
const displayName = cli?.getRoom(roomId)?.getMember(dmPartner)?.rawDisplayName || dmPartner;
|
const displayName = room.getMember(dmPartner)?.rawDisplayName || dmPartner;
|
||||||
subtitle = _t("Messages here are end-to-end encrypted. " +
|
subtitle = _t("Messages here are end-to-end encrypted. " +
|
||||||
"Verify %(displayName)s in their profile - tap on their avatar.", { displayName });
|
"Verify %(displayName)s in their profile - tap on their avatar.", { displayName });
|
||||||
|
} else if (isLocalRoom(room)) {
|
||||||
|
subtitle = _t("Messages in this chat will be end-to-end encrypted.");
|
||||||
} else {
|
} else {
|
||||||
subtitle = _t("Messages in this room are end-to-end encrypted. " +
|
subtitle = _t("Messages in this room are end-to-end encrypted. " +
|
||||||
"When people join, you can verify them in their profile, just tap on their avatar.");
|
"When people join, you can verify them in their profile, just tap on their avatar.");
|
||||||
|
|
|
@ -2101,6 +2101,7 @@
|
||||||
"View Source": "View Source",
|
"View Source": "View Source",
|
||||||
"Some encryption parameters have been changed.": "Some encryption parameters have been changed.",
|
"Some encryption parameters have been changed.": "Some encryption parameters have been changed.",
|
||||||
"Messages here are end-to-end encrypted. Verify %(displayName)s in their profile - tap on their avatar.": "Messages here are end-to-end encrypted. Verify %(displayName)s in their profile - tap on their avatar.",
|
"Messages here are end-to-end encrypted. Verify %(displayName)s in their profile - tap on their avatar.": "Messages here are end-to-end encrypted. Verify %(displayName)s in their profile - tap on their avatar.",
|
||||||
|
"Messages in this chat will be end-to-end encrypted.": "Messages in this chat will be end-to-end encrypted.",
|
||||||
"Messages in this room are end-to-end encrypted. When people join, you can verify them in their profile, just tap on their avatar.": "Messages in this room are end-to-end encrypted. When people join, you can verify them in their profile, just tap on their avatar.",
|
"Messages in this room are end-to-end encrypted. When people join, you can verify them in their profile, just tap on their avatar.": "Messages in this room are end-to-end encrypted. When people join, you can verify them in their profile, just tap on their avatar.",
|
||||||
"Encryption enabled": "Encryption enabled",
|
"Encryption enabled": "Encryption enabled",
|
||||||
"Ignored attempt to disable encryption": "Ignored attempt to disable encryption",
|
"Ignored attempt to disable encryption": "Ignored attempt to disable encryption",
|
||||||
|
|
|
@ -16,6 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
import { MatrixClientPeg } from "../MatrixClientPeg";
|
import { MatrixClientPeg } from "../MatrixClientPeg";
|
||||||
import SettingsStore from "../settings/SettingsStore";
|
import SettingsStore from "../settings/SettingsStore";
|
||||||
|
import { isLocalRoom } from "../utils/localRoom/isLocalRoom";
|
||||||
import Timer from "../utils/Timer";
|
import Timer from "../utils/Timer";
|
||||||
|
|
||||||
const TYPING_USER_TIMEOUT = 10000;
|
const TYPING_USER_TIMEOUT = 10000;
|
||||||
|
@ -64,6 +65,9 @@ export default class TypingStore {
|
||||||
* @param {boolean} isTyping Whether the user is typing or not.
|
* @param {boolean} isTyping Whether the user is typing or not.
|
||||||
*/
|
*/
|
||||||
public setSelfTyping(roomId: string, threadId: string | null, isTyping: boolean): void {
|
public setSelfTyping(roomId: string, threadId: string | null, isTyping: boolean): void {
|
||||||
|
// No typing notifications for local rooms
|
||||||
|
if (isLocalRoom(roomId)) return;
|
||||||
|
|
||||||
if (!SettingsStore.getValue('sendTypingNotifications')) return;
|
if (!SettingsStore.getValue('sendTypingNotifications')) return;
|
||||||
if (SettingsStore.getValue('lowBandwidth')) return;
|
if (SettingsStore.getValue('lowBandwidth')) return;
|
||||||
// Disable typing notification for threads for the initial launch
|
// Disable typing notification for threads for the initial launch
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
|
||||||
import CallHandler from "../../../CallHandler";
|
import CallHandler from "../../../CallHandler";
|
||||||
import { RoomListCustomisations } from "../../../customisations/RoomList";
|
import { RoomListCustomisations } from "../../../customisations/RoomList";
|
||||||
import { LocalRoom } from "../../../models/LocalRoom";
|
import { isLocalRoom } from "../../../utils/localRoom/isLocalRoom";
|
||||||
import VoipUserMapper from "../../../VoipUserMapper";
|
import VoipUserMapper from "../../../VoipUserMapper";
|
||||||
|
|
||||||
export class VisibilityProvider {
|
export class VisibilityProvider {
|
||||||
|
@ -55,7 +55,7 @@ export class VisibilityProvider {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (room instanceof LocalRoom) {
|
if (isLocalRoom(room)) {
|
||||||
// local rooms shouldn't show up anywhere
|
// local rooms shouldn't show up anywhere
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
26
src/utils/localRoom/isLocalRoom.ts
Normal file
26
src/utils/localRoom/isLocalRoom.ts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Room } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
|
import { LocalRoom, LOCAL_ROOM_ID_PREFIX } from "../../models/LocalRoom";
|
||||||
|
|
||||||
|
export function isLocalRoom(roomOrID: Room|string): boolean {
|
||||||
|
if (typeof roomOrID === "string") {
|
||||||
|
return roomOrID.startsWith(LOCAL_ROOM_ID_PREFIX);
|
||||||
|
}
|
||||||
|
return roomOrID instanceof LocalRoom;
|
||||||
|
}
|
102
test/Avatar-test.ts
Normal file
102
test/Avatar-test.ts
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { mocked } from "jest-mock";
|
||||||
|
import { Room, RoomMember } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
|
import { avatarUrlForRoom } from "../src/Avatar";
|
||||||
|
import { Media, mediaFromMxc } from "../src/customisations/Media";
|
||||||
|
import DMRoomMap from "../src/utils/DMRoomMap";
|
||||||
|
|
||||||
|
jest.mock("../src/customisations/Media", () => ({
|
||||||
|
mediaFromMxc: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const roomId = "!room:example.com";
|
||||||
|
const avatarUrl1 = "https://example.com/avatar1";
|
||||||
|
const avatarUrl2 = "https://example.com/avatar2";
|
||||||
|
|
||||||
|
describe("avatarUrlForRoom", () => {
|
||||||
|
let getThumbnailOfSourceHttp: jest.Mock;
|
||||||
|
let room: Room;
|
||||||
|
let roomMember: RoomMember;
|
||||||
|
let dmRoomMap: DMRoomMap;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
getThumbnailOfSourceHttp = jest.fn();
|
||||||
|
mocked(mediaFromMxc).mockImplementation((): Media => {
|
||||||
|
return {
|
||||||
|
getThumbnailOfSourceHttp,
|
||||||
|
} as unknown as Media;
|
||||||
|
});
|
||||||
|
room = {
|
||||||
|
roomId,
|
||||||
|
getMxcAvatarUrl: jest.fn(),
|
||||||
|
isSpaceRoom: jest.fn(),
|
||||||
|
getAvatarFallbackMember: jest.fn(),
|
||||||
|
} as unknown as Room;
|
||||||
|
dmRoomMap = {
|
||||||
|
getUserIdForRoomId: jest.fn(),
|
||||||
|
} as unknown as DMRoomMap;
|
||||||
|
DMRoomMap.setShared(dmRoomMap);
|
||||||
|
roomMember = {
|
||||||
|
getMxcAvatarUrl: jest.fn(),
|
||||||
|
} as unknown as RoomMember;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return null for a null room", () => {
|
||||||
|
expect(avatarUrlForRoom(null, 128, 128)).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return the HTTP source if the room provides a MXC url", () => {
|
||||||
|
mocked(room.getMxcAvatarUrl).mockReturnValue(avatarUrl1);
|
||||||
|
getThumbnailOfSourceHttp.mockReturnValue(avatarUrl2);
|
||||||
|
expect(avatarUrlForRoom(room, 128, 256, "crop")).toEqual(avatarUrl2);
|
||||||
|
expect(getThumbnailOfSourceHttp).toHaveBeenCalledWith(128, 256, "crop");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return null for a space room", () => {
|
||||||
|
mocked(room.isSpaceRoom).mockReturnValue(true);
|
||||||
|
expect(avatarUrlForRoom(room, 128, 128)).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return null if the room is not a DM", () => {
|
||||||
|
mocked(dmRoomMap).getUserIdForRoomId.mockReturnValue(null);
|
||||||
|
expect(avatarUrlForRoom(room, 128, 128)).toBeNull();
|
||||||
|
expect(dmRoomMap.getUserIdForRoomId).toHaveBeenCalledWith(roomId);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return null if there is no other member in the room", () => {
|
||||||
|
mocked(dmRoomMap).getUserIdForRoomId.mockReturnValue("@user:example.com");
|
||||||
|
mocked(room.getAvatarFallbackMember).mockReturnValue(null);
|
||||||
|
expect(avatarUrlForRoom(room, 128, 128)).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return null if the other member has no avatar URL", () => {
|
||||||
|
mocked(dmRoomMap).getUserIdForRoomId.mockReturnValue("@user:example.com");
|
||||||
|
mocked(room.getAvatarFallbackMember).mockReturnValue(roomMember);
|
||||||
|
expect(avatarUrlForRoom(room, 128, 128)).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return the other member's avatar URL", () => {
|
||||||
|
mocked(dmRoomMap).getUserIdForRoomId.mockReturnValue("@user:example.com");
|
||||||
|
mocked(room.getAvatarFallbackMember).mockReturnValue(roomMember);
|
||||||
|
mocked(roomMember.getMxcAvatarUrl).mockReturnValue(avatarUrl2);
|
||||||
|
getThumbnailOfSourceHttp.mockReturnValue(avatarUrl2);
|
||||||
|
expect(avatarUrlForRoom(room, 128, 256, "crop")).toEqual(avatarUrl2);
|
||||||
|
expect(getThumbnailOfSourceHttp).toHaveBeenCalledWith(128, 256, "crop");
|
||||||
|
});
|
||||||
|
});
|
|
@ -14,8 +14,9 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { mount } from "enzyme";
|
import { mount, ReactWrapper } from "enzyme";
|
||||||
import { IProtocol, IPublicRoomsChunkRoom, MatrixClient, RoomMember } from "matrix-js-sdk/src/matrix";
|
import { mocked } from "jest-mock";
|
||||||
|
import { IProtocol, IPublicRoomsChunkRoom, MatrixClient, Room, RoomMember } from "matrix-js-sdk/src/matrix";
|
||||||
import { sleep } from "matrix-js-sdk/src/utils";
|
import { sleep } from "matrix-js-sdk/src/utils";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { act } from "react-dom/test-utils";
|
import { act } from "react-dom/test-utils";
|
||||||
|
@ -23,7 +24,15 @@ import sanitizeHtml from "sanitize-html";
|
||||||
|
|
||||||
import SpotlightDialog, { Filter } from "../../../../src/components/views/dialogs/spotlight/SpotlightDialog";
|
import SpotlightDialog, { Filter } from "../../../../src/components/views/dialogs/spotlight/SpotlightDialog";
|
||||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||||
import { stubClient } from "../../../test-utils";
|
import { LocalRoom, LOCAL_ROOM_ID_PREFIX } from "../../../../src/models/LocalRoom";
|
||||||
|
import DMRoomMap from "../../../../src/utils/DMRoomMap";
|
||||||
|
import { mkRoom, stubClient } from "../../../test-utils";
|
||||||
|
|
||||||
|
jest.mock("../../../../src/utils/direct-messages", () => ({
|
||||||
|
// @ts-ignore
|
||||||
|
...jest.requireActual("../../../../src/utils/direct-messages"),
|
||||||
|
startDmOnFirstMessage: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
interface IUserChunkMember {
|
interface IUserChunkMember {
|
||||||
user_id: string;
|
user_id: string;
|
||||||
|
@ -110,10 +119,23 @@ describe("Spotlight Dialog", () => {
|
||||||
guest_can_join: false,
|
guest_can_join: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
let testRoom: Room;
|
||||||
mockClient({ rooms: [testPublicRoom], users: [testPerson] });
|
let testLocalRoom: LocalRoom;
|
||||||
});
|
|
||||||
|
|
||||||
|
let mockedClient: MatrixClient;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mockedClient = mockClient({ rooms: [testPublicRoom], users: [testPerson] });
|
||||||
|
testRoom = mkRoom(mockedClient, "!test23:example.com");
|
||||||
|
mocked(testRoom.getMyMembership).mockReturnValue("join");
|
||||||
|
testLocalRoom = new LocalRoom(LOCAL_ROOM_ID_PREFIX + "test23", mockedClient, mockedClient.getUserId());
|
||||||
|
testLocalRoom.updateMyMembership("join");
|
||||||
|
mocked(mockedClient.getVisibleRooms).mockReturnValue([testRoom, testLocalRoom]);
|
||||||
|
|
||||||
|
jest.spyOn(DMRoomMap, "shared").mockReturnValue({
|
||||||
|
getUserIdForRoomId: jest.fn(),
|
||||||
|
} as unknown as DMRoomMap);
|
||||||
|
});
|
||||||
describe("should apply filters supplied via props", () => {
|
describe("should apply filters supplied via props", () => {
|
||||||
it("without filter", async () => {
|
it("without filter", async () => {
|
||||||
const wrapper = mount(
|
const wrapper = mount(
|
||||||
|
@ -289,4 +311,38 @@ describe("Spotlight Dialog", () => {
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("searching for rooms", () => {
|
||||||
|
let wrapper: ReactWrapper;
|
||||||
|
let options: ReactWrapper;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
wrapper = mount(
|
||||||
|
<SpotlightDialog
|
||||||
|
initialText="test23"
|
||||||
|
onFinished={() => null} />,
|
||||||
|
);
|
||||||
|
await act(async () => {
|
||||||
|
await sleep(200);
|
||||||
|
});
|
||||||
|
wrapper.update();
|
||||||
|
|
||||||
|
const content = wrapper.find("#mx_SpotlightDialog_content");
|
||||||
|
options = content.find("div.mx_SpotlightDialog_option");
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should find Rooms", () => {
|
||||||
|
expect(options.length).toBe(3);
|
||||||
|
expect(options.first().text()).toContain(testRoom.name);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not find LocalRooms", () => {
|
||||||
|
expect(options.length).toBe(3);
|
||||||
|
expect(options.first().text()).not.toContain(testLocalRoom.name);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
131
test/components/views/messages/EncryptionEvent-test.tsx
Normal file
131
test/components/views/messages/EncryptionEvent-test.tsx
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { mocked } from "jest-mock";
|
||||||
|
import { MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
|
||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
|
||||||
|
import EncryptionEvent from "../../../../src/components/views/messages/EncryptionEvent";
|
||||||
|
import { createTestClient, mkMessage } from "../../../test-utils";
|
||||||
|
import { MatrixClientPeg } from '../../../../src/MatrixClientPeg';
|
||||||
|
import { LocalRoom } from '../../../../src/models/LocalRoom';
|
||||||
|
import DMRoomMap from '../../../../src/utils/DMRoomMap';
|
||||||
|
import MatrixClientContext from '../../../../src/contexts/MatrixClientContext';
|
||||||
|
|
||||||
|
const renderEncryptionEvent = (client: MatrixClient, event: MatrixEvent) => {
|
||||||
|
render(<MatrixClientContext.Provider value={client}>
|
||||||
|
<EncryptionEvent mxEvent={event} />
|
||||||
|
</MatrixClientContext.Provider>);
|
||||||
|
};
|
||||||
|
|
||||||
|
const checkTexts = (title: string, subTitle: string) => {
|
||||||
|
screen.getByText(title);
|
||||||
|
screen.getByText(subTitle);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("EncryptionEvent", () => {
|
||||||
|
const roomId = "!room:example.com";
|
||||||
|
const algorithm = "m.megolm.v1.aes-sha2";
|
||||||
|
let client: MatrixClient;
|
||||||
|
let event: MatrixEvent;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
client = createTestClient();
|
||||||
|
jest.spyOn(MatrixClientPeg, "get").mockReturnValue(client);
|
||||||
|
event = mkMessage({
|
||||||
|
event: true,
|
||||||
|
room: roomId,
|
||||||
|
user: client.getUserId(),
|
||||||
|
});
|
||||||
|
jest.spyOn(DMRoomMap, "shared").mockReturnValue({
|
||||||
|
getUserIdForRoomId: jest.fn(),
|
||||||
|
} as unknown as DMRoomMap);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("for an encrypted room", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
event.event.content.algorithm = algorithm;
|
||||||
|
mocked(client.isRoomEncrypted).mockReturnValue(true);
|
||||||
|
const room = new Room(roomId, client, client.getUserId());
|
||||||
|
mocked(client.getRoom).mockReturnValue(room);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show the expected texts", () => {
|
||||||
|
renderEncryptionEvent(client, event);
|
||||||
|
checkTexts(
|
||||||
|
"Encryption enabled",
|
||||||
|
"Messages in this room are end-to-end encrypted. "
|
||||||
|
+ "When people join, you can verify them in their profile, just tap on their avatar.",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("with same previous algorithm", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.spyOn(event, "getPrevContent").mockReturnValue({
|
||||||
|
algorithm: algorithm,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show the expected texts", () => {
|
||||||
|
renderEncryptionEvent(client, event);
|
||||||
|
checkTexts(
|
||||||
|
"Encryption enabled",
|
||||||
|
"Some encryption parameters have been changed.",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("with unknown algorithm", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
event.event.content.algorithm = "unknown";
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show the expected texts", () => {
|
||||||
|
renderEncryptionEvent(client, event);
|
||||||
|
checkTexts("Encryption enabled", "Ignored attempt to disable encryption");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("for an unencrypted room", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mocked(client.isRoomEncrypted).mockReturnValue(false);
|
||||||
|
renderEncryptionEvent(client, event);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show the expected texts", () => {
|
||||||
|
expect(client.isRoomEncrypted).toHaveBeenCalledWith(roomId);
|
||||||
|
checkTexts("Encryption not enabled", "The encryption used by this room isn't supported.");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("for an encrypted local room", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
event.event.content.algorithm = algorithm;
|
||||||
|
mocked(client.isRoomEncrypted).mockReturnValue(true);
|
||||||
|
const localRoom = new LocalRoom(roomId, client, client.getUserId());
|
||||||
|
mocked(client.getRoom).mockReturnValue(localRoom);
|
||||||
|
renderEncryptionEvent(client, event);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show the expected texts", () => {
|
||||||
|
expect(client.isRoomEncrypted).toHaveBeenCalledWith(roomId);
|
||||||
|
checkTexts("Encryption enabled", "Messages in this chat will be end-to-end encrypted.");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
88
test/stores/TypingStore-test.ts
Normal file
88
test/stores/TypingStore-test.ts
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { mocked } from "jest-mock";
|
||||||
|
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
|
import { MatrixClientPeg } from "../../src/MatrixClientPeg";
|
||||||
|
import TypingStore from "../../src/stores/TypingStore";
|
||||||
|
import { LOCAL_ROOM_ID_PREFIX } from "../../src/models/LocalRoom";
|
||||||
|
import SettingsStore from "../../src/settings/SettingsStore";
|
||||||
|
|
||||||
|
jest.mock("../../src/settings/SettingsStore", () => ({
|
||||||
|
getValue: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("TypingStore", () => {
|
||||||
|
let typingStore: TypingStore;
|
||||||
|
let mockClient: MatrixClient;
|
||||||
|
const settings = {
|
||||||
|
"sendTypingNotifications": true,
|
||||||
|
"feature_thread": false,
|
||||||
|
};
|
||||||
|
const roomId = "!test:example.com";
|
||||||
|
const localRoomId = LOCAL_ROOM_ID_PREFIX + "test";
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
typingStore = new TypingStore();
|
||||||
|
mockClient = {
|
||||||
|
sendTyping: jest.fn(),
|
||||||
|
} as unknown as MatrixClient;
|
||||||
|
MatrixClientPeg.get = () => mockClient;
|
||||||
|
mocked(SettingsStore.getValue).mockImplementation((setting: string) => {
|
||||||
|
return settings[setting];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("setSelfTyping", () => {
|
||||||
|
it("shouldn't do anything for a local room", () => {
|
||||||
|
typingStore.setSelfTyping(localRoomId, null, true);
|
||||||
|
expect(mockClient.sendTyping).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("in typing state true", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
typingStore.setSelfTyping(roomId, null, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should change to false when setting false", () => {
|
||||||
|
typingStore.setSelfTyping(roomId, null, false);
|
||||||
|
expect(mockClient.sendTyping).toHaveBeenCalledWith(roomId, false, 30000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should change to true when setting true", () => {
|
||||||
|
typingStore.setSelfTyping(roomId, null, true);
|
||||||
|
expect(mockClient.sendTyping).toHaveBeenCalledWith(roomId, true, 30000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("in typing state false", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
typingStore.setSelfTyping(roomId, null, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shouldn't change when setting false", () => {
|
||||||
|
typingStore.setSelfTyping(roomId, null, false);
|
||||||
|
expect(mockClient.sendTyping).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should change to true when setting true", () => {
|
||||||
|
typingStore.setSelfTyping(roomId, null, true);
|
||||||
|
expect(mockClient.sendTyping).toHaveBeenCalledWith(roomId, true, 30000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -31,6 +31,7 @@ import {
|
||||||
IEventRelation,
|
IEventRelation,
|
||||||
IUnsigned,
|
IUnsigned,
|
||||||
} from 'matrix-js-sdk/src/matrix';
|
} from 'matrix-js-sdk/src/matrix';
|
||||||
|
import { normalize } from "matrix-js-sdk/src/utils";
|
||||||
|
|
||||||
import { MatrixClientPeg as peg } from '../../src/MatrixClientPeg';
|
import { MatrixClientPeg as peg } from '../../src/MatrixClientPeg';
|
||||||
import dis from '../../src/dispatcher/dispatcher';
|
import dis from '../../src/dispatcher/dispatcher';
|
||||||
|
@ -389,6 +390,7 @@ export function mkStubRoom(roomId: string = null, name: string, client: MatrixCl
|
||||||
removeListener: jest.fn(),
|
removeListener: jest.fn(),
|
||||||
getDMInviter: jest.fn(),
|
getDMInviter: jest.fn(),
|
||||||
name,
|
name,
|
||||||
|
normalizedName: normalize(name || ""),
|
||||||
getAvatarUrl: () => 'mxc://avatar.url/room.png',
|
getAvatarUrl: () => 'mxc://avatar.url/room.png',
|
||||||
getMxcAvatarUrl: () => 'mxc://avatar.url/room.png',
|
getMxcAvatarUrl: () => 'mxc://avatar.url/room.png',
|
||||||
isSpaceRoom: jest.fn().mockReturnValue(false),
|
isSpaceRoom: jest.fn().mockReturnValue(false),
|
||||||
|
|
52
test/utils/localRoom/isLocalRoom-test.ts
Normal file
52
test/utils/localRoom/isLocalRoom-test.ts
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Room } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
|
import { LocalRoom, LOCAL_ROOM_ID_PREFIX } from "../../../src/models/LocalRoom";
|
||||||
|
import { isLocalRoom } from "../../../src/utils/localRoom/isLocalRoom";
|
||||||
|
import { createTestClient } from "../../test-utils";
|
||||||
|
|
||||||
|
describe("isLocalRoom", () => {
|
||||||
|
let room: Room;
|
||||||
|
let localRoom: LocalRoom;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const client = createTestClient();
|
||||||
|
room = new Room("!room:example.com", client, client.getUserId());
|
||||||
|
localRoom = new LocalRoom(LOCAL_ROOM_ID_PREFIX + "test", client, client.getUserId());
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return false for null", () => {
|
||||||
|
expect(isLocalRoom(null)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return false for a Room", () => {
|
||||||
|
expect(isLocalRoom(room)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return false for a non-local room ID", () => {
|
||||||
|
expect(isLocalRoom(room.roomId)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return true for LocalRoom", () => {
|
||||||
|
expect(isLocalRoom(localRoom)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return true for local room ID", () => {
|
||||||
|
expect(isLocalRoom(LOCAL_ROOM_ID_PREFIX + "test")).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Add table
Add a link
Reference in a new issue