1
0
mirror of https://github.com/element-hq/element-web.git synced 2025-08-08 03:42:14 +03:00
Files
element-web/test/unit-tests/components/viewmodels/right_panel/user_info/UserInfoHeaderViewModel-test.tsx
Marc 0a97cbaada MVVM userinfo: split header and verification components (#30214)
* feat: mvvm userinfo split header and verification

* test: add userinfoheader tests

* fix: userHeaderVerificationView verification method
2025-07-21 12:04:50 +00:00

180 lines
7.0 KiB
TypeScript

/*
Copyright 2025 New Vector 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 { type MatrixClient, RoomMember } from "matrix-js-sdk/src/matrix";
import { mocked, type Mocked } from "jest-mock";
import { type CryptoApi } from "matrix-js-sdk/src/crypto-api";
import { renderHook } from "jest-matrix-react";
import { withClientContextRenderOptions } from "../../../../../test-utils";
import { MatrixClientPeg } from "../../../../../../src/MatrixClientPeg";
import { useUserfoHeaderViewModel } from "../../../../../../src/components/viewmodels/right_panel/user_info/UserInfoHeaderViewModel";
import * as UseTimezone from "../../../../../../src/hooks/useUserTimezone";
import SdkConfig from "../../../../../../src/SdkConfig";
import Modal from "../../../../../../src/Modal";
import ImageView from "../../../../../../src/components/views/elements/ImageView";
import * as Media from "../../../../../../src/customisations/Media";
import { type IConfigOptions } from "../../../../../../src/IConfigOptions";
jest.mock("../../../../../../src/customisations/UserIdentifier", () => {
return {
getDisplayUserIdentifier: jest.fn().mockReturnValue("customUserIdentifier"),
};
});
describe("useUserInfoHeaderViewModel", () => {
const defaultRoomId = "!fkfk";
const defaultUserId = "@user:example.com";
const defaultMember = new RoomMember(defaultRoomId, defaultUserId);
const defaultProps = {
member: defaultMember,
roomId: defaultRoomId,
};
let mockClient: Mocked<MatrixClient>;
let mockCrypto: Mocked<CryptoApi>;
const mockAvatarUrl = "mock-avatar-url";
const oldGet = SdkConfig.get;
beforeEach(() => {
mockCrypto = mocked({
getDeviceVerificationStatus: jest.fn(),
getUserDeviceInfo: jest.fn(),
userHasCrossSigningKeys: jest.fn().mockResolvedValue(false),
getUserVerificationStatus: jest.fn(),
isEncryptionEnabledInRoom: jest.fn().mockResolvedValue(false),
} as unknown as CryptoApi);
mockClient = mocked({
getUser: jest.fn(),
isGuest: jest.fn().mockReturnValue(false),
isUserIgnored: jest.fn(),
getIgnoredUsers: jest.fn(),
setIgnoredUsers: jest.fn(),
getUserId: jest.fn(),
getSafeUserId: jest.fn(),
getDomain: jest.fn(),
on: jest.fn(),
off: jest.fn(),
isSynapseAdministrator: jest.fn().mockResolvedValue(false),
doesServerSupportUnstableFeature: jest.fn().mockReturnValue(false),
doesServerSupportExtendedProfiles: jest.fn().mockResolvedValue(false),
getExtendedProfileProperty: jest.fn().mockRejectedValue(new Error("Not supported")),
mxcUrlToHttp: jest.fn().mockReturnValue(mockAvatarUrl),
removeListener: jest.fn(),
currentState: {
on: jest.fn(),
},
getRoom: jest.fn(),
credentials: {},
setPowerLevel: jest.fn(),
getCrypto: jest.fn().mockReturnValue(mockCrypto),
baseUrl: "homeserver.url",
} as unknown as MatrixClient);
jest.spyOn(MatrixClientPeg, "get").mockReturnValue(mockClient);
jest.spyOn(MatrixClientPeg, "safeGet").mockReturnValue(mockClient);
});
afterEach(() => {
jest.restoreAllMocks();
});
const renderUserInfoHeaderViewModelHook = (props = defaultProps) => {
return renderHook(() => useUserfoHeaderViewModel(props), withClientContextRenderOptions(mockClient));
};
it("should give user timezone info", () => {
const defaultTZ = { timezone: "FR", friendly: "fr" };
jest.spyOn(UseTimezone, "useUserTimezone").mockReturnValue(defaultTZ);
const { result } = renderUserInfoHeaderViewModelHook();
const timezone = result.current.timezoneInfo;
expect(UseTimezone.useUserTimezone).toHaveBeenCalledWith(mockClient, defaultMember.userId);
expect(timezone).toEqual(defaultTZ);
});
it("should give correct showPresence value based on enablePresenceByHsUrl", () => {
jest.spyOn(SdkConfig, "get").mockImplementation((key: string) => {
if (key === "enable_presence_by_hs_url") {
return {
[mockClient.baseUrl]: false,
};
}
return oldGet(key as keyof IConfigOptions);
});
const { result } = renderUserInfoHeaderViewModelHook();
const showPresence = result.current.showPresence;
expect(showPresence).toBeFalsy();
});
it("should have default value true for showPresence", () => {
jest.spyOn(SdkConfig, "get").mockImplementation(() => false);
const { result } = renderUserInfoHeaderViewModelHook();
const showPresence = result.current.showPresence;
expect(showPresence).toBeTruthy();
});
it("should open image dialog when avatar is clicked", () => {
const props = Object.assign({}, defaultProps);
const spyModale = jest.spyOn(Modal, "createDialog");
const spyMedia = jest.spyOn(Media, "mediaFromMxc");
jest.spyOn(props.member, "getMxcAvatarUrl").mockReturnValue(mockAvatarUrl);
const { result } = renderUserInfoHeaderViewModelHook(props);
result.current.onMemberAvatarClick();
expect(spyModale).toHaveBeenCalledWith(
ImageView,
{
src: mockAvatarUrl,
name: defaultMember.name,
},
"mx_Dialog_lightbox",
undefined,
true,
);
expect(spyMedia).toHaveBeenCalledWith(mockAvatarUrl);
});
it("should not open image dialog when avatar url is null", () => {
const props = Object.assign({}, defaultProps);
const spyModale = jest.spyOn(Modal, "createDialog");
jest.spyOn(props.member, "getMxcAvatarUrl").mockReturnValue(mockAvatarUrl);
jest.spyOn(Media, "mediaFromMxc").mockReturnValue({
srcHttp: null,
isEncrypted: false,
srcMxc: "",
thumbnailMxc: undefined,
hasThumbnail: false,
thumbnailHttp: null,
getThumbnailHttp: function (width: number, height: number, mode?: "scale" | "crop"): string | null {
throw new Error("Function not implemented.");
},
getThumbnailOfSourceHttp: function (width: number, height: number, mode?: "scale" | "crop"): string | null {
throw new Error("Function not implemented.");
},
getSquareThumbnailHttp: function (dim: number): string | null {
throw new Error("Function not implemented.");
},
downloadSource: function (): Promise<Response> {
throw new Error("Function not implemented.");
},
});
const { result } = renderUserInfoHeaderViewModelHook(props);
result.current.onMemberAvatarClick();
expect(spyModale).not.toHaveBeenCalled();
});
});