Merge branch 'develop' into johannes/find-myself

This commit is contained in:
Johannes Marbach 2023-02-10 08:26:16 +01:00
commit 6ee6accfc6
16 changed files with 392 additions and 774 deletions

View file

@ -113,10 +113,10 @@ describe("RoomNotifs test", () => {
event: true,
type: "m.room.create",
room: ROOM_ID,
user: client.getUserId()!,
user: "@zoe:localhost",
content: {
...(predecessorId ? { predecessor: { room_id: predecessorId, event_id: "$someevent" } } : {}),
creator: client.getUserId(),
creator: "@zoe:localhost",
room_version: "5",
},
ts: Date.now(),
@ -128,7 +128,7 @@ describe("RoomNotifs test", () => {
event: true,
type: EventType.RoomPredecessor,
room: ROOM_ID,
user: client.getUserId()!,
user: "@zoe:localhost",
skey: "",
content: {
predecessor_room_id: predecessorId,

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>"
`;

View file

@ -14,10 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { fireEvent, render, screen } from "@testing-library/react";
import React from "react";
// eslint-disable-next-line deprecate/import
import { mount } from "enzyme";
import { act } from "react-dom/test-utils";
import LabelledCheckbox from "../../../../src/components/views/elements/LabelledCheckbox";
@ -30,32 +28,18 @@ jest.mock("matrix-js-sdk/src/randomstring", () => {
describe("<LabelledCheckbox />", () => {
type CompProps = React.ComponentProps<typeof LabelledCheckbox>;
const getComponent = (props: CompProps) => mount(<LabelledCheckbox {...props} />);
type CompClass = ReturnType<typeof getComponent>;
const getComponent = (props: CompProps) => <LabelledCheckbox {...props} />;
const getCheckbox = (): HTMLInputElement => screen.getByRole("checkbox");
const getCheckbox = (component: CompClass) => component.find(`input[type="checkbox"]`);
const getLabel = (component: CompClass) => component.find(`.mx_LabelledCheckbox_label`);
const getByline = (component: CompClass) => component.find(`.mx_LabelledCheckbox_byline`);
const isChecked = (checkbox: ReturnType<typeof getCheckbox>) => checkbox.is(`[checked=true]`);
const isDisabled = (checkbox: ReturnType<typeof getCheckbox>) => checkbox.is(`[disabled=true]`);
const getText = (span: ReturnType<typeof getLabel>) => (span.length > 0 ? span.at(0).text() : null);
test.each([null, "this is a byline"])("should render with byline of %p", (byline) => {
it.each([undefined, "this is a byline"])("should render with byline of %p", (byline) => {
const props: CompProps = {
label: "Hello world",
value: true,
byline: byline,
onChange: jest.fn(),
};
const component = getComponent(props);
const checkbox = getCheckbox(component);
expect(component).toMatchSnapshot();
expect(isChecked(checkbox)).toBe(true);
expect(isDisabled(checkbox)).toBe(false);
expect(getText(getLabel(component))).toBe(props.label);
expect(getText(getByline(component))).toBe(byline);
const renderResult = render(getComponent(props));
expect(renderResult.asFragment()).toMatchSnapshot();
});
it("should support unchecked by default", () => {
@ -64,9 +48,8 @@ describe("<LabelledCheckbox />", () => {
value: false,
onChange: jest.fn(),
};
const component = getComponent(props);
expect(isChecked(getCheckbox(component))).toBe(false);
render(getComponent(props));
expect(getCheckbox()).not.toBeChecked();
});
it("should be possible to disable the checkbox", () => {
@ -76,9 +59,8 @@ describe("<LabelledCheckbox />", () => {
disabled: true,
onChange: jest.fn(),
};
const component = getComponent(props);
expect(isDisabled(getCheckbox(component))).toBe(true);
render(getComponent(props));
expect(getCheckbox()).toBeDisabled();
});
it("should emit onChange calls", () => {
@ -87,15 +69,11 @@ describe("<LabelledCheckbox />", () => {
value: false,
onChange: jest.fn(),
};
const component = getComponent(props);
render(getComponent(props));
expect(props.onChange).not.toHaveBeenCalled();
act(() => {
getCheckbox(component).simulate("change");
});
expect(props.onChange).toHaveBeenCalledTimes(1);
fireEvent.click(getCheckbox());
expect(props.onChange).toHaveBeenCalledWith(true);
});
it("should react to value and disabled prop changes", () => {
@ -104,16 +82,18 @@ describe("<LabelledCheckbox />", () => {
value: false,
onChange: jest.fn(),
};
const component = getComponent(props);
let checkbox = getCheckbox(component);
const { rerender } = render(getComponent(props));
expect(isChecked(checkbox)).toBe(false);
expect(isDisabled(checkbox)).toBe(false);
let checkbox = getCheckbox();
expect(checkbox).not.toBeChecked();
expect(checkbox).not.toBeDisabled();
component.setProps({ value: true, disabled: true });
checkbox = getCheckbox(component); // refresh reference to checkbox
props.disabled = true;
props.value = true;
rerender(getComponent(props));
expect(isChecked(checkbox)).toBe(true);
expect(isDisabled(checkbox)).toBe(true);
checkbox = getCheckbox();
expect(checkbox).toBeChecked();
expect(checkbox).toBeDisabled();
});
});

View file

@ -1,106 +1,82 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<LabelledCheckbox /> should render with byline of "this is a byline" 1`] = `
<LabelledCheckbox
byline="this is a byline"
label="Hello world"
onChange={[MockFunction]}
value={true}
>
<DocumentFragment>
<label
className="mx_LabelledCheckbox"
class="mx_LabelledCheckbox"
>
<StyledCheckbox
checked={true}
className=""
onChange={[Function]}
<span
class="mx_Checkbox mx_Checkbox_hasKind mx_Checkbox_kind_solid"
>
<span
className="mx_Checkbox mx_Checkbox_hasKind mx_Checkbox_kind_solid"
<input
checked=""
id="checkbox_abdefghi"
type="checkbox"
/>
<label
for="checkbox_abdefghi"
>
<input
checked={true}
id="checkbox_abdefghi"
onChange={[Function]}
type="checkbox"
/>
<label
htmlFor="checkbox_abdefghi"
<div
class="mx_Checkbox_background"
>
<div
className="mx_Checkbox_background"
>
<div
className="mx_Checkbox_checkmark"
/>
</div>
</label>
</span>
</StyledCheckbox>
class="mx_Checkbox_checkmark"
/>
</div>
</label>
</span>
<div
className="mx_LabelledCheckbox_labels"
class="mx_LabelledCheckbox_labels"
>
<span
className="mx_LabelledCheckbox_label"
class="mx_LabelledCheckbox_label"
>
Hello world
</span>
<span
className="mx_LabelledCheckbox_byline"
class="mx_LabelledCheckbox_byline"
>
this is a byline
</span>
</div>
</label>
</LabelledCheckbox>
</DocumentFragment>
`;
exports[`<LabelledCheckbox /> should render with byline of null 1`] = `
<LabelledCheckbox
byline={null}
label="Hello world"
onChange={[MockFunction]}
value={true}
>
exports[`<LabelledCheckbox /> should render with byline of undefined 1`] = `
<DocumentFragment>
<label
className="mx_LabelledCheckbox"
class="mx_LabelledCheckbox"
>
<StyledCheckbox
checked={true}
className=""
onChange={[Function]}
<span
class="mx_Checkbox mx_Checkbox_hasKind mx_Checkbox_kind_solid"
>
<span
className="mx_Checkbox mx_Checkbox_hasKind mx_Checkbox_kind_solid"
<input
checked=""
id="checkbox_abdefghi"
type="checkbox"
/>
<label
for="checkbox_abdefghi"
>
<input
checked={true}
id="checkbox_abdefghi"
onChange={[Function]}
type="checkbox"
/>
<label
htmlFor="checkbox_abdefghi"
<div
class="mx_Checkbox_background"
>
<div
className="mx_Checkbox_background"
>
<div
className="mx_Checkbox_checkmark"
/>
</div>
</label>
</span>
</StyledCheckbox>
class="mx_Checkbox_checkmark"
/>
</div>
</label>
</span>
<div
className="mx_LabelledCheckbox_labels"
class="mx_LabelledCheckbox_labels"
>
<span
className="mx_LabelledCheckbox_label"
class="mx_LabelledCheckbox_label"
>
Hello world
</span>
</div>
</label>
</LabelledCheckbox>
</DocumentFragment>
`;

View file

@ -24,34 +24,64 @@ import * as TestUtils from "../../../test-utils";
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
import EditorModel from "../../../../src/editor/model";
import { createPartCreator, createRenderer } from "../../../editor/mock";
import SettingsStore from "../../../../src/settings/SettingsStore";
describe("BasicMessageComposer", () => {
const renderer = createRenderer();
const pc = createPartCreator();
beforeEach(() => {
TestUtils.stubClient();
});
TestUtils.stubClient();
it("should allow a user to paste a URL without it being mangled", () => {
const client: MatrixClient = MatrixClientPeg.get();
const roomId = "!1234567890:domain";
const userId = client.getSafeUserId();
const room = new Room(roomId, client, userId);
it("should allow a user to paste a URL without it being mangled", async () => {
const model = new EditorModel([], pc, renderer);
const client: MatrixClient = MatrixClientPeg.get();
const roomId = "!1234567890:domain";
const userId = client.getSafeUserId();
const room = new Room(roomId, client, userId);
render(<BasicMessageComposer model={model} room={room} />);
const testUrl = "https://element.io";
const mockDataTransfer = generateMockDataTransferForString(testUrl);
render(<BasicMessageComposer model={model} room={room} />);
userEvent.paste(mockDataTransfer);
await userEvent.paste(mockDataTransfer);
expect(model.parts).toHaveLength(1);
expect(model.parts[0].text).toBe(testUrl);
expect(screen.getByText(testUrl)).toBeInTheDocument();
});
it("should replaceEmoticons properly", async () => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName: string) => {
return settingName === "MessageComposerInput.autoReplaceEmoji";
});
userEvent.setup();
const model = new EditorModel([], pc, renderer);
render(<BasicMessageComposer model={model} room={room} />);
const tranformations = [
{ before: "4:3 video", after: "4:3 video" },
{ before: "regexp 12345678", after: "regexp 12345678" },
{ before: "--:--)", after: "--:--)" },
{ before: "we <3 matrix", after: "we ❤️ matrix" },
{ before: "hello world :-)", after: "hello world 🙂" },
{ before: ":) hello world", after: "🙂 hello world" },
{ before: ":D 4:3 video :)", after: "😄 4:3 video 🙂" },
{ before: ":-D", after: "😄" },
{ before: ":D", after: "😄" },
{ before: ":3", after: "😽" },
];
const input = screen.getByRole("textbox");
for (const { before, after } of tranformations) {
await userEvent.clear(input);
//add a space after the text to trigger the replacement
await userEvent.type(input, before + " ");
const transformedText = model.parts.map((part) => part.text).join("");
expect(transformedText).toBe(after + " ");
}
});
});
function generateMockDataTransferForString(string: string): DataTransfer {

View file

@ -226,6 +226,7 @@ describe("<Notifications />", () => {
setAccountData: jest.fn(),
sendReadReceipt: jest.fn(),
supportsThreads: jest.fn().mockReturnValue(true),
isInitialSyncComplete: jest.fn().mockReturnValue(false),
});
mockClient.getPushRules.mockResolvedValue(pushRules);

View file

@ -94,6 +94,8 @@ describe("RoomViewStore", function () {
getDeviceId: jest.fn().mockReturnValue("ABC123"),
sendStateEvent: jest.fn().mockResolvedValue({}),
supportsThreads: jest.fn(),
isInitialSyncComplete: jest.fn().mockResolvedValue(false),
relations: jest.fn(),
});
const room = new Room(roomId, mockClient, userId);
const room2 = new Room(roomId2, mockClient, userId);