Migrate SpaceContextMenu-test.tsx to react-testing-library (#10120)

This commit is contained in:
Michael Weimann 2023-02-09 12:23:22 +01:00 committed by GitHub
parent a068b1e940
commit 9868d8f39d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 169 additions and 569 deletions

View file

@ -63,7 +63,7 @@ const SpaceContextMenu: React.FC<IProps> = ({ space, hideHeader, onFinished, ...
inviteOption = (
<IconizedContextMenuOption
data-test-id="invite-option"
data-testid="invite-option"
className="mx_SpacePanel_contextMenu_inviteButton"
iconClassName="mx_SpacePanel_iconInvite"
label={_t("Invite")}
@ -85,7 +85,7 @@ const SpaceContextMenu: React.FC<IProps> = ({ space, hideHeader, onFinished, ...
settingsOption = (
<IconizedContextMenuOption
data-test-id="settings-option"
data-testid="settings-option"
iconClassName="mx_SpacePanel_iconSettings"
label={_t("Settings")}
onClick={onSettingsClick}
@ -102,7 +102,7 @@ const SpaceContextMenu: React.FC<IProps> = ({ space, hideHeader, onFinished, ...
leaveOption = (
<IconizedContextMenuOption
data-test-id="leave-option"
data-testid="leave-option"
iconClassName="mx_SpacePanel_iconLeave"
className="mx_IconizedContextMenu_option_red"
label={_t("Leave space")}
@ -172,12 +172,12 @@ const SpaceContextMenu: React.FC<IProps> = ({ space, hideHeader, onFinished, ...
newRoomSection = (
<>
<div data-test-id="add-to-space-header" className="mx_SpacePanel_contextMenu_separatorLabel">
<div data-testid="add-to-space-header" className="mx_SpacePanel_contextMenu_separatorLabel">
{_t("Add")}
</div>
{canAddRooms && (
<IconizedContextMenuOption
data-test-id="new-room-option"
data-testid="new-room-option"
iconClassName="mx_SpacePanel_iconPlus"
label={_t("Room")}
onClick={onNewRoomClick}
@ -185,7 +185,7 @@ const SpaceContextMenu: React.FC<IProps> = ({ space, hideHeader, onFinished, ...
)}
{canAddVideoRooms && (
<IconizedContextMenuOption
data-test-id="new-video-room-option"
data-testid="new-video-room-option"
iconClassName="mx_SpacePanel_iconPlus"
label={_t("Video room")}
onClick={onNewVideoRoomClick}
@ -195,7 +195,7 @@ const SpaceContextMenu: React.FC<IProps> = ({ space, hideHeader, onFinished, ...
)}
{canAddSubSpaces && (
<IconizedContextMenuOption
data-test-id="new-subspace-option"
data-testid="new-subspace-option"
iconClassName="mx_SpacePanel_iconPlus"
label={_t("Space")}
onClick={onNewSubspaceClick}

View file

@ -15,16 +15,14 @@ limitations under the License.
*/
import React from "react";
// eslint-disable-next-line deprecate/import
import { mount } from "enzyme";
import { Room } from "matrix-js-sdk/src/matrix";
import { mocked } from "jest-mock";
import { act } from "react-dom/test-utils";
import { MatrixClient, Room } from "matrix-js-sdk/src/matrix";
import { Mocked, mocked } from "jest-mock";
import "focus-visible"; // to fix context menus
import { prettyDOM, render, RenderResult, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import SpaceContextMenu from "../../../../src/components/views/context_menus/SpaceContextMenu";
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
import { findByTestId } from "../../../test-utils";
import {
shouldShowSpaceSettings,
showCreateNewRoom,
@ -55,9 +53,11 @@ jest.mock("../../../../src/utils/leave-behaviour", () => ({
describe("<SpaceContextMenu />", () => {
const userId = "@test:server";
const mockClient = {
getUserId: jest.fn().mockReturnValue(userId),
};
} as unknown as Mocked<MatrixClient>;
const makeMockSpace = (props = {}) =>
({
name: "test space",
@ -70,17 +70,18 @@ describe("<SpaceContextMenu />", () => {
getMyMembership: jest.fn(),
...props,
} as unknown as Room);
const defaultProps = {
space: makeMockSpace(),
onFinished: jest.fn(),
};
const getComponent = (props = {}) =>
mount(<SpaceContextMenu {...defaultProps} {...props} />, {
wrappingComponent: MatrixClientContext.Provider,
wrappingComponentProps: {
value: mockClient,
},
});
const renderComponent = (props = {}): RenderResult =>
render(
<MatrixClientContext.Provider value={mockClient}>
<SpaceContextMenu {...defaultProps} {...props} />
</MatrixClientContext.Provider>,
);
beforeEach(() => {
jest.resetAllMocks();
@ -88,134 +89,135 @@ describe("<SpaceContextMenu />", () => {
});
it("renders menu correctly", () => {
const component = getComponent();
expect(component).toMatchSnapshot();
const { baseElement } = renderComponent();
expect(prettyDOM(baseElement)).toMatchSnapshot();
});
it("renders invite option when space is public", () => {
const space = makeMockSpace({
getJoinRule: jest.fn().mockReturnValue("public"),
});
const component = getComponent({ space });
expect(findByTestId(component, "invite-option").length).toBeTruthy();
renderComponent({ space });
expect(screen.getByTestId("invite-option")).toBeInTheDocument();
});
it("renders invite option when user is has invite rights for space", () => {
const space = makeMockSpace({
canInvite: jest.fn().mockReturnValue(true),
});
const component = getComponent({ space });
renderComponent({ space });
expect(space.canInvite).toHaveBeenCalledWith(userId);
expect(findByTestId(component, "invite-option").length).toBeTruthy();
expect(screen.getByTestId("invite-option")).toBeInTheDocument();
});
it("opens invite dialog when invite option is clicked", () => {
it("opens invite dialog when invite option is clicked", async () => {
const space = makeMockSpace({
getJoinRule: jest.fn().mockReturnValue("public"),
});
const onFinished = jest.fn();
const component = getComponent({ space, onFinished });
renderComponent({ space, onFinished });
act(() => {
findByTestId(component, "invite-option").at(0).simulate("click");
});
await userEvent.click(screen.getByTestId("invite-option"));
expect(showSpaceInvite).toHaveBeenCalledWith(space);
expect(onFinished).toHaveBeenCalled();
});
it("renders space settings option when user has rights", () => {
mocked(shouldShowSpaceSettings).mockReturnValue(true);
const component = getComponent();
renderComponent();
expect(shouldShowSpaceSettings).toHaveBeenCalledWith(defaultProps.space);
expect(findByTestId(component, "settings-option").length).toBeTruthy();
expect(screen.getByTestId("settings-option")).toBeInTheDocument();
});
it("opens space settings when space settings option is clicked", () => {
it("opens space settings when space settings option is clicked", async () => {
mocked(shouldShowSpaceSettings).mockReturnValue(true);
const onFinished = jest.fn();
const component = getComponent({ onFinished });
renderComponent({ onFinished });
act(() => {
findByTestId(component, "settings-option").at(0).simulate("click");
});
await userEvent.click(screen.getByTestId("settings-option"));
expect(showSpaceSettings).toHaveBeenCalledWith(defaultProps.space);
expect(onFinished).toHaveBeenCalled();
});
it("renders leave option when user does not have rights to see space settings", () => {
const component = getComponent();
expect(findByTestId(component, "leave-option").length).toBeTruthy();
renderComponent();
expect(screen.getByTestId("leave-option")).toBeInTheDocument();
});
it("leaves space when leave option is clicked", () => {
it("leaves space when leave option is clicked", async () => {
const onFinished = jest.fn();
const component = getComponent({ onFinished });
act(() => {
findByTestId(component, "leave-option").at(0).simulate("click");
});
renderComponent({ onFinished });
await userEvent.click(screen.getByTestId("leave-option"));
expect(leaveSpace).toHaveBeenCalledWith(defaultProps.space);
expect(onFinished).toHaveBeenCalled();
});
describe("add children section", () => {
const space = makeMockSpace();
beforeEach(() => {
// set space to allow adding children to space
mocked(space.currentState.maySendStateEvent).mockReturnValue(true);
mocked(shouldShowComponent).mockReturnValue(true);
});
it("does not render section when user does not have permission to add children", () => {
mocked(space.currentState.maySendStateEvent).mockReturnValue(false);
const component = getComponent({ space });
renderComponent({ space });
expect(findByTestId(component, "add-to-space-header").length).toBeFalsy();
expect(findByTestId(component, "new-room-option").length).toBeFalsy();
expect(findByTestId(component, "new-subspace-option").length).toBeFalsy();
expect(screen.queryByTestId("add-to-space-header")).not.toBeInTheDocument();
expect(screen.queryByTestId("new-room-option")).not.toBeInTheDocument();
expect(screen.queryByTestId("new-subspace-option")).not.toBeInTheDocument();
});
it("does not render section when UIComponent customisations disable room and space creation", () => {
mocked(shouldShowComponent).mockReturnValue(false);
const component = getComponent({ space });
renderComponent({ space });
expect(shouldShowComponent).toHaveBeenCalledWith(UIComponent.CreateRooms);
expect(shouldShowComponent).toHaveBeenCalledWith(UIComponent.CreateSpaces);
expect(findByTestId(component, "add-to-space-header").length).toBeFalsy();
expect(findByTestId(component, "new-room-option").length).toBeFalsy();
expect(findByTestId(component, "new-subspace-option").length).toBeFalsy();
expect(screen.queryByTestId("add-to-space-header")).not.toBeInTheDocument();
expect(screen.queryByTestId("new-room-option")).not.toBeInTheDocument();
expect(screen.queryByTestId("new-subspace-option")).not.toBeInTheDocument();
});
it("renders section with add room button when UIComponent customisation allows CreateRoom", () => {
// only allow CreateRoom
mocked(shouldShowComponent).mockImplementation((feature) => feature === UIComponent.CreateRooms);
const component = getComponent({ space });
renderComponent({ space });
expect(findByTestId(component, "add-to-space-header").length).toBeTruthy();
expect(findByTestId(component, "new-room-option").length).toBeTruthy();
expect(findByTestId(component, "new-subspace-option").length).toBeFalsy();
expect(screen.getByTestId("add-to-space-header")).toBeInTheDocument();
expect(screen.getByTestId("new-room-option")).toBeInTheDocument();
expect(screen.queryByTestId("new-subspace-option")).not.toBeInTheDocument();
});
it("renders section with add space button when UIComponent customisation allows CreateSpace", () => {
// only allow CreateSpaces
mocked(shouldShowComponent).mockImplementation((feature) => feature === UIComponent.CreateSpaces);
const component = getComponent({ space });
renderComponent({ space });
expect(findByTestId(component, "add-to-space-header").length).toBeTruthy();
expect(findByTestId(component, "new-room-option").length).toBeFalsy();
expect(findByTestId(component, "new-subspace-option").length).toBeTruthy();
expect(screen.getByTestId("add-to-space-header")).toBeInTheDocument();
expect(screen.queryByTestId("new-room-option")).not.toBeInTheDocument();
expect(screen.getByTestId("new-subspace-option")).toBeInTheDocument();
});
it("opens create room dialog on add room button click", () => {
it("opens create room dialog on add room button click", async () => {
const onFinished = jest.fn();
const component = getComponent({ space, onFinished });
renderComponent({ space, onFinished });
act(() => {
findByTestId(component, "new-room-option").at(0).simulate("click");
});
await userEvent.click(screen.getByTestId("new-room-option"));
expect(showCreateNewRoom).toHaveBeenCalledWith(space);
expect(onFinished).toHaveBeenCalled();
});
it("opens create space dialog on add space button click", () => {
const onFinished = jest.fn();
const component = getComponent({ space, onFinished });
act(() => {
findByTestId(component, "new-subspace-option").at(0).simulate("click");
});
it("opens create space dialog on add space button click", async () => {
const onFinished = jest.fn();
renderComponent({ space, onFinished });
await userEvent.click(screen.getByTestId("new-subspace-option"));
expect(showCreateNewSubspace).toHaveBeenCalledWith(space);
expect(onFinished).toHaveBeenCalled();
});

View file

@ -1,500 +1,98 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<SpaceContextMenu /> renders menu correctly 1`] = `
<SpaceContextMenu
onFinished={[MockFunction]}
space={
{
"canInvite": [MockFunction] {
"calls": [
[
"@test:server",
],
],
"results": [
{
"type": "return",
"value": undefined,
},
],
},
"client": {
"getUserId": [MockFunction] {
"calls": [
[],
],
"results": [
{
"type": "return",
"value": "@test:server",
},
],
},
},
"currentState": {
"maySendStateEvent": [MockFunction] {
"calls": [
[
"m.space.child",
"@test:server",
],
],
"results": [
{
"type": "return",
"value": undefined,
},
],
},
},
"getJoinRule": [MockFunction] {
"calls": [
[],
],
"results": [
{
"type": "return",
"value": undefined,
},
],
},
"getMyMembership": [MockFunction],
"name": "test space",
}
}
>
<IconizedContextMenu
className="mx_SpacePanel_contextMenu"
compact={true}
onFinished={[MockFunction]}
>
<ContextMenu
chevronFace="none"
hasBackground={true}
managed={true}
onFinished={[MockFunction]}
>
<Portal
containerInfo={
<div
id="mx_ContextualMenu_Container"
>
<div
class="mx_ContextualMenu_wrapper"
>
<div
class="mx_ContextualMenu_background"
/>
<div
class="mx_ContextualMenu"
role="menu"
>
<div
class="mx_IconizedContextMenu mx_SpacePanel_contextMenu mx_IconizedContextMenu_compact"
>
<div
class="mx_SpacePanel_contextMenu_header"
>
test space
</div>
<div
class="mx_IconizedContextMenu_optionList"
>
<div
aria-label="Space home"
class="mx_AccessibleButton mx_IconizedContextMenu_item focus-visible"
data-focus-visible-added=""
role="menuitem"
tabindex="0"
>
<span
class="mx_IconizedContextMenu_icon mx_SpacePanel_iconHome"
/>
<span
class="mx_IconizedContextMenu_label"
>
Space home
</span>
</div>
<div
aria-label="Explore rooms"
class="mx_AccessibleButton mx_IconizedContextMenu_item"
role="menuitem"
tabindex="-1"
>
<span
class="mx_IconizedContextMenu_icon mx_SpacePanel_iconExplore"
/>
<span
class="mx_IconizedContextMenu_label"
>
Explore rooms
</span>
</div>
<div
aria-label="Preferences"
class="mx_AccessibleButton mx_IconizedContextMenu_item"
role="menuitem"
tabindex="-1"
>
<span
class="mx_IconizedContextMenu_icon mx_SpacePanel_iconPreferences"
/>
<span
class="mx_IconizedContextMenu_label"
>
Preferences
</span>
</div>
<div
aria-label="Leave space"
class="mx_AccessibleButton mx_IconizedContextMenu_option_red mx_IconizedContextMenu_item"
data-test-id="leave-option"
role="menuitem"
tabindex="-1"
>
<span
class="mx_IconizedContextMenu_icon mx_SpacePanel_iconLeave"
/>
<span
class="mx_IconizedContextMenu_label"
>
Leave space
</span>
</div>
</div>
</div>
</div>
</div>
</div>
}
>
<RovingTabIndexProvider
handleHomeEnd={true}
handleUpDown={true}
onKeyDown={[Function]}
>
<div
className="mx_ContextualMenu_wrapper"
onClick={[Function]}
onContextMenu={[Function]}
onKeyDown={[Function]}
style={
{
"bottom": undefined,
"right": undefined,
}
}
>
<div
className="mx_ContextualMenu_background"
onClick={[Function]}
onContextMenu={[Function]}
style={{}}
/>
<div
className="mx_ContextualMenu"
role="menu"
style={{}}
>
<div
className="mx_IconizedContextMenu mx_SpacePanel_contextMenu mx_IconizedContextMenu_compact"
>
<div
className="mx_SpacePanel_contextMenu_header"
>
test space
</div>
<IconizedContextMenuOptionList
first={true}
>
<div
className="mx_IconizedContextMenu_optionList"
>
<IconizedContextMenuOption
iconClassName="mx_SpacePanel_iconHome"
label="Space home"
onClick={[Function]}
>
<MenuItem
className="mx_IconizedContextMenu_item"
label="Space home"
onClick={[Function]}
>
<RovingAccessibleButton
aria-label="Space home"
className="mx_IconizedContextMenu_item"
onClick={[Function]}
role="menuitem"
>
<AccessibleButton
aria-label="Space home"
className="mx_IconizedContextMenu_item"
element="div"
inputRef={
{
"current": <div
aria-label="Space home"
class="mx_AccessibleButton mx_IconizedContextMenu_item focus-visible"
data-focus-visible-added=""
role="menuitem"
tabindex="0"
>
<span
class="mx_IconizedContextMenu_icon mx_SpacePanel_iconHome"
/>
<span
class="mx_IconizedContextMenu_label"
>
Space home
</span>
</div>,
}
}
onClick={[Function]}
onFocus={[Function]}
role="menuitem"
tabIndex={0}
>
<div
aria-label="Space home"
className="mx_AccessibleButton mx_IconizedContextMenu_item"
onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onKeyUp={[Function]}
role="menuitem"
tabIndex={0}
>
<span
className="mx_IconizedContextMenu_icon mx_SpacePanel_iconHome"
/>
<span
className="mx_IconizedContextMenu_label"
>
Space home
</span>
</div>
</AccessibleButton>
</RovingAccessibleButton>
</MenuItem>
</IconizedContextMenuOption>
<IconizedContextMenuOption
iconClassName="mx_SpacePanel_iconExplore"
label="Explore rooms"
onClick={[Function]}
>
<MenuItem
className="mx_IconizedContextMenu_item"
label="Explore rooms"
onClick={[Function]}
>
<RovingAccessibleButton
aria-label="Explore rooms"
className="mx_IconizedContextMenu_item"
onClick={[Function]}
role="menuitem"
>
<AccessibleButton
aria-label="Explore rooms"
className="mx_IconizedContextMenu_item"
element="div"
inputRef={
{
"current": <div
aria-label="Explore rooms"
class="mx_AccessibleButton mx_IconizedContextMenu_item"
role="menuitem"
tabindex="-1"
>
<span
class="mx_IconizedContextMenu_icon mx_SpacePanel_iconExplore"
/>
<span
class="mx_IconizedContextMenu_label"
>
Explore rooms
</span>
</div>,
}
}
onClick={[Function]}
onFocus={[Function]}
role="menuitem"
tabIndex={-1}
>
<div
aria-label="Explore rooms"
className="mx_AccessibleButton mx_IconizedContextMenu_item"
onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onKeyUp={[Function]}
role="menuitem"
tabIndex={-1}
>
<span
className="mx_IconizedContextMenu_icon mx_SpacePanel_iconExplore"
/>
<span
className="mx_IconizedContextMenu_label"
>
Explore rooms
</span>
</div>
</AccessibleButton>
</RovingAccessibleButton>
</MenuItem>
</IconizedContextMenuOption>
<IconizedContextMenuOption
iconClassName="mx_SpacePanel_iconPreferences"
label="Preferences"
onClick={[Function]}
>
<MenuItem
className="mx_IconizedContextMenu_item"
label="Preferences"
onClick={[Function]}
>
<RovingAccessibleButton
aria-label="Preferences"
className="mx_IconizedContextMenu_item"
onClick={[Function]}
role="menuitem"
>
<AccessibleButton
aria-label="Preferences"
className="mx_IconizedContextMenu_item"
element="div"
inputRef={
{
"current": <div
aria-label="Preferences"
class="mx_AccessibleButton mx_IconizedContextMenu_item"
role="menuitem"
tabindex="-1"
>
<span
class="mx_IconizedContextMenu_icon mx_SpacePanel_iconPreferences"
/>
<span
class="mx_IconizedContextMenu_label"
>
Preferences
</span>
</div>,
}
}
onClick={[Function]}
onFocus={[Function]}
role="menuitem"
tabIndex={-1}
>
<div
aria-label="Preferences"
className="mx_AccessibleButton mx_IconizedContextMenu_item"
onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onKeyUp={[Function]}
role="menuitem"
tabIndex={-1}
>
<span
className="mx_IconizedContextMenu_icon mx_SpacePanel_iconPreferences"
/>
<span
className="mx_IconizedContextMenu_label"
>
Preferences
</span>
</div>
</AccessibleButton>
</RovingAccessibleButton>
</MenuItem>
</IconizedContextMenuOption>
<IconizedContextMenuOption
className="mx_IconizedContextMenu_option_red"
data-test-id="leave-option"
iconClassName="mx_SpacePanel_iconLeave"
label="Leave space"
onClick={[Function]}
>
<MenuItem
className="mx_IconizedContextMenu_option_red mx_IconizedContextMenu_item"
data-test-id="leave-option"
label="Leave space"
onClick={[Function]}
>
<RovingAccessibleButton
aria-label="Leave space"
className="mx_IconizedContextMenu_option_red mx_IconizedContextMenu_item"
data-test-id="leave-option"
onClick={[Function]}
role="menuitem"
>
<AccessibleButton
aria-label="Leave space"
className="mx_IconizedContextMenu_option_red mx_IconizedContextMenu_item"
data-test-id="leave-option"
element="div"
inputRef={
{
"current": <div
aria-label="Leave space"
class="mx_AccessibleButton mx_IconizedContextMenu_option_red mx_IconizedContextMenu_item"
data-test-id="leave-option"
role="menuitem"
tabindex="-1"
>
<span
class="mx_IconizedContextMenu_icon mx_SpacePanel_iconLeave"
/>
<span
class="mx_IconizedContextMenu_label"
>
Leave space
</span>
</div>,
}
}
onClick={[Function]}
onFocus={[Function]}
role="menuitem"
tabIndex={-1}
>
<div
aria-label="Leave space"
className="mx_AccessibleButton mx_IconizedContextMenu_option_red mx_IconizedContextMenu_item"
data-test-id="leave-option"
onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onKeyUp={[Function]}
role="menuitem"
tabIndex={-1}
>
<span
className="mx_IconizedContextMenu_icon mx_SpacePanel_iconLeave"
/>
<span
className="mx_IconizedContextMenu_label"
>
Leave space
</span>
</div>
</AccessibleButton>
</RovingAccessibleButton>
</MenuItem>
</IconizedContextMenuOption>
</div>
</IconizedContextMenuOptionList>
</div>
</div>
</div>
</RovingTabIndexProvider>
</Portal>
</ContextMenu>
</IconizedContextMenu>
</SpaceContextMenu>
"<body>
<div />
<div
id="mx_ContextualMenu_Container"
>
<div
class="mx_ContextualMenu_wrapper"
>
<div
class="mx_ContextualMenu_background"
/>
<div
class="mx_ContextualMenu"
role="menu"
>
<div
class="mx_IconizedContextMenu mx_SpacePanel_contextMenu mx_IconizedContextMenu_compact"
>
<div
class="mx_SpacePanel_contextMenu_header"
>
test space
</div>
<div
class="mx_IconizedContextMenu_optionList"
>
<div
aria-label="Space home"
class="mx_AccessibleButton mx_IconizedContextMenu_item focus-visible"
data-focus-visible-added=""
role="menuitem"
tabindex="0"
>
<span
class="mx_IconizedContextMenu_icon mx_SpacePanel_iconHome"
/>
<span
class="mx_IconizedContextMenu_label"
>
Space home
</span>
</div>
<div
aria-label="Explore rooms"
class="mx_AccessibleButton mx_IconizedContextMenu_item"
role="menuitem"
tabindex="-1"
>
<span
class="mx_IconizedContextMenu_icon mx_SpacePanel_iconExplore"
/>
<span
class="mx_IconizedContextMenu_label"
>
Explore rooms
</span>
</div>
<div
aria-label="Preferences"
class="mx_AccessibleButton mx_IconizedContextMenu_item"
role="menuitem"
tabindex="-1"
>
<span
class="mx_IconizedContextMenu_icon mx_SpacePanel_iconPreferences"
/>
<span
class="mx_IconizedContextMenu_label"
>
Preferences
</span>
</div>
<div
aria-label="Leave space"
class="mx_AccessibleButton mx_IconizedContextMenu_option_red mx_IconizedContextMenu_item"
data-testid="leave-option"
role="menuitem"
tabindex="-1"
>
<span
class="mx_IconizedContextMenu_icon mx_SpacePanel_iconLeave"
/>
<span
class="mx_IconizedContextMenu_label"
>
Leave space
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</body>"
`;