apply minor changes from review

pull/28211/head
Hubert Chathi 2024-10-24 18:40:38 -04:00
parent 0b1e7adf91
commit f4b403d236
2 changed files with 81 additions and 90 deletions

View File

@ -6,19 +6,11 @@ Please see LICENSE files in the repository root for full details.
*/ */
import React, { useCallback, useRef, useState } from "react"; import React, { useCallback, useRef, useState } from "react";
import { import { EventType, KnownMembership, MatrixEvent, Room, RoomStateEvent, RoomMember } from "matrix-js-sdk/src/matrix";
CryptoEvent, import { CryptoApi, CryptoEvent, UserVerificationStatus } from "matrix-js-sdk/src/crypto-api";
EventType,
KnownMembership,
MatrixEvent,
Room,
RoomStateEvent,
RoomMember,
} from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { Button, Separator } from "@vector-im/compound-web"; import { Button, Separator } from "@vector-im/compound-web";
import type { CryptoApi, UserVerificationStatus } from "matrix-js-sdk/src/crypto-api";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import MemberAvatar from "../avatars/MemberAvatar"; import MemberAvatar from "../avatars/MemberAvatar";
import { useMatrixClientContext } from "../../../contexts/MatrixClientContext"; import { useMatrixClientContext } from "../../../contexts/MatrixClientContext";

View File

