Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 74ea0d1

Browse files
maheichykMikhail Aheichyk
and
Mikhail Aheichyk
authored
Fix rejoin of knock rooms (#11980)
Signed-off-by: Mikhail Aheichyk <[email protected]> Co-authored-by: Mikhail Aheichyk <[email protected]>
1 parent e2bc437 commit 74ea0d1

File tree

5 files changed

+160
-4
lines changed

5 files changed

+160
-4
lines changed

cypress/e2e/knock/knock-into-room.spec.ts

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ describe("Knock Into Room", () => {
6363
cy.stopHomeserver(homeserver);
6464
});
6565

66-
it("should knock into the room then knock is approved and user joins the room", () => {
66+
it("should knock into the room then knock is approved and user joins the room then user is kicked and joins again", () => {
6767
cy.viewRoomById(roomId);
6868

6969
cy.get(".mx_RoomPreviewBar").within(() => {
@@ -104,6 +104,124 @@ describe("Knock Into Room", () => {
104104
cy.findByRole("group", { name: "Rooms" }).findByRole("treeitem", { name: "Cybersecurity" });
105105

106106
cy.findByText("Alice joined the room").should("exist");
107+
108+
cy.window().then(async (win) => {
109+
// bot kicks Alice
110+
await bot.kick(roomId, user.userId);
111+
});
112+
113+
cy.get(".mx_RoomPreviewBar").within(() => {
114+
cy.findByRole("button", { name: "Re-join" }).click();
115+
116+
cy.findByRole("heading", { name: "Ask to join Cybersecurity?" });
117+
cy.findByRole("button", { name: "Request access" }).click();
118+
});
119+
120+
cy.window().then(async (win) => {
121+
// bot waits for knock request from Alice
122+
await waitForRoom(win, bot, roomId, (room) => {
123+
const events = room.getLiveTimeline().getEvents();
124+
return events.some(
125+
(e) =>
126+
e.getType() === "m.room.member" &&
127+
e.getContent()?.membership === "knock" &&
128+
e.getContent()?.displayname === "Alice",
129+
);
130+
});
131+
132+
// bot invites Alice
133+
await bot.invite(roomId, user.userId);
134+
});
135+
136+
// Alice have to accept invitation in order to join the room.
137+
// It will be not needed when homeserver implements auto accept knock requests.
138+
cy.get(".mx_RoomView").findByRole("button", { name: "Accept" }).click();
139+
140+
cy.findByText("Alice was invited, joined, was removed, was invited, and joined").should("exist");
141+
});
142+
143+
it("should knock into the room then knock is approved and user joins the room then user is banned/unbanned and joins again", () => {
144+
cy.viewRoomById(roomId);
145+
146+
cy.get(".mx_RoomPreviewBar").within(() => {
147+
cy.findByRole("button", { name: "Join the discussion" }).click();
148+
149+
cy.findByRole("heading", { name: "Ask to join?" });
150+
cy.findByRole("textbox");
151+
cy.findByRole("button", { name: "Request access" }).click();
152+
153+
cy.findByRole("heading", { name: "Request to join sent" });
154+
});
155+
156+
// Knocked room should appear in Rooms
157+
cy.findByRole("group", { name: "Rooms" }).findByRole("treeitem", { name: "Cybersecurity" });
158+
159+
cy.window().then(async (win) => {
160+
// bot waits for knock request from Alice
161+
await waitForRoom(win, bot, roomId, (room) => {
162+
const events = room.getLiveTimeline().getEvents();
163+
return events.some(
164+
(e) =>
165+
e.getType() === "m.room.member" &&
166+
e.getContent()?.membership === "knock" &&
167+
e.getContent()?.displayname === "Alice",
168+
);
169+
});
170+
171+
// bot invites Alice
172+
await bot.invite(roomId, user.userId);
173+
});
174+
175+
cy.findByRole("group", { name: "Invites" }).findByRole("treeitem", { name: "Cybersecurity" });
176+
177+
// Alice have to accept invitation in order to join the room.
178+
// It will be not needed when homeserver implements auto accept knock requests.
179+
cy.get(".mx_RoomView").findByRole("button", { name: "Accept" }).click();
180+
181+
cy.findByRole("group", { name: "Rooms" }).findByRole("treeitem", { name: "Cybersecurity" });
182+
183+
cy.findByText("Alice joined the room").should("exist");
184+
185+
cy.window().then(async (win) => {
186+
// bot bans Alice
187+
await bot.ban(roomId, user.userId);
188+
});
189+
190+
cy.get(".mx_RoomPreviewBar").findByText("You were banned from Cybersecurity by Bob").should("exist");
191+
192+
cy.window().then(async (win) => {
193+
// bot unbans Alice
194+
await bot.unban(roomId, user.userId);
195+
});
196+
197+
cy.get(".mx_RoomPreviewBar").within(() => {
198+
cy.findByRole("button", { name: "Re-join" }).click();
199+
200+
cy.findByRole("heading", { name: "Ask to join Cybersecurity?" });
201+
cy.findByRole("button", { name: "Request access" }).click();
202+
});
203+
204+
cy.window().then(async (win) => {
205+
// bot waits for knock request from Alice
206+
await waitForRoom(win, bot, roomId, (room) => {
207+
const events = room.getLiveTimeline().getEvents();
208+
return events.some(
209+
(e) =>
210+
e.getType() === "m.room.member" &&
211+
e.getContent()?.membership === "knock" &&
212+
e.getContent()?.displayname === "Alice",
213+
);
214+
});
215+
216+
// bot invites Alice
217+
await bot.invite(roomId, user.userId);
218+
});
219+
220+
// Alice have to accept invitation in order to join the room.
221+
// It will be not needed when homeserver implements auto accept knock requests.
222+
cy.get(".mx_RoomView").findByRole("button", { name: "Accept" }).click();
223+
224+
cy.findByText("Alice was invited, joined, was banned, was unbanned, was invited, and joined").should("exist");
107225
});
108226

109227
it("should knock into the room and knock is cancelled by user himself", () => {

src/components/structures/RoomView.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2229,8 +2229,10 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
22292229
<div className="mx_RoomView" data-room-header={roomHeaderType}>
22302230
<ErrorBoundary>
22312231
<RoomPreviewBar
2232+
onJoinClick={this.onJoinButtonClicked}
22322233
room={this.state.room}
2233-
promptAskToJoin={myMembership === "leave" || this.state.promptAskToJoin}
2234+
canAskToJoinAndMembershipIsLeave={myMembership === "leave"}
2235+
promptAskToJoin={this.state.promptAskToJoin}
22342236
knocked={myMembership === "knock"}
22352237
onSubmitAskToJoin={this.onSubmitAskToJoin}
22362238
onCancelAskToJoin={this.onCancelAskToJoin}

src/components/views/rooms/RoomPreviewBar.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ interface IProps {
106106
onRejectAndIgnoreClick?(): void;
107107
onForgetClick?(): void;
108108

109+
canAskToJoinAndMembershipIsLeave?: boolean;
109110
promptAskToJoin?: boolean;
110111
knocked?: boolean;
111112
onSubmitAskToJoin?(reason?: string): void;
@@ -193,6 +194,8 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
193194
if (myMember.isKicked()) {
194195
if (previousMembership === "knock") {
195196
return MessageCase.RequestDenied;
197+
} else if (this.props.promptAskToJoin) {
198+
return MessageCase.PromptAskToJoin;
196199
}
197200
return MessageCase.Kicked;
198201
} else if (myMember.membership === "ban") {
@@ -208,7 +211,7 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
208211
return MessageCase.Loading;
209212
} else if (this.props.knocked) {
210213
return MessageCase.Knocked;
211-
} else if (this.props.promptAskToJoin) {
214+
} else if (this.props.canAskToJoinAndMembershipIsLeave || this.props.promptAskToJoin) {
212215
return MessageCase.PromptAskToJoin;
213216
}
214217

test/components/views/rooms/RoomPreviewBar-test.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ describe("<RoomPreviewBar />", () => {
172172
it("renders kicked message", () => {
173173
const room = createRoom(roomId, otherUserId);
174174
jest.spyOn(room, "getMember").mockReturnValue(makeMockRoomMember({ isKicked: true }));
175-
const component = getComponent({ room, promptAskToJoin: true });
175+
const component = getComponent({ room, canAskToJoinAndMembershipIsLeave: true, promptAskToJoin: false });
176176

177177
expect(getMessage(component)).toMatchSnapshot();
178178
});
@@ -458,6 +458,14 @@ describe("<RoomPreviewBar />", () => {
458458
expect(getMessage(component)).toMatchSnapshot();
459459
});
460460

461+
it("renders the corresponding message when kicked", () => {
462+
const room = createRoom(roomId, otherUserId);
463+
jest.spyOn(room, "getMember").mockReturnValue(makeMockRoomMember({ isKicked: true }));
464+
const component = getComponent({ room, promptAskToJoin: true });
465+
466+
expect(getMessage(component)).toMatchSnapshot();
467+
});
468+
461469
it("renders the corresponding message with a generic title", () => {
462470
const component = render(<RoomPreviewBar promptAskToJoin />);
463471
expect(getMessage(component)).toMatchSnapshot();

test/components/views/rooms/__snapshots__/RoomPreviewBar-test.tsx.snap

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,31 @@ exports[`<RoomPreviewBar /> message case AskToJoin renders the corresponding mes
3939
</div>
4040
`;
4141

42+
exports[`<RoomPreviewBar /> message case AskToJoin renders the corresponding message when kicked 1`] = `
43+
<div
44+
class="mx_RoomPreviewBar_message"
45+
>
46+
<h3>
47+
Ask to join RoomPreviewBar-test-room?
48+
</h3>
49+
<p>
50+
<span
51+
class="_avatar_1o69u_17 mx_BaseAvatar _avatar-imageless_1o69u_60"
52+
data-color="4"
53+
data-testid="avatar-img"
54+
data-type="round"
55+
role="presentation"
56+
style="--cpd-avatar-size: 36px;"
57+
>
58+
R
59+
</span>
60+
</p>
61+
<p>
62+
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.
63+
</p>
64+
</div>
65+
`;
66+
4267
exports[`<RoomPreviewBar /> message case AskToJoin renders the corresponding message with a generic title 1`] = `
4368
<div
4469
class="mx_RoomPreviewBar_message"

0 commit comments

Comments
 (0)