More tests for UserInfo (#10677)

* UserInfo-test: move mocking to `beforeEach`

... so that changes to the mocks do not leak between tests

* Add some more tests for UserInfo
pull/28217/head
Richard van der Hoff 2023-04-21 14:48:27 +01:00 committed by GitHub
parent 893feed13b
commit 83f12fcba0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 171 additions and 93 deletions

View File

@ -15,9 +15,9 @@ limitations under the License.
*/
import React from "react";
import { fireEvent, render, screen, waitFor, cleanup, act } from "@testing-library/react";
import { fireEvent, render, screen, waitFor, cleanup, act, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { mocked } from "jest-mock";
import { Mocked, mocked } from "jest-mock";
import { Room, User, MatrixClient, RoomMember, MatrixEvent, EventType } from "matrix-js-sdk/src/matrix";
import { Phase, VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
import { DeviceTrustLevel, UserTrustLevel } from "matrix-js-sdk/src/crypto/CrossSigning";
@ -72,73 +72,78 @@ jest.mock("../../../../src/utils/DMRoomMap", () => {
};
});
const mockRoom = mocked({
roomId: "!fkfk",
getType: jest.fn().mockReturnValue(undefined),
isSpaceRoom: jest.fn().mockReturnValue(false),
getMember: jest.fn().mockReturnValue(undefined),
getMxcAvatarUrl: jest.fn().mockReturnValue("mock-avatar-url"),
name: "test room",
on: jest.fn(),
off: jest.fn(),
currentState: {
getStateEvents: jest.fn(),
on: jest.fn(),
},
getEventReadUpTo: jest.fn(),
} as unknown as Room);
const mockSpace = mocked({
roomId: "!fkfk",
getType: jest.fn().mockReturnValue("m.space"),
isSpaceRoom: jest.fn().mockReturnValue(true),
getMember: jest.fn().mockReturnValue(undefined),
getMxcAvatarUrl: jest.fn().mockReturnValue("mock-avatar-url"),
name: "test room",
on: jest.fn(),
off: jest.fn(),
currentState: {
getStateEvents: jest.fn(),
on: jest.fn(),
},
getEventReadUpTo: jest.fn(),
} as unknown as Room);
const mockClient = mocked({
getUser: jest.fn(),
isGuest: jest.fn().mockReturnValue(false),
isUserIgnored: jest.fn(),
getIgnoredUsers: jest.fn(),
setIgnoredUsers: jest.fn(),
isCryptoEnabled: jest.fn(),
getUserId: jest.fn(),
getSafeUserId: jest.fn(),
on: jest.fn(),
off: jest.fn(),
isSynapseAdministrator: jest.fn().mockResolvedValue(false),
isRoomEncrypted: jest.fn().mockReturnValue(false),
doesServerSupportUnstableFeature: jest.fn().mockReturnValue(false),
mxcUrlToHttp: jest.fn().mockReturnValue("mock-mxcUrlToHttp"),
removeListener: jest.fn(),
currentState: {
on: jest.fn(),
},
checkDeviceTrust: jest.fn(),
checkUserTrust: jest.fn(),
getRoom: jest.fn(),
credentials: {},
setPowerLevel: jest.fn(),
} as unknown as MatrixClient);
const defaultRoomId = "!fkfk";
const defaultUserId = "@user:example.com";
const defaultUser = new User(defaultUserId);
beforeEach(() => {
jest.spyOn(MatrixClientPeg, "get").mockReturnValue(mockClient);
});
let mockRoom: Mocked<Room>;
let mockSpace: Mocked<Room>;
let mockClient: Mocked<MatrixClient>;
afterEach(() => {
mockClient.getUser.mockClear().mockReturnValue({} as unknown as User);
beforeEach(() => {
mockRoom = mocked({
roomId: defaultRoomId,
getType: jest.fn().mockReturnValue(undefined),
isSpaceRoom: jest.fn().mockReturnValue(false),
getMember: jest.fn().mockReturnValue(undefined),
getMxcAvatarUrl: jest.fn().mockReturnValue("mock-avatar-url"),
name: "test room",
on: jest.fn(),
off: jest.fn(),
currentState: {
getStateEvents: jest.fn(),
on: jest.fn(),
off: jest.fn(),
},
getEventReadUpTo: jest.fn(),
} as unknown as Room);
mockSpace = mocked({
roomId: defaultRoomId,
getType: jest.fn().mockReturnValue("m.space"),
isSpaceRoom: jest.fn().mockReturnValue(true),
getMember: jest.fn().mockReturnValue(undefined),
getMxcAvatarUrl: jest.fn().mockReturnValue("mock-avatar-url"),
name: "test room",
on: jest.fn(),
off: jest.fn(),
currentState: {
getStateEvents: jest.fn(),
on: jest.fn(),
off: jest.fn(),
},
getEventReadUpTo: jest.fn(),
} as unknown as Room);
mockClient = mocked({
getUser: jest.fn(),
isGuest: jest.fn().mockReturnValue(false),
isUserIgnored: jest.fn(),
getIgnoredUsers: jest.fn(),
setIgnoredUsers: jest.fn(),
isCryptoEnabled: jest.fn(),
getUserId: jest.fn(),
getSafeUserId: jest.fn(),
on: jest.fn(),
off: jest.fn(),
isSynapseAdministrator: jest.fn().mockResolvedValue(false),
isRoomEncrypted: jest.fn().mockReturnValue(false),
doesServerSupportUnstableFeature: jest.fn().mockReturnValue(false),
mxcUrlToHttp: jest.fn().mockReturnValue("mock-mxcUrlToHttp"),
removeListener: jest.fn(),
currentState: {
on: jest.fn(),
},
checkDeviceTrust: jest.fn(),
checkUserTrust: jest.fn(),
getRoom: jest.fn(),
credentials: {},
setPowerLevel: jest.fn(),
downloadKeys: jest.fn(),
getStoredDevicesForUser: jest.fn(),
} as unknown as MatrixClient);
jest.spyOn(MatrixClientPeg, "get").mockReturnValue(mockClient);
});
describe("<UserInfo />", () => {
@ -241,14 +246,76 @@ describe("<UserInfo />", () => {
expect(screen.getByText(/try with a different client/i)).toBeInTheDocument();
});
});
describe("with crypto enabled", () => {
beforeEach(() => {
mockClient.isCryptoEnabled.mockReturnValue(true);
mockClient.checkUserTrust.mockReturnValue(new UserTrustLevel(false, false, false));
mockClient.checkDeviceTrust.mockReturnValue(new DeviceTrustLevel(false, false, false, false));
const device1 = DeviceInfo.fromStorage(
{
unsigned: { device_display_name: "my device" },
},
"d1",
);
mockClient.getStoredDevicesForUser.mockReturnValue([device1]);
});
it("renders a device list which can be expanded", async () => {
renderComponent();
await act(flushPromises);
// check the button exists with the expected text
const devicesButton = screen.getByRole("button", { name: "1 session" });
// click it
await userEvent.click(devicesButton);
// there should now be a button with the device id ...
const deviceButton = screen.getByRole("button", { description: "d1" });
// ... which should contain the device name
expect(within(deviceButton).getByText("my device")).toBeInTheDocument();
});
});
describe("with an encrypted room", () => {
beforeEach(() => {
mockClient.isCryptoEnabled.mockReturnValue(true);
mockClient.isRoomEncrypted.mockReturnValue(true);
});
it("renders unverified user info", async () => {
mockClient.checkUserTrust.mockReturnValue(new UserTrustLevel(false, false, false));
renderComponent({ room: mockRoom });
await act(flushPromises);
const userHeading = screen.getByRole("heading", { name: defaultUserId });
// there should be a "normal" E2E padlock
expect(userHeading.getElementsByClassName("mx_E2EIcon_normal")).toHaveLength(1);
});
it("renders verified user info", async () => {
mockClient.checkUserTrust.mockReturnValue(new UserTrustLevel(true, false, false));
renderComponent({ room: mockRoom });
await act(flushPromises);
const userHeading = screen.getByRole("heading", { name: defaultUserId });
// there should be a "verified" E2E padlock
expect(userHeading.getElementsByClassName("mx_E2EIcon_verified")).toHaveLength(1);
});
});
});
describe("<UserInfoHeader />", () => {
const defaultMember = new RoomMember(mockRoom.roomId, defaultUserId);
const defaultMember = new RoomMember(defaultRoomId, defaultUserId);
const defaultProps = {
member: defaultMember,
roomId: mockRoom.roomId,
roomId: defaultRoomId,
};
const renderComponent = (props = {}) => {
@ -399,7 +466,7 @@ describe("<DeviceItem />", () => {
});
describe("<UserOptionsSection />", () => {
const member = new RoomMember(mockRoom.roomId, defaultUserId);
const member = new RoomMember(defaultRoomId, defaultUserId);
const defaultProps = { member, isIgnored: false, canInvite: false, isSpace: false };
const renderComponent = (props = {}) => {
@ -644,17 +711,20 @@ describe("<UserOptionsSection />", () => {
});
describe("<PowerLevelEditor />", () => {
const defaultMember = new RoomMember(mockRoom.roomId, defaultUserId);
const defaultMember = new RoomMember(defaultRoomId, defaultUserId);
const defaultProps = {
user: defaultMember,
room: mockRoom,
roomPermissions: {
modifyLevelMax: 100,
canEdit: false,
canInvite: false,
},
};
let defaultProps: Parameters<typeof PowerLevelEditor>[0];
beforeEach(() => {
defaultProps = {
user: defaultMember,
room: mockRoom,
roomPermissions: {
modifyLevelMax: 100,
canEdit: false,
canInvite: false,
},
};
});
const renderComponent = (props = {}) => {
const Wrapper = (wrapperProps = {}) => {
@ -705,11 +775,14 @@ describe("<PowerLevelEditor />", () => {
});
describe("<RoomKickButton />", () => {
const defaultMember = new RoomMember(mockRoom.roomId, defaultUserId);
const defaultMember = new RoomMember(defaultRoomId, defaultUserId);
const memberWithInviteMembership = { ...defaultMember, membership: "invite" };
const memberWithJoinMembership = { ...defaultMember, membership: "join" };
const defaultProps = { room: mockRoom, member: defaultMember, startUpdating: jest.fn(), stopUpdating: jest.fn() };
let defaultProps: Parameters<typeof RoomKickButton>[0];
beforeEach(() => {
defaultProps = { room: mockRoom, member: defaultMember, startUpdating: jest.fn(), stopUpdating: jest.fn() };
});
const renderComponent = (props = {}) => {
const Wrapper = (wrapperProps = {}) => {
@ -805,10 +878,12 @@ describe("<RoomKickButton />", () => {
});
describe("<BanToggleButton />", () => {
const defaultMember = new RoomMember(mockRoom.roomId, defaultUserId);
const defaultMember = new RoomMember(defaultRoomId, defaultUserId);
const memberWithBanMembership = { ...defaultMember, membership: "ban" };
const defaultProps = { room: mockRoom, member: defaultMember, startUpdating: jest.fn(), stopUpdating: jest.fn() };
let defaultProps: Parameters<typeof BanToggleButton>[0];
beforeEach(() => {
defaultProps = { room: mockRoom, member: defaultMember, startUpdating: jest.fn(), stopUpdating: jest.fn() };
});
const renderComponent = (props = {}) => {
const Wrapper = (wrapperProps = {}) => {
@ -927,16 +1002,19 @@ describe("<BanToggleButton />", () => {
});
describe("<RoomAdminToolsContainer />", () => {
const defaultMember = new RoomMember(mockRoom.roomId, defaultUserId);
const defaultMember = new RoomMember(defaultRoomId, defaultUserId);
defaultMember.membership = "invite";
const defaultProps = {
room: mockRoom,
member: defaultMember,
startUpdating: jest.fn(),
stopUpdating: jest.fn(),
powerLevels: {},
};
let defaultProps: Parameters<typeof RoomAdminToolsContainer>[0];
beforeEach(() => {
defaultProps = {
room: mockRoom,
member: defaultMember,
startUpdating: jest.fn(),
stopUpdating: jest.fn(),
powerLevels: {},
};
});
const renderComponent = (props = {}) => {
const Wrapper = (wrapperProps = {}) => {
@ -1039,7 +1117,7 @@ describe("disambiguateDevices", () => {
describe("isMuted", () => {
// this member has a power level of 0
const isMutedMember = new RoomMember(mockRoom.roomId, defaultUserId);
const isMutedMember = new RoomMember(defaultRoomId, defaultUserId);
it("returns false if either argument is falsy", () => {
// @ts-ignore to let us purposely pass incorrect args

View File

@ -127,7 +127,7 @@ export function untilEmission(
});
}
export const flushPromises = async () => await new Promise((resolve) => window.setTimeout(resolve));
export const flushPromises = async () => await new Promise<void>((resolve) => window.setTimeout(resolve));
// with jest's modern fake timers process.nextTick is also mocked,
// flushing promises in the normal way then waits for some advancement