1
0
mirror of https://github.com/matrix-org/matrix-react-sdk.git synced 2025-08-06 10:22:45 +03:00

Allow knocking rooms (#11353)

Signed-off-by: Charly Nguyen <charly.nguyen@nordeck.net>
This commit is contained in:
Charly Nguyen
2023-08-07 08:27:09 +02:00
committed by GitHub
parent e6af09e424
commit 5152aad059
18 changed files with 689 additions and 7 deletions

View File

@@ -17,7 +17,7 @@ limitations under the License.
import React, { createRef, RefObject } from "react";
import { mocked, MockedObject } from "jest-mock";
import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/client";
import { Room, RoomEvent, EventType, MatrixError, RoomStateEvent } from "matrix-js-sdk/src/matrix";
import { Room, RoomEvent, EventType, JoinRule, MatrixError, RoomStateEvent } from "matrix-js-sdk/src/matrix";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { MEGOLM_ALGORITHM } from "matrix-js-sdk/src/crypto/olmlib";
import { fireEvent, render, screen, RenderResult } from "@testing-library/react";
@@ -34,10 +34,12 @@ import {
mkRoomMemberJoinEvent,
mkThirdPartyInviteEvent,
emitPromise,
createTestClient,
untilDispatch,
} from "../../test-utils";
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
import { Action } from "../../../src/dispatcher/actions";
import { defaultDispatcher } from "../../../src/dispatcher/dispatcher";
import dis, { defaultDispatcher } from "../../../src/dispatcher/dispatcher";
import { ViewRoomPayload } from "../../../src/dispatcher/payloads/ViewRoomPayload";
import { RoomView as _RoomView } from "../../../src/components/structures/RoomView";
import ResizeNotifier from "../../../src/utils/ResizeNotifier";
@@ -543,4 +545,41 @@ describe("RoomView", () => {
expect(screen.queryByLabelText("Forget room")).not.toBeInTheDocument();
});
});
describe("knock rooms", () => {
const client = createTestClient();
beforeEach(() => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => setting === "feature_ask_to_join");
jest.spyOn(room, "getJoinRule").mockReturnValue(JoinRule.Knock);
jest.spyOn(dis, "dispatch");
});
it("allows to request to join", async () => {
jest.spyOn(MatrixClientPeg, "safeGet").mockReturnValue(client);
jest.spyOn(client, "knockRoom").mockResolvedValue({ room_id: room.roomId });
await mountRoomView();
fireEvent.click(screen.getByRole("button", { name: "Request access" }));
await untilDispatch(Action.SubmitAskToJoin, dis);
expect(dis.dispatch).toHaveBeenCalledWith({
action: "submit_ask_to_join",
roomId: room.roomId,
opts: { reason: undefined },
});
});
it("allows to cancel a join request", async () => {
jest.spyOn(MatrixClientPeg, "safeGet").mockReturnValue(client);
jest.spyOn(client, "leave").mockResolvedValue({});
jest.spyOn(room, "getMyMembership").mockReturnValue("knock");
await mountRoomView();
fireEvent.click(screen.getByRole("button", { name: "Cancel request" }));
await untilDispatch(Action.CancelAskToJoin, dis);
expect(dis.dispatch).toHaveBeenCalledWith({ action: "cancel_ask_to_join", roomId: room.roomId });
});
});
});

View File

