Move spaces tests from Puppeteer to Cypress (#8645)
	
		
	
				
					
				
			* Move spaces tests from Puppeteer to Cypress * Add missing fixture * Tweak synapsedocker to not double error on a docker failure * Fix space hierarchy loading race condition Fixes https://github.com/matrix-org/element-web-rageshakes/issues/10345 * Fix race condition when creating public space with url update code * Try Electron once more due to perms issues around clipboard * Try set browser permissions properly * Try to enable clipboard another way * Try electron again * Try electron again again * Switch to built-in cypress feature for file uploads * Mock clipboard instead * TMPDIR ftw? * uid:gid pls * Clipboard tests can now run on any browser due to mocking * Test Enter as well as button for space creation * Make the test actually work * Update cypress/support/util.ts Co-authored-by: Eric Eastwood <erice@element.io> Co-authored-by: Eric Eastwood <erice@element.io>watcha-feature/make-nextcloud-documents-integration-a-local-widget
							parent
							
								
									d75e2f19c5
								
							
						
					
					
						commit
						f3f14afbbf
					
				| 
		 After Width: | Height: | Size: 14 KiB  | 
@ -0,0 +1,244 @@ | 
				
			||||
/* | 
				
			||||
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"; | 
				
			||||
import type { ICreateRoomOpts } from "matrix-js-sdk/src/@types/requests"; | 
				
			||||
import { SynapseInstance } from "../../plugins/synapsedocker"; | 
				
			||||
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 getSpacePanelButton(spaceName: string): Chainable<JQuery> { | 
				
			||||
    return cy.get(`.mx_SpaceButton[aria-label="${spaceName}"]`); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
function openSpaceContextMenu(spaceName: string): Chainable<JQuery> { | 
				
			||||
    getSpacePanelButton(spaceName).rightclick(); | 
				
			||||
    return cy.get(".mx_SpacePanel_contextMenu"); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
function spaceCreateOptions(spaceName: string): ICreateRoomOpts { | 
				
			||||
    return { | 
				
			||||
        creation_content: { | 
				
			||||
            type: "m.space", | 
				
			||||
        }, | 
				
			||||
        initial_state: [{ | 
				
			||||
            type: "m.room.name", | 
				
			||||
            content: { | 
				
			||||
                name: spaceName, | 
				
			||||
            }, | 
				
			||||
        }], | 
				
			||||
    }; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
function spaceChildInitialState(roomId: string): ICreateRoomOpts["initial_state"]["0"] { | 
				
			||||
    return { | 
				
			||||
        type: "m.space.child", | 
				
			||||
        state_key: roomId, | 
				
			||||
        content: { | 
				
			||||
            via: [roomId.split(":")[1]], | 
				
			||||
        }, | 
				
			||||
    }; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
describe("Spaces", () => { | 
				
			||||
    let synapse: SynapseInstance; | 
				
			||||
    let user: UserCredentials; | 
				
			||||
 | 
				
			||||
    beforeEach(() => { | 
				
			||||
        cy.startSynapse("default").then(data => { | 
				
			||||
            synapse = data; | 
				
			||||
 | 
				
			||||
            cy.initTestUser(synapse, "Sue").then(_user => { | 
				
			||||
                user = _user; | 
				
			||||
                cy.mockClipboard(); | 
				
			||||
            }); | 
				
			||||
        }); | 
				
			||||
    }); | 
				
			||||
 | 
				
			||||
    afterEach(() => { | 
				
			||||
        cy.stopSynapse(synapse); | 
				
			||||
    }); | 
				
			||||
 | 
				
			||||
    it("should allow user to create public space", () => { | 
				
			||||
        openSpaceCreateMenu().within(() => { | 
				
			||||
            cy.get(".mx_SpaceCreateMenuType_public").click(); | 
				
			||||
            cy.get('.mx_SpaceBasicSettings_avatarContainer input[type="file"]') | 
				
			||||
                .selectFile("cypress/fixtures/riot.png", { force: true }); | 
				
			||||
            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!"); | 
				
			||||
            cy.get(".mx_AccessibleButton").contains("Create").click(); | 
				
			||||
        }); | 
				
			||||
 | 
				
			||||
        // 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"); | 
				
			||||
        cy.get(".mx_AccessibleButton").contains("Continue").click(); | 
				
			||||
 | 
				
			||||
        // 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
 | 
				
			||||
        cy.get(".mx_AccessibleButton").contains("Go to my first room").click(); | 
				
			||||
 | 
				
			||||
        // Assert rooms exist in the room list
 | 
				
			||||
        cy.get(".mx_RoomTile").contains("General").should("exist"); | 
				
			||||
        cy.get(".mx_RoomTile").contains("Random").should("exist"); | 
				
			||||
        cy.get(".mx_RoomTile").contains("Jokes").should("exist"); | 
				
			||||
    }); | 
				
			||||
 | 
				
			||||
    it("should allow user to create private space", () => { | 
				
			||||
        openSpaceCreateMenu().within(() => { | 
				
			||||
            cy.get(".mx_SpaceCreateMenuType_private").click(); | 
				
			||||
            cy.get('.mx_SpaceBasicSettings_avatarContainer input[type="file"]') | 
				
			||||
                .selectFile("cypress/fixtures/riot.png", { force: true }); | 
				
			||||
            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..."); | 
				
			||||
            cy.get(".mx_AccessibleButton").contains("Create").click(); | 
				
			||||
        }); | 
				
			||||
 | 
				
			||||
        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"); | 
				
			||||
        cy.get(".mx_AccessibleButton").contains("Continue").click(); | 
				
			||||
 | 
				
			||||
        cy.get(".mx_SpaceRoomView").should("contain", "Invite your teammates"); | 
				
			||||
        cy.get(".mx_AccessibleButton").contains("Skip for now").click(); | 
				
			||||
 | 
				
			||||
        // Assert rooms exist in the room list
 | 
				
			||||
        cy.get(".mx_RoomTile").contains("General").should("exist"); | 
				
			||||
        cy.get(".mx_RoomTile").contains("Random").should("exist"); | 
				
			||||
        cy.get(".mx_RoomTile").contains("Projects").should("exist"); | 
				
			||||
 | 
				
			||||
        // Assert rooms exist in the space explorer
 | 
				
			||||
        cy.get(".mx_SpaceHierarchy_roomTile").contains("General").should("exist"); | 
				
			||||
        cy.get(".mx_SpaceHierarchy_roomTile").contains("Random").should("exist"); | 
				
			||||
        cy.get(".mx_SpaceHierarchy_roomTile").contains("Projects").should("exist"); | 
				
			||||
    }); | 
				
			||||
 | 
				
			||||
    it("should allow user to create just-me space", () => { | 
				
			||||
        cy.createRoom({ | 
				
			||||
            name: "Sample Room", | 
				
			||||
        }); | 
				
			||||
 | 
				
			||||
        openSpaceCreateMenu().within(() => { | 
				
			||||
            cy.get(".mx_SpaceCreateMenuType_private").click(); | 
				
			||||
            cy.get('.mx_SpaceBasicSettings_avatarContainer input[type="file"]') | 
				
			||||
                .selectFile("cypress/fixtures/riot.png", { force: true }); | 
				
			||||
            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(); | 
				
			||||
        cy.get(".mx_AccessibleButton").contains("Add").click(); | 
				
			||||
 | 
				
			||||
        cy.get(".mx_RoomTile").contains("Sample Room").should("exist"); | 
				
			||||
        cy.get(".mx_SpaceHierarchy_roomTile").contains("Sample Room").should("exist"); | 
				
			||||
    }); | 
				
			||||
 | 
				
			||||
    it("should allow user to invite another to a space", () => { | 
				
			||||
        let bot: MatrixClient; | 
				
			||||
        cy.getBot(synapse, "BotBob").then(_bot => { | 
				
			||||
            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()); | 
				
			||||
            cy.get(".mx_AccessibleButton").contains("Invite").click(); | 
				
			||||
        }); | 
				
			||||
 | 
				
			||||
        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", | 
				
			||||
        }); | 
				
			||||
        getSpacePanelButton("My Space").should("exist"); | 
				
			||||
 | 
				
			||||
        cy.getBot(synapse, "BotBob").then({ timeout: 10000 }, async bot => { | 
				
			||||
            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
 | 
				
			||||
        getSpacePanelButton("Space Space").should("exist") | 
				
			||||
            .parent().next().find('.mx_SpaceButton[aria-label="My Space"]').should("exist"); | 
				
			||||
    }); | 
				
			||||
 | 
				
			||||
    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"; | 
				
			||||
        cy.all([ | 
				
			||||
            cy.get<string>("@roomId1"), | 
				
			||||
            cy.get<string>("@roomId2"), | 
				
			||||
        ]).then(([roomId1, roomId2]) => { | 
				
			||||
            cy.createSpace({ | 
				
			||||
                name: spaceName, | 
				
			||||
                initial_state: [ | 
				
			||||
                    spaceChildInitialState(roomId1), | 
				
			||||
                    spaceChildInitialState(roomId2), | 
				
			||||
                ], | 
				
			||||
            }).as("spaceId"); | 
				
			||||
        }); | 
				
			||||
 | 
				
			||||
        cy.get("@spaceId").then(() => { | 
				
			||||
            getSpacePanelButton(spaceName).dblclick(); // Open space home
 | 
				
			||||
        }); | 
				
			||||
        cy.get(".mx_SpaceRoomView .mx_SpaceHierarchy_list").within(() => { | 
				
			||||
            cy.get(".mx_SpaceHierarchy_roomTile").contains("Music").should("exist"); | 
				
			||||
            cy.get(".mx_SpaceHierarchy_roomTile").contains("Gaming").should("exist"); | 
				
			||||
        }); | 
				
			||||
    }); | 
				
			||||
}); | 
				
			||||
@ -0,0 +1,57 @@ | 
				
			||||
/* | 
				
			||||
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 Chainable = Cypress.Chainable; | 
				
			||||
 | 
				
			||||
// Mock the clipboard, as only Electron gives the app permission to the clipboard API by default
 | 
				
			||||
// Virtual clipboard
 | 
				
			||||
let copyText: string; | 
				
			||||
 | 
				
			||||
declare global { | 
				
			||||
    // eslint-disable-next-line @typescript-eslint/no-namespace
 | 
				
			||||
    namespace Cypress { | 
				
			||||
        interface Chainable { | 
				
			||||
            /** | 
				
			||||
             * Mock the clipboard on the current window, ready for calling `getClipboardText`. | 
				
			||||
             * Irreversible, refresh the window to restore mock. | 
				
			||||
             */ | 
				
			||||
            mockClipboard(): Chainable<AUTWindow>; | 
				
			||||
            /** | 
				
			||||
             * Read text from the mocked clipboard. | 
				
			||||
             * @return {string} the clipboard text | 
				
			||||
             */ | 
				
			||||
            getClipboardText(): Chainable<string>; | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
 | 
				
			||||
Cypress.Commands.add("mockClipboard", () => { | 
				
			||||
    cy.window({ log: false }).then(win => { | 
				
			||||
        win.navigator.clipboard.writeText = (text) => { | 
				
			||||
            copyText = text; | 
				
			||||
            return Promise.resolve(); | 
				
			||||
        }; | 
				
			||||
    }); | 
				
			||||
}); | 
				
			||||
 | 
				
			||||
Cypress.Commands.add("getClipboardText", (): Chainable<string> => { | 
				
			||||
    return cy.wrap(copyText); | 
				
			||||
}); | 
				
			||||
 | 
				
			||||
// Needed to make this file a module
 | 
				
			||||
export { }; | 
				
			||||
@ -0,0 +1,82 @@ | 
				
			||||
/* | 
				
			||||
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" />
 | 
				
			||||
 | 
				
			||||
// @see https://github.com/cypress-io/cypress/issues/915#issuecomment-475862672
 | 
				
			||||
// Modified due to changes to `cy.queue` https://github.com/cypress-io/cypress/pull/17448
 | 
				
			||||
// Note: this DOES NOT run Promises in parallel like `Promise.all` due to the nature
 | 
				
			||||
// of Cypress promise-like objects and command queue. This only makes it convenient to use the same
 | 
				
			||||
// API but runs the commands sequentially.
 | 
				
			||||
 | 
				
			||||
declare global { | 
				
			||||
    // eslint-disable-next-line @typescript-eslint/no-namespace
 | 
				
			||||
    namespace Cypress { | 
				
			||||
        type ChainableValue<T> = T extends Cypress.Chainable<infer V> ? V : T; | 
				
			||||
 | 
				
			||||
        interface cy { | 
				
			||||
            all<T extends Cypress.Chainable[] | []>( | 
				
			||||
                commands: T | 
				
			||||
            ): Cypress.Chainable<{ [P in keyof T]: ChainableValue<T[P]> }>; | 
				
			||||
            queue: any; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        interface Chainable { | 
				
			||||
            chainerId: string; | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
 | 
				
			||||
const chainStart = Symbol("chainStart"); | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * @description Returns a single Chainable that resolves when all of the Chainables pass. | 
				
			||||
 * @param {Cypress.Chainable[]} commands - List of Cypress.Chainable to resolve. | 
				
			||||
 * @returns {Cypress.Chainable} Cypress when all Chainables are resolved. | 
				
			||||
 */ | 
				
			||||
cy.all = function all(commands): Cypress.Chainable { | 
				
			||||
    const chain = cy.wrap(null, { log: false }); | 
				
			||||
    const stopCommand = Cypress._.find(cy.queue.get(), { | 
				
			||||
        attributes: { chainerId: chain.chainerId }, | 
				
			||||
    }); | 
				
			||||
    const startCommand = Cypress._.find(cy.queue.get(), { | 
				
			||||
        attributes: { chainerId: commands[0].chainerId }, | 
				
			||||
    }); | 
				
			||||
    const p = chain.then(() => { | 
				
			||||
        return cy.wrap( | 
				
			||||
            // @see https://lodash.com/docs/4.17.15#lodash
 | 
				
			||||
            Cypress._(commands) | 
				
			||||
                .map(cmd => { | 
				
			||||
                    return cmd[chainStart] | 
				
			||||
                        ? cmd[chainStart].attributes | 
				
			||||
                        : Cypress._.find(cy.queue.get(), { | 
				
			||||
                            attributes: { chainerId: cmd.chainerId }, | 
				
			||||
                        }).attributes; | 
				
			||||
                }) | 
				
			||||
                .concat(stopCommand.attributes) | 
				
			||||
                .slice(1) | 
				
			||||
                .map(cmd => { | 
				
			||||
                    return cmd.prev.get("subject"); | 
				
			||||
                }) | 
				
			||||
                .value(), | 
				
			||||
        ); | 
				
			||||
    }); | 
				
			||||
    p[chainStart] = startCommand; | 
				
			||||
    return p; | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
// Needed to make this file a module
 | 
				
			||||
export { }; | 
				
			||||
@ -1,33 +0,0 @@ | 
				
			||||
/* | 
				
			||||
Copyright 2021 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. | 
				
			||||
*/ | 
				
			||||
 | 
				
			||||
import { createSpace, inviteSpace } from "../usecases/create-space"; | 
				
			||||
import { ElementSession } from "../session"; | 
				
			||||
 | 
				
			||||
export async function spacesScenarios(alice: ElementSession, bob: ElementSession): Promise<void> { | 
				
			||||
    console.log(" creating a space for spaces scenarios:"); | 
				
			||||
 | 
				
			||||
    await alice.delay(1000); // wait for dialogs to close
 | 
				
			||||
    await setupSpaceUsingAliceAndInviteBob(alice, bob); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
const space = "Test Space"; | 
				
			||||
 | 
				
			||||
async function setupSpaceUsingAliceAndInviteBob(alice: ElementSession, bob: ElementSession): Promise<void> { | 
				
			||||
    await createSpace(alice, space); | 
				
			||||
    await inviteSpace(alice, space, "@bob:localhost"); | 
				
			||||
    await bob.query(`.mx_SpaceButton[aria-label="${space}"]`); // assert invite received
 | 
				
			||||
} | 
				
			||||
@ -1,82 +0,0 @@ | 
				
			||||
/* | 
				
			||||
Copyright 2021 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. | 
				
			||||
*/ | 
				
			||||
 | 
				
			||||
import { ElementSession } from "../session"; | 
				
			||||
 | 
				
			||||
export async function openSpaceCreateMenu(session: ElementSession): Promise<void> { | 
				
			||||
    const spaceCreateButton = await session.query('.mx_SpaceButton_new'); | 
				
			||||
    await spaceCreateButton.click(); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
export async function createSpace(session: ElementSession, name: string, isPublic = false): Promise<void> { | 
				
			||||
    session.log.step(`creates space "${name}"`); | 
				
			||||
 | 
				
			||||
    await openSpaceCreateMenu(session); | 
				
			||||
    const className = isPublic ? ".mx_SpaceCreateMenuType_public" : ".mx_SpaceCreateMenuType_private"; | 
				
			||||
    const visibilityButton = await session.query(className); | 
				
			||||
    await visibilityButton.click(); | 
				
			||||
 | 
				
			||||
    const nameInput = await session.query('input[name="spaceName"]'); | 
				
			||||
    await session.replaceInputText(nameInput, name); | 
				
			||||
 | 
				
			||||
    await session.delay(100); | 
				
			||||
 | 
				
			||||
    const createButton = await session.query('.mx_SpaceCreateMenu_wrapper .mx_AccessibleButton_kind_primary'); | 
				
			||||
    await createButton.click(); | 
				
			||||
 | 
				
			||||
    if (!isPublic) { | 
				
			||||
        const justMeButton = await session.query('.mx_SpaceRoomView_privateScope_justMeButton'); | 
				
			||||
        await justMeButton.click(); | 
				
			||||
        const continueButton = await session.query('.mx_AddExistingToSpace_footer .mx_AccessibleButton_kind_primary'); | 
				
			||||
        await continueButton.click(); | 
				
			||||
    } else { | 
				
			||||
        for (let i = 0; i < 2; i++) { | 
				
			||||
            const continueButton = await session.query('.mx_SpaceRoomView_buttons .mx_AccessibleButton_kind_primary'); | 
				
			||||
            await continueButton.click(); | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    session.log.done(); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
export async function inviteSpace(session: ElementSession, spaceName: string, userId: string): Promise<void> { | 
				
			||||
    session.log.step(`invites "${userId}" to space "${spaceName}"`); | 
				
			||||
 | 
				
			||||
    const spaceButton = await session.query(`.mx_SpaceButton[aria-label="${spaceName}"]`); | 
				
			||||
    await spaceButton.click({ | 
				
			||||
        button: 'right', | 
				
			||||
    }); | 
				
			||||
 | 
				
			||||
    const inviteButton = await session.query('.mx_SpacePanel_contextMenu_inviteButton[aria-label="Invite"]'); | 
				
			||||
    await inviteButton.click(); | 
				
			||||
 | 
				
			||||
    try { | 
				
			||||
        // You only get this interstitial if it's a public space, so give up after 200ms
 | 
				
			||||
        // if it hasn't appeared
 | 
				
			||||
        const button = await session.query('.mx_SpacePublicShare_inviteButton', 200); | 
				
			||||
        await button.click(); | 
				
			||||
    } catch (e) { | 
				
			||||
        // ignore
 | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    const inviteTextArea = await session.query(".mx_InviteDialog_editor input"); | 
				
			||||
    await inviteTextArea.type(userId); | 
				
			||||
    const selectUserItem = await session.query(".mx_InviteDialog_roomTile"); | 
				
			||||
    await selectUserItem.click(); | 
				
			||||
    const confirmButton = await session.query(".mx_InviteDialog_goButton"); | 
				
			||||
    await confirmButton.click(); | 
				
			||||
    session.log.done(); | 
				
			||||
} | 
				
			||||
					Loading…
					
					
				
		Reference in new issue