2022-05-26 17:19:00 +08:00
|
|
|
/*
|
|
|
|
Copyright 2022 The Matrix.org Foundation C.I.C.
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/// <reference types="cypress" />
|
|
|
|
|
|
|
|
import type { MatrixClient } from "matrix-js-sdk/src/client";
|
2023-02-03 16:59:21 +08:00
|
|
|
import type { Preset } from "matrix-js-sdk/src/@types/partials";
|
2022-05-26 17:19:00 +08:00
|
|
|
import type { ICreateRoomOpts } from "matrix-js-sdk/src/@types/requests";
|
2023-01-11 07:29:56 +08:00
|
|
|
import { HomeserverInstance } from "../../plugins/utils/homeserver";
|
2022-05-26 17:19:00 +08:00
|
|
|
import Chainable = Cypress.Chainable;
|
|
|
|
import { UserCredentials } from "../../support/login";
|
|
|
|
|
|
|
|
function openSpaceCreateMenu(): Chainable<JQuery> {
|
|
|
|
cy.get(".mx_SpaceButton_new").click();
|
|
|
|
return cy.get(".mx_SpaceCreateMenu_wrapper .mx_ContextualMenu");
|
|
|
|
}
|
|
|
|
|
|
|
|
function openSpaceContextMenu(spaceName: string): Chainable<JQuery> {
|
2022-07-25 19:46:19 +08:00
|
|
|
cy.getSpacePanelButton(spaceName).rightclick();
|
2022-05-26 17:19:00 +08:00
|
|
|
return cy.get(".mx_SpacePanel_contextMenu");
|
|
|
|
}
|
|
|
|
|
2023-02-03 16:59:21 +08:00
|
|
|
function spaceCreateOptions(spaceName: string, roomIds: string[] = []): ICreateRoomOpts {
|
2022-05-26 17:19:00 +08:00
|
|
|
return {
|
|
|
|
creation_content: {
|
|
|
|
type: "m.space",
|
|
|
|
},
|
2022-12-12 19:24:14 +08:00
|
|
|
initial_state: [
|
|
|
|
{
|
|
|
|
type: "m.room.name",
|
|
|
|
content: {
|
|
|
|
name: spaceName,
|
|
|
|
},
|
2022-05-26 17:19:00 +08:00
|
|
|
},
|
2023-02-03 16:59:21 +08:00
|
|
|
...roomIds.map(spaceChildInitialState),
|
2022-12-12 19:24:14 +08:00
|
|
|
],
|
2022-05-26 17:19:00 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function spaceChildInitialState(roomId: string): ICreateRoomOpts["initial_state"]["0"] {
|
|
|
|
return {
|
|
|
|
type: "m.space.child",
|
|
|
|
state_key: roomId,
|
|
|
|
content: {
|
|
|
|
via: [roomId.split(":")[1]],
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
describe("Spaces", () => {
|
2023-01-11 07:29:56 +08:00
|
|
|
let homeserver: HomeserverInstance;
|
2022-05-26 17:19:00 +08:00
|
|
|
let user: UserCredentials;
|
|
|
|
|
|
|
|
beforeEach(() => {
|
2023-01-11 07:29:56 +08:00
|
|
|
cy.startHomeserver("default").then((data) => {
|
|
|
|
homeserver = data;
|
2022-05-26 17:19:00 +08:00
|
|
|
|
2023-01-11 07:29:56 +08:00
|
|
|
cy.initTestUser(homeserver, "Sue").then((_user) => {
|
2022-05-26 17:19:00 +08:00
|
|
|
user = _user;
|
|
|
|
cy.mockClipboard();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
afterEach(() => {
|
2023-01-11 07:29:56 +08:00
|
|
|
cy.stopHomeserver(homeserver);
|
2022-05-26 17:19:00 +08:00
|
|
|
});
|
|
|
|
|
2023-02-02 23:25:24 +08:00
|
|
|
it("should allow user to create public space", () => {
|
2023-01-05 16:19:54 +08:00
|
|
|
openSpaceCreateMenu();
|
|
|
|
cy.get("#mx_ContextualMenu_Container").percySnapshotElement("Space create menu");
|
|
|
|
cy.get(".mx_SpaceCreateMenu_wrapper .mx_ContextualMenu").within(() => {
|
2022-05-26 17:19:00 +08:00
|
|
|
cy.get(".mx_SpaceCreateMenuType_public").click();
|
2022-12-12 19:24:14 +08:00
|
|
|
cy.get('.mx_SpaceBasicSettings_avatarContainer input[type="file"]').selectFile(
|
|
|
|
"cypress/fixtures/riot.png",
|
|
|
|
{ force: true },
|
|
|
|
);
|
2022-05-26 17:19:00 +08:00
|
|
|
cy.get('input[label="Name"]').type("Let's have a Riot");
|
|
|
|
cy.get('input[label="Address"]').should("have.value", "lets-have-a-riot");
|
|
|
|
cy.get('textarea[label="Description"]').type("This is a space to reminisce Riot.im!");
|
2022-10-19 00:07:23 +08:00
|
|
|
cy.contains(".mx_AccessibleButton", "Create").click();
|
2022-05-26 17:19:00 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
// Create the default General & Random rooms, as well as a custom "Jokes" room
|
|
|
|
cy.get('input[label="Room name"][value="General"]').should("exist");
|
|
|
|
cy.get('input[label="Room name"][value="Random"]').should("exist");
|
|
|
|
cy.get('input[placeholder="Support"]').type("Jokes");
|
2022-10-19 00:07:23 +08:00
|
|
|
cy.contains(".mx_AccessibleButton", "Continue").click();
|
2022-05-26 17:19:00 +08:00
|
|
|
|
|
|
|
// Copy matrix.to link
|
|
|
|
cy.get(".mx_SpacePublicShare_shareButton").focus().realClick();
|
|
|
|
cy.getClipboardText().should("eq", "https://matrix.to/#/#lets-have-a-riot:localhost");
|
|
|
|
|
|
|
|
// Go to space home
|
2022-10-19 00:07:23 +08:00
|
|
|
cy.contains(".mx_AccessibleButton", "Go to my first room").click();
|
2022-05-26 17:19:00 +08:00
|
|
|
|
|
|
|
// Assert rooms exist in the room list
|
2022-10-19 00:07:23 +08:00
|
|
|
cy.contains(".mx_RoomList .mx_RoomTile", "General").should("exist");
|
|
|
|
cy.contains(".mx_RoomList .mx_RoomTile", "Random").should("exist");
|
|
|
|
cy.contains(".mx_RoomList .mx_RoomTile", "Jokes").should("exist");
|
2022-05-26 17:19:00 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
it("should allow user to create private space", () => {
|
|
|
|
openSpaceCreateMenu().within(() => {
|
|
|
|
cy.get(".mx_SpaceCreateMenuType_private").click();
|
2022-12-12 19:24:14 +08:00
|
|
|
cy.get('.mx_SpaceBasicSettings_avatarContainer input[type="file"]').selectFile(
|
|
|
|
"cypress/fixtures/riot.png",
|
|
|
|
{ force: true },
|
|
|
|
);
|
2022-05-26 17:19:00 +08:00
|
|
|
cy.get('input[label="Name"]').type("This is not a Riot");
|
|
|
|
cy.get('input[label="Address"]').should("not.exist");
|
|
|
|
cy.get('textarea[label="Description"]').type("This is a private space of mourning Riot.im...");
|
2022-10-19 00:07:23 +08:00
|
|
|
cy.contains(".mx_AccessibleButton", "Create").click();
|
2022-05-26 17:19:00 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
cy.get(".mx_SpaceRoomView_privateScope_meAndMyTeammatesButton").click();
|
|
|
|
|
|
|
|
// Create the default General & Random rooms, as well as a custom "Projects" room
|
|
|
|
cy.get('input[label="Room name"][value="General"]').should("exist");
|
|
|
|
cy.get('input[label="Room name"][value="Random"]').should("exist");
|
|
|
|
cy.get('input[placeholder="Support"]').type("Projects");
|
2022-10-19 00:07:23 +08:00
|
|
|
cy.contains(".mx_AccessibleButton", "Continue").click();
|
2022-05-26 17:19:00 +08:00
|
|
|
|
|
|
|
cy.get(".mx_SpaceRoomView").should("contain", "Invite your teammates");
|
2022-10-19 00:07:23 +08:00
|
|
|
cy.contains(".mx_AccessibleButton", "Skip for now").click();
|
2022-05-26 17:19:00 +08:00
|
|
|
|
|
|
|
// Assert rooms exist in the room list
|
2022-10-19 00:07:23 +08:00
|
|
|
cy.contains(".mx_RoomList .mx_RoomTile", "General").should("exist");
|
|
|
|
cy.contains(".mx_RoomList .mx_RoomTile", "Random").should("exist");
|
|
|
|
cy.contains(".mx_RoomList .mx_RoomTile", "Projects").should("exist");
|
2022-05-26 17:19:00 +08:00
|
|
|
|
|
|
|
// Assert rooms exist in the space explorer
|
2022-10-19 00:07:23 +08:00
|
|
|
cy.contains(".mx_SpaceHierarchy_list .mx_SpaceHierarchy_roomTile", "General").should("exist");
|
|
|
|
cy.contains(".mx_SpaceHierarchy_list .mx_SpaceHierarchy_roomTile", "Random").should("exist");
|
|
|
|
cy.contains(".mx_SpaceHierarchy_list .mx_SpaceHierarchy_roomTile", "Projects").should("exist");
|
2022-05-26 17:19:00 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
it("should allow user to create just-me space", () => {
|
|
|
|
cy.createRoom({
|
|
|
|
name: "Sample Room",
|
|
|
|
});
|
|
|
|
|
|
|
|
openSpaceCreateMenu().within(() => {
|
|
|
|
cy.get(".mx_SpaceCreateMenuType_private").click();
|
2023-02-02 18:22:19 +08:00
|
|
|
cy.get('.mx_SpaceBasicSettings_avatarContainer input[type="file"]').selectFile(
|
|
|
|
"cypress/fixtures/riot.png",
|
|
|
|
{ force: true },
|
|
|
|
);
|
2022-05-26 17:19:00 +08:00
|
|
|
cy.get('input[label="Address"]').should("not.exist");
|
|
|
|
cy.get('textarea[label="Description"]').type("This is a personal space to mourn Riot.im...");
|
|
|
|
cy.get('input[label="Name"]').type("This is my Riot{enter}");
|
|
|
|
});
|
|
|
|
|
|
|
|
cy.get(".mx_SpaceRoomView_privateScope_justMeButton").click();
|
|
|
|
|
|
|
|
cy.get(".mx_AddExistingToSpace_entry").click();
|
2022-10-19 00:07:23 +08:00
|
|
|
cy.contains(".mx_AccessibleButton", "Add").click();
|
2022-05-26 17:19:00 +08:00
|
|
|
|
2022-10-19 00:07:23 +08:00
|
|
|
cy.contains(".mx_RoomList .mx_RoomTile", "Sample Room").should("exist");
|
|
|
|
cy.contains(".mx_SpaceHierarchy_list .mx_SpaceHierarchy_roomTile", "Sample Room").should("exist");
|
2022-05-26 17:19:00 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
it("should allow user to invite another to a space", () => {
|
|
|
|
let bot: MatrixClient;
|
2023-01-11 07:29:56 +08:00
|
|
|
cy.getBot(homeserver, { displayName: "BotBob" }).then((_bot) => {
|
2022-05-26 17:19:00 +08:00
|
|
|
bot = _bot;
|
|
|
|
});
|
|
|
|
|
|
|
|
cy.createSpace({
|
|
|
|
visibility: "public" as any,
|
|
|
|
room_alias_name: "space",
|
|
|
|
}).as("spaceId");
|
|
|
|
|
|
|
|
openSpaceContextMenu("#space:localhost").within(() => {
|
|
|
|
cy.get('.mx_SpacePanel_contextMenu_inviteButton[aria-label="Invite"]').click();
|
|
|
|
});
|
|
|
|
|
|
|
|
cy.get(".mx_SpacePublicShare").within(() => {
|
|
|
|
// Copy link first
|
|
|
|
cy.get(".mx_SpacePublicShare_shareButton").focus().realClick();
|
|
|
|
cy.getClipboardText().should("eq", "https://matrix.to/#/#space:localhost");
|
|
|
|
// Start Matrix invite flow
|
|
|
|
cy.get(".mx_SpacePublicShare_inviteButton").click();
|
|
|
|
});
|
|
|
|
|
|
|
|
cy.get(".mx_InviteDialog_other").within(() => {
|
|
|
|
cy.get('input[type="text"]').type(bot.getUserId());
|
2022-10-19 00:07:23 +08:00
|
|
|
cy.contains(".mx_AccessibleButton", "Invite").click();
|
2022-05-26 17:19:00 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
cy.get(".mx_InviteDialog_other").should("not.exist");
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should show space invites at the top of the space panel", () => {
|
|
|
|
cy.createSpace({
|
|
|
|
name: "My Space",
|
|
|
|
});
|
2022-07-25 19:46:19 +08:00
|
|
|
cy.getSpacePanelButton("My Space").should("exist");
|
2022-05-26 17:19:00 +08:00
|
|
|
|
2023-01-11 07:29:56 +08:00
|
|
|
cy.getBot(homeserver, { displayName: "BotBob" }).then({ timeout: 10000 }, async (bot) => {
|
2022-05-26 17:19:00 +08:00
|
|
|
const { room_id: roomId } = await bot.createRoom(spaceCreateOptions("Space Space"));
|
|
|
|
await bot.invite(roomId, user.userId);
|
|
|
|
});
|
|
|
|
// Assert that `Space Space` is above `My Space` due to it being an invite
|
2022-12-12 19:24:14 +08:00
|
|
|
cy.getSpacePanelButton("Space Space")
|
|
|
|
.should("exist")
|
|
|
|
.parent()
|
|
|
|
.next()
|
|
|
|
.find('.mx_SpaceButton[aria-label="My Space"]')
|
|
|
|
.should("exist");
|
2022-05-26 17:19:00 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
it("should include rooms in space home", () => {
|
|
|
|
cy.createRoom({
|
|
|
|
name: "Music",
|
|
|
|
}).as("roomId1");
|
|
|
|
cy.createRoom({
|
|
|
|
name: "Gaming",
|
|
|
|
}).as("roomId2");
|
|
|
|
|
|
|
|
const spaceName = "Spacey Mc. Space Space";
|
2022-12-12 19:24:14 +08:00
|
|
|
cy.all([cy.get<string>("@roomId1"), cy.get<string>("@roomId2")]).then(([roomId1, roomId2]) => {
|
2022-05-26 17:19:00 +08:00
|
|
|
cy.createSpace({
|
|
|
|
name: spaceName,
|
2022-12-12 19:24:14 +08:00
|
|
|
initial_state: [spaceChildInitialState(roomId1), spaceChildInitialState(roomId2)],
|
2022-05-26 17:19:00 +08:00
|
|
|
}).as("spaceId");
|
|
|
|
});
|
|
|
|
|
|
|
|
cy.get("@spaceId").then(() => {
|
2022-07-25 19:46:19 +08:00
|
|
|
cy.viewSpaceHomeByName(spaceName);
|
2022-05-26 17:19:00 +08:00
|
|
|
});
|
|
|
|
cy.get(".mx_SpaceRoomView .mx_SpaceHierarchy_list").within(() => {
|
2022-08-09 00:07:55 +08:00
|
|
|
cy.contains(".mx_SpaceHierarchy_roomTile", "Music").should("exist");
|
|
|
|
cy.contains(".mx_SpaceHierarchy_roomTile", "Gaming").should("exist");
|
2022-05-26 17:19:00 +08:00
|
|
|
});
|
|
|
|
});
|
2022-08-10 23:29:53 +08:00
|
|
|
|
|
|
|
it("should render subspaces in the space panel only when expanded", () => {
|
|
|
|
cy.injectAxe();
|
|
|
|
|
|
|
|
cy.createSpace({
|
|
|
|
name: "Child Space",
|
|
|
|
initial_state: [],
|
2022-12-12 19:24:14 +08:00
|
|
|
}).then((spaceId) => {
|
2022-08-10 23:29:53 +08:00
|
|
|
cy.createSpace({
|
|
|
|
name: "Root Space",
|
2022-12-12 19:24:14 +08:00
|
|
|
initial_state: [spaceChildInitialState(spaceId)],
|
2022-08-10 23:29:53 +08:00
|
|
|
}).as("spaceId");
|
|
|
|
});
|
|
|
|
cy.get('.mx_SpacePanel .mx_SpaceButton[aria-label="Root Space"]').should("exist");
|
|
|
|
cy.get('.mx_SpacePanel .mx_SpaceButton[aria-label="Child Space"]').should("not.exist");
|
|
|
|
|
|
|
|
const axeOptions = {
|
|
|
|
rules: {
|
|
|
|
// Disable this check as it triggers on nested roving tab index elements which are in practice fine
|
2022-12-12 19:24:14 +08:00
|
|
|
"nested-interactive": {
|
2022-08-10 23:29:53 +08:00
|
|
|
enabled: false,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
cy.checkA11y(undefined, axeOptions);
|
|
|
|
cy.get(".mx_SpacePanel").percySnapshotElement("Space panel collapsed", { widths: [68] });
|
|
|
|
|
|
|
|
cy.get(".mx_SpaceButton_toggleCollapse").click({ force: true });
|
|
|
|
cy.get(".mx_SpacePanel:not(.collapsed)").should("exist");
|
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
cy.contains(".mx_SpaceItem", "Root Space")
|
|
|
|
.should("exist")
|
|
|
|
.contains(".mx_SpaceItem", "Child Space")
|
|
|
|
.should("exist");
|
2022-08-10 23:29:53 +08:00
|
|
|
|
|
|
|
cy.checkA11y(undefined, axeOptions);
|
|
|
|
cy.get(".mx_SpacePanel").percySnapshotElement("Space panel expanded", { widths: [258] });
|
|
|
|
});
|
2023-02-03 16:59:21 +08:00
|
|
|
|
|
|
|
it("should not soft crash when joining a room from space hierarchy which has a link in its topic", () => {
|
|
|
|
cy.getBot(homeserver, { displayName: "BotBob" }).then({ timeout: 10000 }, async (bot) => {
|
|
|
|
const { room_id: roomId } = await bot.createRoom({
|
|
|
|
preset: "public_chat" as Preset,
|
|
|
|
name: "Test Room",
|
|
|
|
topic: "This is a topic https://github.com/matrix-org/matrix-react-sdk/pull/10060 with a link",
|
|
|
|
});
|
|
|
|
const { room_id: spaceId } = await bot.createRoom(spaceCreateOptions("Test Space", [roomId]));
|
|
|
|
await bot.invite(spaceId, user.userId);
|
|
|
|
});
|
|
|
|
|
|
|
|
cy.getSpacePanelButton("Test Space").should("exist");
|
|
|
|
cy.wait(500); // without this we can end up clicking too quickly and it ends up having no effect
|
|
|
|
cy.viewSpaceByName("Test Space");
|
|
|
|
cy.contains(".mx_AccessibleButton", "Accept").click();
|
|
|
|
|
|
|
|
cy.contains(".mx_SpaceHierarchy_roomTile.mx_AccessibleButton", "Test Room").within(() => {
|
|
|
|
cy.contains("Join").should("exist").realHover().click();
|
|
|
|
cy.contains("View", { timeout: 5000 }).should("exist").click();
|
|
|
|
});
|
|
|
|
|
|
|
|
// Assert we get shown the new room intro, and thus not the soft crash screen
|
|
|
|
cy.get(".mx_NewRoomIntro").should("exist");
|
|
|
|
});
|
2022-05-26 17:19:00 +08:00
|
|
|
});
|