@@ -425,4 +425,60 @@ describe("<RoomPreviewBar />", () => {
});
});
});
describe("message case AskToJoin", () => {
it("renders the corresponding message", () => {
const component = getComponent({ promptAskToJoin: true });
expect(getMessage(component)).toMatchSnapshot();
});
it("renders the corresponding message with a generic title", () => {
const component = render(<RoomPreviewBar promptAskToJoin />);
expect(getMessage(component)).toMatchSnapshot();
});
it("renders the corresponding actions", () => {
const component = getComponent({ promptAskToJoin: true });
expect(getActions(component)).toMatchSnapshot();
});
it("triggers the primary action callback", () => {
const onSubmitAskToJoin = jest.fn();
const component = getComponent({ promptAskToJoin: true, onSubmitAskToJoin });
fireEvent.click(getPrimaryActionButton(component)!);
expect(onSubmitAskToJoin).toHaveBeenCalled();
});
it("triggers the primary action callback with a reason", () => {
const onSubmitAskToJoin = jest.fn();
const reason = "some reason";
const component = getComponent({ promptAskToJoin: true, onSubmitAskToJoin });
fireEvent.change(component.container.querySelector("textarea")!, { target: { value: reason } });
fireEvent.click(getPrimaryActionButton(component)!);
expect(onSubmitAskToJoin).toHaveBeenCalledWith(reason);
});
});
describe("message case Knocked", () => {
it("renders the corresponding message", () => {
const component = getComponent({ knocked: true });
expect(getMessage(component)).toMatchSnapshot();
});
it("renders the corresponding actions", () => {
const component = getComponent({ knocked: true, onCancelAskToJoin: () => {} });
expect(getActions(component)).toMatchSnapshot();
});
it("triggers the secondary action callback", () => {
const onCancelAskToJoin = jest.fn();
const component = getComponent({ knocked: true, onCancelAskToJoin });
fireEvent.click(getSecondaryActionButton(component)!);
expect(onCancelAskToJoin).toHaveBeenCalled();
});
});
});

View File

@@ -83,6 +83,9 @@ describe("<SendMessageComposer/>", () => {
narrow: false,
activeCall: null,
msc3946ProcessDynamicPredecessor: false,
canAskToJoin: false,
promptAskToJoin: false,
knocked: false,
};
describe("createMessageContent", () => {
const permalinkCreator = jest.fn() as any;

View File

@@ -1,5 +1,121 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<RoomPreviewBar /> message case AskToJoin renders the corresponding actions 1`] = `
<div
class="mx_RoomPreviewBar_actions mx_RoomPreviewBar_fullWidth"
>
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
role="button"
tabindex="0"
>
Request access
</div>
</div>
`;
exports[`<RoomPreviewBar /> message case AskToJoin renders the corresponding message 1`] = `
<div
class="mx_RoomPreviewBar_message"
>
<h3>
Ask to join RoomPreviewBar-test-room?
</h3>
<p>
<span
class="mx_BaseAvatar"
role="presentation"
>
<span
aria-hidden="true"
class="mx_BaseAvatar_initial"
style="font-size: 23.400000000000002px; width: 36px; line-height: 36px;"
>
R
</span>
<img
alt=""
aria-hidden="true"
class="mx_BaseAvatar_image"
data-testid="avatar-img"
loading="lazy"
src="data:image/png;base64,00"
style="width: 36px; height: 36px;"
/>
</span>
</p>
<p>
You need to be granted access to this room in order to view or participate in the conversation. You can send a request to join below.
</p>
</div>
`;
exports[`<RoomPreviewBar /> message case AskToJoin renders the corresponding message with a generic title 1`] = `
<div
class="mx_RoomPreviewBar_message"
>
<h3>
Ask to join?
</h3>
<p>
<span
class="mx_BaseAvatar"
role="presentation"
>
<span
aria-hidden="true"
class="mx_BaseAvatar_initial"
style="font-size: 23.400000000000002px; width: 36px; line-height: 36px;"
>
?
</span>
<img
alt=""
aria-hidden="true"
class="mx_BaseAvatar_image"
data-testid="avatar-img"
loading="lazy"
src="data:image/png;base64,00"
style="width: 36px; height: 36px;"
/>
</span>
</p>
<p>
You need to be granted access to this room in order to view or participate in the conversation. You can send a request to join below.
</p>
</div>
`;
exports[`<RoomPreviewBar /> message case Knocked renders the corresponding actions 1`] = `
<div
class="mx_RoomPreviewBar_actions"
>
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_secondary"
role="button"
tabindex="0"
>
Cancel request
</div>
</div>
`;
exports[`<RoomPreviewBar /> message case Knocked renders the corresponding message 1`] = `
<div
class="mx_RoomPreviewBar_message"
>
<h3>
Request to join sent
</h3>
<p>
<div
class="mx_Icon mx_Icon_16 mx_RoomPreviewBar_icon"
/>
Your request to join is pending.
</p>
</div>
`;
exports[`<RoomPreviewBar /> renders banned message 1`] = `
<div
class="mx_RoomPreviewBar_message"