@ -8,7 +8,6 @@ Please see LICENSE files in the repository root for full details.
import React from "react"; import React from "react";
import { sleep } from "matrix-js-sdk/src/utils"; import { sleep } from "matrix-js-sdk/src/utils";
import { import {
CryptoEvent,
EventType, EventType,
MatrixClient, MatrixClient,
MatrixEvent, MatrixEvent,
@ -17,8 +16,9 @@ import {
RoomStateEvent, RoomStateEvent,
RoomMember, RoomMember,
} from "matrix-js-sdk/src/matrix"; } from "matrix-js-sdk/src/matrix";
import { UserVerificationStatus } from "matrix-js-sdk/src/crypto-api"; import { CryptoEvent, UserVerificationStatus } from "matrix-js-sdk/src/crypto-api";
import { act, fireEvent, render, screen, waitFor } from "jest-matrix-react"; import { act, render, screen, waitFor } from "jest-matrix-react";
import userEvent from "@testing-library/user-event";
import { stubClient } from "../../../../test-utils"; import { stubClient } from "../../../../test-utils";
import { UserIdentityWarning } from "../../../../../src/components/views/rooms/UserIdentityWarning"; import { UserIdentityWarning } from "../../../../../src/components/views/rooms/UserIdentityWarning";
@ -52,7 +52,11 @@ function dummyRoomState(): RoomState {
return new RoomState(ROOM_ID); return new RoomState(ROOM_ID);
} }
// Get the warning element, given the warning text (excluding the "Learn more" link). /**
* Get the warning element, given the warning text (excluding the "Learn more"
* link). This is needed because the warning text contains a `<b>` tag, so the
* normal `getByText` doesn't work.
*/
function getWarningByText(text: string): Element { function getWarningByText(text: string): Element {
return screen.getByText((content?: string, element?: Element | null): boolean => { return screen.getByText((content?: string, element?: Element | null): boolean => {
return ( return (
@ -63,6 +67,12 @@ function getWarningByText(text: string): Element {
}); });
} }
function renderComponent(client: MatrixClient, room: Room) {
return render(<UserIdentityWarning room={room} key={ROOM_ID} />, {
wrapper: ({ ...rest }) => <MatrixClientContext.Provider value={client} {...rest} />,
});
}
describe("UserIdentityWarning", () => { describe("UserIdentityWarning", () => {
let client: MatrixClient; let client: MatrixClient;
let room: Room; let room: Room;
@ -80,24 +90,22 @@ describe("UserIdentityWarning", () => {
// member whose identity needs accepting, we should display a warning. When // member whose identity needs accepting, we should display a warning. When
// the "OK" button gets pressed, it should call `pinCurrentUserIdentity`. // the "OK" button gets pressed, it should call `pinCurrentUserIdentity`.
it("displays a warning when a user's identity needs approval", async () => { it("displays a warning when a user's identity needs approval", async () => {
room.getEncryptionTargetMembers = jest.fn(async () => { jest.spyOn(room, "getEncryptionTargetMembers").mockResolvedValue([
return [mockRoomMember("@alice:example.org", "Alice")]; mockRoomMember("@alice:example.org", "Alice"),
}); ]);
const crypto = client.getCrypto()!; const crypto = client.getCrypto()!;
crypto["getUserVerificationStatus"] = jest.fn(async () => { jest.spyOn(crypto, "getUserVerificationStatus").mockResolvedValue(
return Promise.resolve(new UserVerificationStatus(false, false, false, true)); new UserVerificationStatus(false, false, false, true),
}); );
crypto.pinCurrentUserIdentity = jest.fn(); crypto.pinCurrentUserIdentity = jest.fn();
const { container } = render(<UserIdentityWarning room={room} key={ROOM_ID} />, { renderComponent(client, room);
wrapper: ({ ...rest }) => <MatrixClientContext.Provider value={client} {...rest} />,
});
await waitFor(() => await waitFor(() =>
expect( expect(
getWarningByText("Alice's (@alice:example.org) identity appears to have changed."), getWarningByText("Alice's (@alice:example.org) identity appears to have changed."),
).toBeInTheDocument(), ).toBeInTheDocument(),
); );
fireEvent.click(container.querySelector("[role=button]")!); await userEvent.click(screen.getByRole("button")!);
await waitFor(() => expect(crypto.pinCurrentUserIdentity).toHaveBeenCalledWith("@alice:example.org")); await waitFor(() => expect(crypto.pinCurrentUserIdentity).toHaveBeenCalledWith("@alice:example.org"));
}); });
@ -105,19 +113,17 @@ describe("UserIdentityWarning", () => {
// enabled, then we should display a warning if there are any users whose // enabled, then we should display a warning if there are any users whose
// identity need accepting. // identity need accepting.
it("displays pending warnings when encryption is enabled", async () => { it("displays pending warnings when encryption is enabled", async () => {
room.getEncryptionTargetMembers = jest.fn(async () => { jest.spyOn(room, "getEncryptionTargetMembers").mockResolvedValue([
return [mockRoomMember("@alice:example.org", "Alice")]; mockRoomMember("@alice:example.org", "Alice"),
}); ]);
// Start the room off unencrypted. We shouldn't display anything. // Start the room off unencrypted. We shouldn't display anything.
room.hasEncryptionStateEvent = jest.fn(() => false); jest.spyOn(room, "hasEncryptionStateEvent").mockReturnValue(false);
const crypto = client.getCrypto()!; const crypto = client.getCrypto()!;
crypto["getUserVerificationStatus"] = jest.fn(async () => { jest.spyOn(crypto, "getUserVerificationStatus").mockResolvedValue(
return Promise.resolve(new UserVerificationStatus(false, false, false, true)); new UserVerificationStatus(false, false, false, true),
}); );
render(<UserIdentityWarning room={room} key={ROOM_ID} />, { renderComponent(client, room);
wrapper: ({ ...rest }) => <MatrixClientContext.Provider value={client} {...rest} />,
});
await sleep(10); // give it some time to finish initialising await sleep(10); // give it some time to finish initialising
expect(() => getWarningByText("Alice's (@alice:example.org) identity appears to have changed.")).toThrow(); expect(() => getWarningByText("Alice's (@alice:example.org) identity appears to have changed.")).toThrow();
@ -148,17 +154,15 @@ describe("UserIdentityWarning", () => {
// When a user's identity needs approval, or has been approved, the display // When a user's identity needs approval, or has been approved, the display
// should update appropriately. // should update appropriately.
it("updates the display when identity changes", async () => { it("updates the display when identity changes", async () => {
room.getEncryptionTargetMembers = jest.fn(async () => { jest.spyOn(room, "getEncryptionTargetMembers").mockResolvedValue([
return [mockRoomMember("@alice:example.org", "Alice")]; mockRoomMember("@alice:example.org", "Alice"),
}); ]);
room.getMember = jest.fn(() => mockRoomMember("@alice:example.org", "Alice")); jest.spyOn(room, "getMember").mockReturnValue(mockRoomMember("@alice:example.org", "Alice"));
const crypto = client.getCrypto()!; const crypto = client.getCrypto()!;
crypto["getUserVerificationStatus"] = jest.fn(async () => { jest.spyOn(crypto, "getUserVerificationStatus").mockResolvedValue(
return Promise.resolve(new UserVerificationStatus(false, false, false, false)); new UserVerificationStatus(false, false, false, false),
}); );
render(<UserIdentityWarning room={room} key={ROOM_ID} />, { renderComponent(client, room);
wrapper: ({ ...rest }) => <MatrixClientContext.Provider value={client} {...rest} />,
});
await sleep(10); // give it some time to finish initialising await sleep(10); // give it some time to finish initialising
expect(() => getWarningByText("Alice's (@alice:example.org) identity appears to have changed.")).toThrow(); expect(() => getWarningByText("Alice's (@alice:example.org) identity appears to have changed.")).toThrow();
@ -194,17 +198,13 @@ describe("UserIdentityWarning", () => {
// joins/leaves, we should update the warning appropriately. // joins/leaves, we should update the warning appropriately.
it("updates the display when a member joins/leaves", async () => { it("updates the display when a member joins/leaves", async () => {
// Nobody in the room yet // Nobody in the room yet
room.getEncryptionTargetMembers = jest.fn(async () => { jest.spyOn(room, "getEncryptionTargetMembers").mockResolvedValue([]);
return []; jest.spyOn(room, "getMember").mockReturnValue(mockRoomMember("@alice:example.org", "Alice"));
});
room.getMember = jest.fn(() => mockRoomMember("@alice:example.org", "Alice"));
const crypto = client.getCrypto()!; const crypto = client.getCrypto()!;
crypto["getUserVerificationStatus"] = jest.fn(async () => { jest.spyOn(crypto, "getUserVerificationStatus").mockResolvedValue(
return Promise.resolve(new UserVerificationStatus(false, false, false, true)); new UserVerificationStatus(false, false, false, true),
}); );
render(<UserIdentityWarning room={room} key={ROOM_ID} />, { renderComponent(client, room);
wrapper: ({ ...rest }) => <MatrixClientContext.Provider value={client} {...rest} />,
});
await sleep(10); // give it some time to finish initialising await sleep(10); // give it some time to finish initialising
// Alice joins. Her identity needs approval, so we should show a warning. // Alice joins. Her identity needs approval, so we should show a warning.
@ -253,20 +253,19 @@ describe("UserIdentityWarning", () => {
}); });
// When we have multiple users whose identity needs approval, one user's // When we have multiple users whose identity needs approval, one user's
// identity no longer reeds approval (e.g. their identity was approved), // identity no longer needs approval (e.g. their identity was approved),
// then we show the next one. // then we show the next one.
it("displays the next user when the current user's identity is approved", async () => { it("displays the next user when the current user's identity is approved", async () => {
room.getEncryptionTargetMembers = jest.fn(async () => { jest.spyOn(room, "getEncryptionTargetMembers").mockResolvedValue([
return [mockRoomMember("@alice:example.org", "Alice"), mockRoomMember("@bob:example.org")]; mockRoomMember("@alice:example.org", "Alice"),
}); mockRoomMember("@bob:example.org"),
]);
const crypto = client.getCrypto()!; const crypto = client.getCrypto()!;
crypto["getUserVerificationStatus"] = jest.fn(async () => { jest.spyOn(crypto, "getUserVerificationStatus").mockResolvedValue(
return Promise.resolve(new UserVerificationStatus(false, false, false, true)); new UserVerificationStatus(false, false, false, true),
}); );
render(<UserIdentityWarning room={room} key={ROOM_ID} />, { renderComponent(client, room);
wrapper: ({ ...rest }) => <MatrixClientContext.Provider value={client} {...rest} />,
});
// We should warn about Alice's identity first. // We should warn about Alice's identity first.
await waitFor(() => await waitFor(() =>
expect( expect(
@ -295,22 +294,22 @@ describe("UserIdentityWarning", () => {
// First case: check that if the update says that the user identity // First case: check that if the update says that the user identity
// needs approval, but the fetch says it doesn't, we show the warning. // needs approval, but the fetch says it doesn't, we show the warning.
it("update says identity needs approval", async () => { it("update says identity needs approval", async () => {
room.getEncryptionTargetMembers = jest.fn(async () => { jest.spyOn(room, "getEncryptionTargetMembers").mockResolvedValue([
return [mockRoomMember("@alice:example.org", "Alice")]; mockRoomMember("@alice:example.org", "Alice"),
}); ]);
room.getMember = jest.fn(() => mockRoomMember("@alice:example.org", "Alice")); jest.spyOn(room, "getMember").mockReturnValue(mockRoomMember("@alice:example.org", "Alice"));
const crypto = client.getCrypto()!; const crypto = client.getCrypto()!;
crypto["getUserVerificationStatus"] = jest.fn(async () => { jest.spyOn(crypto, "getUserVerificationStatus").mockImplementation(async () => {
client.emit( act(() => {
CryptoEvent.UserTrustStatusChanged, client.emit(
"@alice:example.org", CryptoEvent.UserTrustStatusChanged,
new UserVerificationStatus(false, false, false, true), "@alice:example.org",
); new UserVerificationStatus(false, false, false, true),
);
});
return Promise.resolve(new UserVerificationStatus(false, false, false, false)); return Promise.resolve(new UserVerificationStatus(false, false, false, false));
}); });
render(<UserIdentityWarning room={room} key={ROOM_ID} />, { renderComponent(client, room);
wrapper: ({ ...rest }) => <MatrixClientContext.Provider value={client} {...rest} />,
});
await sleep(10); // give it some time to finish initialising await sleep(10); // give it some time to finish initialising
await waitFor(() => await waitFor(() =>
expect( expect(
@ -323,22 +322,22 @@ describe("UserIdentityWarning", () => {
// doesn't needs approval, but the fetch says it does, we don't show the // doesn't needs approval, but the fetch says it does, we don't show the
// warning. // warning.
it("update says identity doesn't need approval", async () => { it("update says identity doesn't need approval", async () => {
room.getEncryptionTargetMembers = jest.fn(async () => { jest.spyOn(room, "getEncryptionTargetMembers").mockResolvedValue([
return [mockRoomMember("@alice:example.org", "Alice")]; mockRoomMember("@alice:example.org", "Alice"),
}); ]);
room.getMember = jest.fn(() => mockRoomMember("@alice:example.org", "Alice")); jest.spyOn(room, "getMember").mockReturnValue(mockRoomMember("@alice:example.org", "Alice"));
const crypto = client.getCrypto()!; const crypto = client.getCrypto()!;
crypto["getUserVerificationStatus"] = jest.fn(async () => { jest.spyOn(crypto, "getUserVerificationStatus").mockImplementation(async () => {
client.emit( act(() => {
CryptoEvent.UserTrustStatusChanged, client.emit(
"@alice:example.org", CryptoEvent.UserTrustStatusChanged,
new UserVerificationStatus(false, false, false, false), "@alice:example.org",
); new UserVerificationStatus(false, false, false, false),
);
});
return Promise.resolve(new UserVerificationStatus(false, false, false, true)); return Promise.resolve(new UserVerificationStatus(false, false, false, true));
}); });
render(<UserIdentityWarning room={room} key={ROOM_ID} />, { renderComponent(client, room);
wrapper: ({ ...rest }) => <MatrixClientContext.Provider value={client} {...rest} />,
});
await sleep(10); // give it some time to finish initialising await sleep(10); // give it some time to finish initialising
await waitFor(() => await waitFor(() =>
expect(() => expect(() =>