Update tests to prefer RTL over Enzyme (#10247
* Update tests to prefer RTL over Enzyme * Strict typespull/28788/head^2
parent
dd6fc124d7
commit
f40d15388c
|
@ -60,7 +60,7 @@ export default class PlayPauseButton extends React.PureComponent<IProps> {
|
|||
|
||||
return (
|
||||
<AccessibleTooltipButton
|
||||
data-test-id="play-pause-button"
|
||||
data-testid="play-pause-button"
|
||||
className={classes}
|
||||
title={isPlaying ? _t("Pause") : _t("Play")}
|
||||
onClick={this.onClick}
|
||||
|
|
|
@ -15,20 +15,16 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount, ReactWrapper } from "enzyme";
|
||||
import { mocked } from "jest-mock";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { act } from "react-dom/test-utils";
|
||||
import { fireEvent, render, RenderResult } from "@testing-library/react";
|
||||
|
||||
import RecordingPlayback, { PlaybackLayout } from "../../../../src/components/views/audio_messages/RecordingPlayback";
|
||||
import { Playback } from "../../../../src/audio/Playback";
|
||||
import RoomContext, { TimelineRenderingType } from "../../../../src/contexts/RoomContext";
|
||||
import { createAudioContext } from "../../../../src/audio/compat";
|
||||
import { findByTestId, flushPromises } from "../../../test-utils";
|
||||
import PlaybackWaveform from "../../../../src/components/views/audio_messages/PlaybackWaveform";
|
||||
import SeekBar from "../../../../src/components/views/audio_messages/SeekBar";
|
||||
import PlaybackClock from "../../../../src/components/views/audio_messages/PlaybackClock";
|
||||
import { flushPromises } from "../../../test-utils";
|
||||
import { IRoomState } from "../../../../src/components/structures/RoomView";
|
||||
|
||||
jest.mock("../../../../src/audio/compat", () => ({
|
||||
createAudioContext: jest.fn(),
|
||||
|
@ -57,12 +53,13 @@ describe("<RecordingPlayback />", () => {
|
|||
|
||||
const mockChannelData = new Float32Array();
|
||||
|
||||
const defaultRoom = { roomId: "!room:server.org", timelineRenderingType: TimelineRenderingType.File };
|
||||
const defaultRoom = { roomId: "!room:server.org", timelineRenderingType: TimelineRenderingType.File } as IRoomState;
|
||||
const getComponent = (props: React.ComponentProps<typeof RecordingPlayback>, room = defaultRoom) =>
|
||||
mount(<RecordingPlayback {...props} />, {
|
||||
wrappingComponent: RoomContext.Provider,
|
||||
wrappingComponentProps: { value: room },
|
||||
});
|
||||
render(
|
||||
<RoomContext.Provider value={room}>
|
||||
<RecordingPlayback {...props} />
|
||||
</RoomContext.Provider>,
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(logger, "error").mockRestore();
|
||||
|
@ -71,7 +68,7 @@ describe("<RecordingPlayback />", () => {
|
|||
mocked(createAudioContext).mockReturnValue(mockAudioContext as unknown as AudioContext);
|
||||
});
|
||||
|
||||
const getPlayButton = (component: ReactWrapper) => findByTestId(component, "play-pause-button").at(0);
|
||||
const getPlayButton = (component: RenderResult) => component.getByTestId("play-pause-button");
|
||||
|
||||
it("renders recording playback", () => {
|
||||
const playback = new Playback(new ArrayBuffer(8));
|
||||
|
@ -82,15 +79,16 @@ describe("<RecordingPlayback />", () => {
|
|||
it("disables play button while playback is decoding", async () => {
|
||||
const playback = new Playback(new ArrayBuffer(8));
|
||||
const component = getComponent({ playback });
|
||||
expect(getPlayButton(component).props().disabled).toBeTruthy();
|
||||
expect(getPlayButton(component)).toHaveAttribute("disabled");
|
||||
expect(getPlayButton(component)).toHaveAttribute("aria-disabled", "true");
|
||||
});
|
||||
|
||||
it("enables play button when playback is finished decoding", async () => {
|
||||
const playback = new Playback(new ArrayBuffer(8));
|
||||
const component = getComponent({ playback });
|
||||
await flushPromises();
|
||||
component.setProps({});
|
||||
expect(getPlayButton(component).props().disabled).toBeFalsy();
|
||||
expect(getPlayButton(component)).not.toHaveAttribute("disabled");
|
||||
expect(getPlayButton(component)).not.toHaveAttribute("aria-disabled", "true");
|
||||
});
|
||||
|
||||
it("displays error when playback decoding fails", async () => {
|
||||
|
@ -101,7 +99,7 @@ describe("<RecordingPlayback />", () => {
|
|||
const playback = new Playback(new ArrayBuffer(8));
|
||||
const component = getComponent({ playback });
|
||||
await flushPromises();
|
||||
expect(component.find(".text-warning").length).toBeFalsy();
|
||||
expect(component.container.querySelector(".text-warning")).toBeDefined();
|
||||
});
|
||||
|
||||
it("displays pre-prepared playback with correct playback phase", async () => {
|
||||
|
@ -109,8 +107,9 @@ describe("<RecordingPlayback />", () => {
|
|||
await playback.prepare();
|
||||
const component = getComponent({ playback });
|
||||
// playback already decoded, button is not disabled
|
||||
expect(getPlayButton(component).props().disabled).toBeFalsy();
|
||||
expect(component.find(".text-warning").length).toBeFalsy();
|
||||
expect(getPlayButton(component)).not.toHaveAttribute("disabled");
|
||||
expect(getPlayButton(component)).not.toHaveAttribute("aria-disabled", "true");
|
||||
expect(component.container.querySelector(".text-warning")).toBeFalsy();
|
||||
});
|
||||
|
||||
it("toggles playback on play pause button click", async () => {
|
||||
|
@ -119,9 +118,7 @@ describe("<RecordingPlayback />", () => {
|
|||
await playback.prepare();
|
||||
const component = getComponent({ playback });
|
||||
|
||||
act(() => {
|
||||
getPlayButton(component).simulate("click");
|
||||
});
|
||||
fireEvent.click(getPlayButton(component));
|
||||
|
||||
expect(playback.toggle).toHaveBeenCalled();
|
||||
});
|
||||
|
@ -131,9 +128,9 @@ describe("<RecordingPlayback />", () => {
|
|||
const playback = new Playback(new ArrayBuffer(8));
|
||||
const component = getComponent({ playback, layout: PlaybackLayout.Composer });
|
||||
|
||||
expect(component.find(PlaybackClock).length).toBeTruthy();
|
||||
expect(component.find(PlaybackWaveform).length).toBeTruthy();
|
||||
expect(component.find(SeekBar).length).toBeFalsy();
|
||||
expect(component.container.querySelector(".mx_Clock")).toBeDefined();
|
||||
expect(component.container.querySelector(".mx_Waveform")).toBeDefined();
|
||||
expect(component.container.querySelector(".mx_SeekBar")).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -142,18 +139,18 @@ describe("<RecordingPlayback />", () => {
|
|||
const playback = new Playback(new ArrayBuffer(8));
|
||||
const component = getComponent({ playback, layout: PlaybackLayout.Timeline });
|
||||
|
||||
expect(component.find(PlaybackClock).length).toBeTruthy();
|
||||
expect(component.find(PlaybackWaveform).length).toBeTruthy();
|
||||
expect(component.find(SeekBar).length).toBeTruthy();
|
||||
expect(component.container.querySelector(".mx_Clock")).toBeDefined();
|
||||
expect(component.container.querySelector(".mx_Waveform")).toBeDefined();
|
||||
expect(component.container.querySelector(".mx_SeekBar")).toBeDefined();
|
||||
});
|
||||
|
||||
it("should be the default", () => {
|
||||
const playback = new Playback(new ArrayBuffer(8));
|
||||
const component = getComponent({ playback }); // no layout set for test
|
||||
|
||||
expect(component.find(PlaybackClock).length).toBeTruthy();
|
||||
expect(component.find(PlaybackWaveform).length).toBeTruthy();
|
||||
expect(component.find(SeekBar).length).toBeTruthy();
|
||||
expect(component.container.querySelector(".mx_Clock")).toBeDefined();
|
||||
expect(component.container.querySelector(".mx_Waveform")).toBeDefined();
|
||||
expect(component.container.querySelector(".mx_SeekBar")).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -17,9 +17,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import React from "react";
|
||||
import { act } from "react-dom/test-utils";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount, ReactWrapper } from "enzyme";
|
||||
import { fireEvent, render, RenderResult } from "@testing-library/react";
|
||||
|
||||
import InteractiveAuthComponent from "../../../../src/components/structures/InteractiveAuth";
|
||||
import { flushPromises, getMockClientWithEventEmitter, unmockClientPeg } from "../../../test-utils";
|
||||
|
@ -34,7 +32,7 @@ describe("InteractiveAuthComponent", function () {
|
|||
makeRequest: jest.fn().mockResolvedValue(undefined),
|
||||
onAuthFinished: jest.fn(),
|
||||
};
|
||||
const getComponent = (props = {}) => mount(<InteractiveAuthComponent {...defaultProps} {...props} />);
|
||||
const getComponent = (props = {}) => render(<InteractiveAuthComponent {...defaultProps} {...props} />);
|
||||
|
||||
beforeEach(function () {
|
||||
jest.clearAllMocks();
|
||||
|
@ -44,9 +42,10 @@ describe("InteractiveAuthComponent", function () {
|
|||
unmockClientPeg();
|
||||
});
|
||||
|
||||
const getSubmitButton = (wrapper: ReactWrapper) => wrapper.find('AccessibleButton[kind="primary"]').at(0);
|
||||
const getRegistrationTokenInput = (wrapper: ReactWrapper) =>
|
||||
wrapper.find('input[name="registrationTokenField"]').at(0);
|
||||
const getSubmitButton = ({ container }: RenderResult) =>
|
||||
container.querySelector(".mx_AccessibleButton_kind_primary");
|
||||
const getRegistrationTokenInput = ({ container }: RenderResult) =>
|
||||
container.querySelector('input[name="registrationTokenField"]');
|
||||
|
||||
it("Should successfully complete a registration token flow", async () => {
|
||||
const onAuthFinished = jest.fn();
|
||||
|
@ -61,28 +60,25 @@ describe("InteractiveAuthComponent", function () {
|
|||
|
||||
const registrationTokenNode = getRegistrationTokenInput(wrapper);
|
||||
const submitNode = getSubmitButton(wrapper);
|
||||
const formNode = wrapper.find("form").at(0);
|
||||
const formNode = wrapper.container.querySelector("form");
|
||||
|
||||
expect(registrationTokenNode).toBeTruthy();
|
||||
expect(submitNode).toBeTruthy();
|
||||
expect(formNode).toBeTruthy();
|
||||
|
||||
// submit should be disabled
|
||||
expect(submitNode.props().disabled).toBe(true);
|
||||
expect(submitNode).toHaveAttribute("disabled");
|
||||
expect(submitNode).toHaveAttribute("aria-disabled", "true");
|
||||
|
||||
// put something in the registration token box
|
||||
act(() => {
|
||||
registrationTokenNode.simulate("change", { target: { value: "s3kr3t" } });
|
||||
wrapper.setProps({});
|
||||
});
|
||||
fireEvent.change(registrationTokenNode!, { target: { value: "s3kr3t" } });
|
||||
|
||||
expect(getRegistrationTokenInput(wrapper).props().value).toEqual("s3kr3t");
|
||||
expect(getSubmitButton(wrapper).props().disabled).toBe(false);
|
||||
expect(getRegistrationTokenInput(wrapper)).toHaveValue("s3kr3t");
|
||||
expect(submitNode).not.toHaveAttribute("disabled");
|
||||
expect(submitNode).not.toHaveAttribute("aria-disabled", "true");
|
||||
|
||||
// hit enter; that should trigger a request
|
||||
act(() => {
|
||||
formNode.simulate("submit");
|
||||
});
|
||||
fireEvent.submit(formNode!);
|
||||
|
||||
// wait for auth request to resolve
|
||||
await flushPromises();
|
||||
|
|
|
@ -15,8 +15,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import React from "react";
|
||||
import { act } from "react-dom/test-utils";
|
||||
import { fireEvent, render, RenderResult } from "@testing-library/react";
|
||||
import { act, fireEvent, render, RenderResult } from "@testing-library/react";
|
||||
import { MatrixClient, MatrixEvent, Room, RoomMember, getBeaconInfoIdentifier } from "matrix-js-sdk/src/matrix";
|
||||
import * as maplibregl from "maplibre-gl";
|
||||
import { mocked } from "jest-mock";
|
||||
|
|
|
@ -18,6 +18,7 @@ import React from "react";
|
|||
// eslint-disable-next-line deprecate/import
|
||||
import { mount, ReactWrapper } from "enzyme";
|
||||
import { mocked } from "jest-mock";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { act } from "react-dom/test-utils";
|
||||
import { Room } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
|
|
|
@ -15,8 +15,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import React, { ComponentProps } from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount, ReactWrapper } from "enzyme";
|
||||
import { render, RenderResult } from "@testing-library/react";
|
||||
import { MatrixEvent, RoomMember } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import {
|
||||
|
@ -124,8 +123,8 @@ describe("EventListSummary", function () {
|
|||
events: [],
|
||||
children: [],
|
||||
};
|
||||
const renderComponent = (props = {}): ReactWrapper => {
|
||||
return mount(
|
||||
const renderComponent = (props = {}): RenderResult => {
|
||||
return render(
|
||||
<MatrixClientContext.Provider value={mockClient}>
|
||||
<EventListSummary {...defaultProps} {...props} />
|
||||
</MatrixClientContext.Provider>,
|
||||
|
@ -150,13 +149,11 @@ describe("EventListSummary", function () {
|
|||
threshold: 3,
|
||||
};
|
||||
|
||||
const wrapper = renderComponent(props); // matrix cli context wrapper
|
||||
const { container } = renderComponent(props); // matrix cli context wrapper
|
||||
|
||||
expect(wrapper.find("GenericEventListSummary").props().children).toEqual([
|
||||
<div className="event_tile" key="event0">
|
||||
Expanded membership
|
||||
</div>,
|
||||
]);
|
||||
const children = container.querySelector(".mx_GenericEventListSummary_unstyledList")!.children;
|
||||
expect(children).toHaveLength(1);
|
||||
expect(children[0]).toHaveTextContent("Expanded membership");
|
||||
});
|
||||
|
||||
it("renders expanded events if there are less than props.threshold", function () {
|
||||
|
@ -172,16 +169,12 @@ describe("EventListSummary", function () {
|
|||
threshold: 3,
|
||||
};
|
||||
|
||||
const wrapper = renderComponent(props); // matrix cli context wrapper
|
||||
const { container } = renderComponent(props); // matrix cli context wrapper
|
||||
|
||||
expect(wrapper.find("GenericEventListSummary").props().children).toEqual([
|
||||
<div className="event_tile" key="event0">
|
||||
Expanded membership
|
||||
</div>,
|
||||
<div className="event_tile" key="event1">
|
||||
Expanded membership
|
||||
</div>,
|
||||
]);
|
||||
const children = container.querySelector(".mx_GenericEventListSummary_unstyledList")!.children;
|
||||
expect(children).toHaveLength(2);
|
||||
expect(children[0]).toHaveTextContent("Expanded membership");
|
||||
expect(children[1]).toHaveTextContent("Expanded membership");
|
||||
});
|
||||
|
||||
it("renders collapsed events if events.length = props.threshold", function () {
|
||||
|
@ -198,11 +191,9 @@ describe("EventListSummary", function () {
|
|||
threshold: 3,
|
||||
};
|
||||
|
||||
const wrapper = renderComponent(props);
|
||||
const summary = wrapper.find(".mx_GenericEventListSummary_summary");
|
||||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe("user_1 joined and left and joined");
|
||||
const { container } = renderComponent(props);
|
||||
const summary = container.querySelector(".mx_GenericEventListSummary_summary");
|
||||
expect(summary).toHaveTextContent("user_1 joined and left and joined");
|
||||
});
|
||||
|
||||
it("truncates long join,leave repetitions", function () {
|
||||
|
@ -230,11 +221,9 @@ describe("EventListSummary", function () {
|
|||
threshold: 3,
|
||||
};
|
||||
|
||||
const wrapper = renderComponent(props);
|
||||
const summary = wrapper.find(".mx_GenericEventListSummary_summary");
|
||||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe("user_1 joined and left 7 times");
|
||||
const { container } = renderComponent(props);
|
||||
const summary = container.querySelector(".mx_GenericEventListSummary_summary");
|
||||
expect(summary).toHaveTextContent("user_1 joined and left 7 times");
|
||||
});
|
||||
|
||||
it("truncates long join,leave repetitions between other events", function () {
|
||||
|
@ -274,11 +263,9 @@ describe("EventListSummary", function () {
|
|||
threshold: 3,
|
||||
};
|
||||
|
||||
const wrapper = renderComponent(props);
|
||||
const summary = wrapper.find(".mx_GenericEventListSummary_summary");
|
||||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe("user_1 was unbanned, joined and left 7 times and was invited");
|
||||
const { container } = renderComponent(props);
|
||||
const summary = container.querySelector(".mx_GenericEventListSummary_summary");
|
||||
expect(summary).toHaveTextContent("user_1 was unbanned, joined and left 7 times and was invited");
|
||||
});
|
||||
|
||||
it("truncates multiple sequences of repetitions with other events between", function () {
|
||||
|
@ -320,11 +307,9 @@ describe("EventListSummary", function () {
|
|||
threshold: 3,
|
||||
};
|
||||
|
||||
const wrapper = renderComponent(props);
|
||||
const summary = wrapper.find(".mx_GenericEventListSummary_summary");
|
||||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe(
|
||||
const { container } = renderComponent(props);
|
||||
const summary = container.querySelector(".mx_GenericEventListSummary_summary");
|
||||
expect(summary).toHaveTextContent(
|
||||
"user_1 was unbanned, joined and left 2 times, was banned, " + "joined and left 3 times and was invited",
|
||||
);
|
||||
});
|
||||
|
@ -374,11 +359,11 @@ describe("EventListSummary", function () {
|
|||
threshold: 3,
|
||||
};
|
||||
|
||||
const wrapper = renderComponent(props);
|
||||
const summary = wrapper.find(".mx_GenericEventListSummary_summary");
|
||||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe("user_1 and one other were unbanned, joined and left 2 times and were banned");
|
||||
const { container } = renderComponent(props);
|
||||
const summary = container.querySelector(".mx_GenericEventListSummary_summary");
|
||||
expect(summary).toHaveTextContent(
|
||||
"user_1 and one other were unbanned, joined and left 2 times and were banned",
|
||||
);
|
||||
});
|
||||
|
||||
it("handles many users following the same sequence of memberships", function () {
|
||||
|
@ -406,11 +391,11 @@ describe("EventListSummary", function () {
|
|||
threshold: 3,
|
||||
};
|
||||
|
||||
const wrapper = renderComponent(props);
|
||||
const summary = wrapper.find(".mx_GenericEventListSummary_summary");
|
||||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe("user_0 and 19 others were unbanned, joined and left 2 times and were banned");
|
||||
const { container } = renderComponent(props);
|
||||
const summary = container.querySelector(".mx_GenericEventListSummary_summary");
|
||||
expect(summary).toHaveTextContent(
|
||||
"user_0 and 19 others were unbanned, joined and left 2 times and were banned",
|
||||
);
|
||||
});
|
||||
|
||||
it("correctly orders sequences of transitions by the order of their first event", function () {
|
||||
|
@ -450,11 +435,9 @@ describe("EventListSummary", function () {
|
|||
threshold: 3,
|
||||
};
|
||||
|
||||
const wrapper = renderComponent(props);
|
||||
const summary = wrapper.find(".mx_GenericEventListSummary_summary");
|
||||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe(
|
||||
const { container } = renderComponent(props);
|
||||
const summary = container.querySelector(".mx_GenericEventListSummary_summary");
|
||||
expect(summary).toHaveTextContent(
|
||||
"user_2 was unbanned and joined and left 2 times, user_1 was unbanned, " +
|
||||
"joined and left 2 times and was banned",
|
||||
);
|
||||
|
@ -520,11 +503,9 @@ describe("EventListSummary", function () {
|
|||
threshold: 3,
|
||||
};
|
||||
|
||||
const wrapper = renderComponent(props);
|
||||
const summary = wrapper.find(".mx_GenericEventListSummary_summary");
|
||||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe(
|
||||
const { container } = renderComponent(props);
|
||||
const summary = container.querySelector(".mx_GenericEventListSummary_summary");
|
||||
expect(summary).toHaveTextContent(
|
||||
"user_1 was invited, was banned, joined, rejected their invitation, left, " +
|
||||
"had their invitation withdrawn, was unbanned, was removed, left and was removed",
|
||||
);
|
||||
|
@ -563,11 +544,11 @@ describe("EventListSummary", function () {
|
|||
threshold: 3,
|
||||
};
|
||||
|
||||
const wrapper = renderComponent(props);
|
||||
const summary = wrapper.find(".mx_GenericEventListSummary_summary");
|
||||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe("user_1 and one other rejected their invitations and had their invitations withdrawn");
|
||||
const { container } = renderComponent(props);
|
||||
const summary = container.querySelector(".mx_GenericEventListSummary_summary");
|
||||
expect(summary).toHaveTextContent(
|
||||
"user_1 and one other rejected their invitations and had their invitations withdrawn",
|
||||
);
|
||||
});
|
||||
|
||||
it("handles invitation plurals correctly when there are multiple invites", function () {
|
||||
|
@ -591,11 +572,9 @@ describe("EventListSummary", function () {
|
|||
threshold: 1, // threshold = 1 to force collapse
|
||||
};
|
||||
|
||||
const wrapper = renderComponent(props);
|
||||
const summary = wrapper.find(".mx_GenericEventListSummary_summary");
|
||||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe("user_1 rejected their invitation 2 times");
|
||||
const { container } = renderComponent(props);
|
||||
const summary = container.querySelector(".mx_GenericEventListSummary_summary");
|
||||
expect(summary).toHaveTextContent("user_1 rejected their invitation 2 times");
|
||||
});
|
||||
|
||||
it('handles a summary length = 2, with no "others"', function () {
|
||||
|
@ -613,11 +592,9 @@ describe("EventListSummary", function () {
|
|||
threshold: 3,
|
||||
};
|
||||
|
||||
const wrapper = renderComponent(props);
|
||||
const summary = wrapper.find(".mx_GenericEventListSummary_summary");
|
||||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe("user_1 and user_2 joined 2 times");
|
||||
const { container } = renderComponent(props);
|
||||
const summary = container.querySelector(".mx_GenericEventListSummary_summary");
|
||||
expect(summary).toHaveTextContent("user_1 and user_2 joined 2 times");
|
||||
});
|
||||
|
||||
it('handles a summary length = 2, with 1 "other"', function () {
|
||||
|
@ -634,11 +611,9 @@ describe("EventListSummary", function () {
|
|||
threshold: 3,
|
||||
};
|
||||
|
||||
const wrapper = renderComponent(props);
|
||||
const summary = wrapper.find(".mx_GenericEventListSummary_summary");
|
||||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe("user_1, user_2 and one other joined");
|
||||
const { container } = renderComponent(props);
|
||||
const summary = container.querySelector(".mx_GenericEventListSummary_summary");
|
||||
expect(summary).toHaveTextContent("user_1, user_2 and one other joined");
|
||||
});
|
||||
|
||||
it('handles a summary length = 2, with many "others"', function () {
|
||||
|
@ -651,11 +626,9 @@ describe("EventListSummary", function () {
|
|||
threshold: 3,
|
||||
};
|
||||
|
||||
const wrapper = renderComponent(props);
|
||||
const summary = wrapper.find(".mx_GenericEventListSummary_summary");
|
||||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe("user_0, user_1 and 18 others joined");
|
||||
const { container } = renderComponent(props);
|
||||
const summary = container.querySelector(".mx_GenericEventListSummary_summary");
|
||||
expect(summary).toHaveTextContent("user_0, user_1 and 18 others joined");
|
||||
});
|
||||
|
||||
it("should not blindly group 3pid invites and treat them as distinct users instead", () => {
|
||||
|
@ -703,10 +676,8 @@ describe("EventListSummary", function () {
|
|||
threshold: 3,
|
||||
};
|
||||
|
||||
const wrapper = renderComponent(props);
|
||||
const summary = wrapper.find(".mx_GenericEventListSummary_summary");
|
||||
const summaryText = summary.text();
|
||||
|
||||
expect(summaryText).toBe("n...@d... was invited 2 times, d...@w... was invited");
|
||||
const { container } = renderComponent(props);
|
||||
const summary = container.querySelector(".mx_GenericEventListSummary_summary");
|
||||
expect(summary).toHaveTextContent("n...@d... was invited 2 times, d...@w... was invited");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -15,15 +15,14 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount, ReactWrapper } from "enzyme";
|
||||
import { fireEvent, render, RenderResult } from "@testing-library/react";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
import { M_POLL_KIND_DISCLOSED, M_POLL_KIND_UNDISCLOSED, M_POLL_START } from "matrix-js-sdk/src/@types/polls";
|
||||
import { PollStartEvent } from "matrix-js-sdk/src/extensible_events_v1/PollStartEvent";
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||
import { M_TEXT } from "matrix-js-sdk/src/@types/extensible_events";
|
||||
|
||||
import { findById, getMockClientWithEventEmitter } from "../../../test-utils";
|
||||
import { getMockClientWithEventEmitter } from "../../../test-utils";
|
||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||
import PollCreateDialog from "../../../../src/components/views/elements/PollCreateDialog";
|
||||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||
|
@ -51,40 +50,41 @@ describe("PollCreateDialog", () => {
|
|||
});
|
||||
|
||||
it("renders a blank poll", () => {
|
||||
const dialog = mount(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />, {
|
||||
wrappingComponent: MatrixClientContext.Provider,
|
||||
wrappingComponentProps: { value: mockClient },
|
||||
});
|
||||
expect(dialog.html()).toMatchSnapshot();
|
||||
const dialog = render(
|
||||
<MatrixClientContext.Provider value={mockClient}>
|
||||
<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
expect(dialog.asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("autofocuses the poll topic on mount", () => {
|
||||
const dialog = mount(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
expect(findById(dialog, "poll-topic-input").at(0).props().autoFocus).toEqual(true);
|
||||
const dialog = render(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
expect(dialog.container.querySelector("#poll-topic-input")).toHaveFocus();
|
||||
});
|
||||
|
||||
it("autofocuses the new poll option field after clicking add option button", () => {
|
||||
const dialog = mount(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
expect(findById(dialog, "poll-topic-input").at(0).props().autoFocus).toEqual(true);
|
||||
const dialog = render(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
expect(dialog.container.querySelector("#poll-topic-input")).toHaveFocus();
|
||||
|
||||
dialog.find("div.mx_PollCreateDialog_addOption").simulate("click");
|
||||
fireEvent.click(dialog.container.querySelector("div.mx_PollCreateDialog_addOption")!);
|
||||
|
||||
expect(findById(dialog, "poll-topic-input").at(0).props().autoFocus).toEqual(false);
|
||||
expect(findById(dialog, "pollcreate_option_1").at(0).props().autoFocus).toEqual(false);
|
||||
expect(findById(dialog, "pollcreate_option_2").at(0).props().autoFocus).toEqual(true);
|
||||
expect(dialog.container.querySelector("#poll-topic-input")).not.toHaveFocus();
|
||||
expect(dialog.container.querySelector("#pollcreate_option_1")).not.toHaveFocus();
|
||||
expect(dialog.container.querySelector("#pollcreate_option_2")).toHaveFocus();
|
||||
});
|
||||
|
||||
it("renders a question and some options", () => {
|
||||
const dialog = mount(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
expect(submitIsDisabled(dialog)).toBe(true);
|
||||
const dialog = render(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
expectSubmitToBeDisabled(dialog, true);
|
||||
|
||||
// When I set some values in the boxes
|
||||
changeValue(dialog, "Question or topic", "How many turnips is the optimal number?");
|
||||
changeValue(dialog, "Option 1", "As many as my neighbour");
|
||||
changeValue(dialog, "Option 2", "The question is meaningless");
|
||||
dialog.find("div.mx_PollCreateDialog_addOption").simulate("click");
|
||||
fireEvent.click(dialog.container.querySelector("div.mx_PollCreateDialog_addOption")!);
|
||||
changeValue(dialog, "Option 3", "Mu");
|
||||
expect(dialog.html()).toMatchSnapshot();
|
||||
expect(dialog.asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders info from a previous event", () => {
|
||||
|
@ -92,23 +92,23 @@ describe("PollCreateDialog", () => {
|
|||
PollStartEvent.from("Poll Q", ["Answer 1", "Answer 2"], M_POLL_KIND_DISCLOSED).serialize(),
|
||||
);
|
||||
|
||||
const dialog = mount(
|
||||
const dialog = render(
|
||||
<PollCreateDialog room={createRoom()} onFinished={jest.fn()} editingMxEvent={previousEvent} />,
|
||||
);
|
||||
|
||||
expect(submitIsDisabled(dialog)).toBe(false);
|
||||
expect(dialog.html()).toMatchSnapshot();
|
||||
expectSubmitToBeDisabled(dialog, false);
|
||||
expect(dialog.asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("doesn't allow submitting until there are options", () => {
|
||||
const dialog = mount(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
expect(submitIsDisabled(dialog)).toBe(true);
|
||||
const dialog = render(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
expectSubmitToBeDisabled(dialog, true);
|
||||
});
|
||||
|
||||
it("does allow submitting when there are options and a question", () => {
|
||||
// Given a dialog with no info in (which I am unable to submit)
|
||||
const dialog = mount(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
expect(submitIsDisabled(dialog)).toBe(true);
|
||||
const dialog = render(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
expectSubmitToBeDisabled(dialog, true);
|
||||
|
||||
// When I set some values in the boxes
|
||||
changeValue(dialog, "Question or topic", "Q");
|
||||
|
@ -116,28 +116,30 @@ describe("PollCreateDialog", () => {
|
|||
changeValue(dialog, "Option 2", "A2");
|
||||
|
||||
// Then I am able to submit
|
||||
expect(submitIsDisabled(dialog)).toBe(false);
|
||||
expectSubmitToBeDisabled(dialog, false);
|
||||
});
|
||||
|
||||
it("shows the open poll description at first", () => {
|
||||
const dialog = mount(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
expect(dialog.find("select").prop("value")).toEqual(M_POLL_KIND_DISCLOSED.name);
|
||||
expect(dialog.find("p").text()).toEqual("Voters see results as soon as they have voted");
|
||||
const dialog = render(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
expect(dialog.container.querySelector("select")).toHaveValue(M_POLL_KIND_DISCLOSED.name);
|
||||
expect(dialog.container.querySelector("p")).toHaveTextContent("Voters see results as soon as they have voted");
|
||||
});
|
||||
|
||||
it("shows the closed poll description if we choose it", () => {
|
||||
const dialog = mount(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
const dialog = render(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
changeKind(dialog, M_POLL_KIND_UNDISCLOSED.name);
|
||||
expect(dialog.find("select").prop("value")).toEqual(M_POLL_KIND_UNDISCLOSED.name);
|
||||
expect(dialog.find("p").text()).toEqual("Results are only revealed when you end the poll");
|
||||
expect(dialog.container.querySelector("select")).toHaveValue(M_POLL_KIND_UNDISCLOSED.name);
|
||||
expect(dialog.container.querySelector("p")).toHaveTextContent(
|
||||
"Results are only revealed when you end the poll",
|
||||
);
|
||||
});
|
||||
|
||||
it("shows the open poll description if we choose it", () => {
|
||||
const dialog = mount(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
const dialog = render(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
changeKind(dialog, M_POLL_KIND_UNDISCLOSED.name);
|
||||
changeKind(dialog, M_POLL_KIND_DISCLOSED.name);
|
||||
expect(dialog.find("select").prop("value")).toEqual(M_POLL_KIND_DISCLOSED.name);
|
||||
expect(dialog.find("p").text()).toEqual("Voters see results as soon as they have voted");
|
||||
expect(dialog.container.querySelector("select")).toHaveValue(M_POLL_KIND_DISCLOSED.name);
|
||||
expect(dialog.container.querySelector("p")).toHaveTextContent("Voters see results as soon as they have voted");
|
||||
});
|
||||
|
||||
it("shows the closed poll description when editing a closed poll", () => {
|
||||
|
@ -146,32 +148,34 @@ describe("PollCreateDialog", () => {
|
|||
);
|
||||
previousEvent.event.event_id = "$prevEventId";
|
||||
|
||||
const dialog = mount(
|
||||
const dialog = render(
|
||||
<PollCreateDialog room={createRoom()} onFinished={jest.fn()} editingMxEvent={previousEvent} />,
|
||||
);
|
||||
|
||||
expect(dialog.find("select").prop("value")).toEqual(M_POLL_KIND_UNDISCLOSED.name);
|
||||
expect(dialog.find("p").text()).toEqual("Results are only revealed when you end the poll");
|
||||
expect(dialog.container.querySelector("select")).toHaveValue(M_POLL_KIND_UNDISCLOSED.name);
|
||||
expect(dialog.container.querySelector("p")).toHaveTextContent(
|
||||
"Results are only revealed when you end the poll",
|
||||
);
|
||||
});
|
||||
|
||||
it("displays a spinner after submitting", () => {
|
||||
const dialog = mount(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
const dialog = render(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
changeValue(dialog, "Question or topic", "Q");
|
||||
changeValue(dialog, "Option 1", "A1");
|
||||
changeValue(dialog, "Option 2", "A2");
|
||||
expect(dialog.find("Spinner").length).toBe(0);
|
||||
expect(dialog.container.querySelector(".mx_Spinner")).toBeFalsy();
|
||||
|
||||
dialog.find("button").simulate("click");
|
||||
expect(dialog.find("Spinner").length).toBe(1);
|
||||
fireEvent.click(dialog.container.querySelector("button")!);
|
||||
expect(dialog.container.querySelector(".mx_Spinner")).toBeDefined();
|
||||
});
|
||||
|
||||
it("sends a poll create event when submitted", () => {
|
||||
const dialog = mount(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
const dialog = render(<PollCreateDialog room={createRoom()} onFinished={jest.fn()} />);
|
||||
changeValue(dialog, "Question or topic", "Q");
|
||||
changeValue(dialog, "Option 1", "A1");
|
||||
changeValue(dialog, "Option 2", "A2");
|
||||
|
||||
dialog.find("button").simulate("click");
|
||||
fireEvent.click(dialog.container.querySelector("button")!);
|
||||
const [, , eventType, sentEventContent] = mockClient.sendEvent.mock.calls[0];
|
||||
expect(M_POLL_START.matches(eventType)).toBeTruthy();
|
||||
expect(sentEventContent).toEqual({
|
||||
|
@ -206,14 +210,14 @@ describe("PollCreateDialog", () => {
|
|||
);
|
||||
previousEvent.event.event_id = "$prevEventId";
|
||||
|
||||
const dialog = mount(
|
||||
const dialog = render(
|
||||
<PollCreateDialog room={createRoom()} onFinished={jest.fn()} editingMxEvent={previousEvent} />,
|
||||
);
|
||||
|
||||
changeValue(dialog, "Question or topic", "Poll Q updated");
|
||||
changeValue(dialog, "Option 2", "Answer 2 updated");
|
||||
changeKind(dialog, M_POLL_KIND_UNDISCLOSED.name);
|
||||
dialog.find("button").simulate("click");
|
||||
fireEvent.click(dialog.container.querySelector("button")!);
|
||||
|
||||
const [, , eventType, sentEventContent] = mockClient.sendEvent.mock.calls[0];
|
||||
expect(M_POLL_START.matches(eventType)).toBeTruthy();
|
||||
|
@ -255,12 +259,12 @@ describe("PollCreateDialog", () => {
|
|||
);
|
||||
previousEvent.event.event_id = "$prevEventId";
|
||||
|
||||
const dialog = mount(
|
||||
const dialog = render(
|
||||
<PollCreateDialog room={createRoom()} onFinished={jest.fn()} editingMxEvent={previousEvent} />,
|
||||
);
|
||||
|
||||
changeValue(dialog, "Question or topic", "Poll Q updated");
|
||||
dialog.find("button").simulate("click");
|
||||
fireEvent.click(dialog.container.querySelector("button")!);
|
||||
|
||||
const [, , eventType, sentEventContent] = mockClient.sendEvent.mock.calls[0];
|
||||
expect(M_POLL_START.matches(eventType)).toBeTruthy();
|
||||
|
@ -273,14 +277,20 @@ function createRoom(): Room {
|
|||
return new Room("roomid", MatrixClientPeg.get(), "@name:example.com", {});
|
||||
}
|
||||
|
||||
function changeValue(wrapper: ReactWrapper, labelText: string, value: string) {
|
||||
wrapper.find(`input[label="${labelText}"]`).simulate("change", { target: { value: value } });
|
||||
function changeValue(wrapper: RenderResult, labelText: string, value: string) {
|
||||
fireEvent.change(wrapper.container.querySelector(`input[label="${labelText}"]`)!, {
|
||||
target: { value: value },
|
||||
});
|
||||
}
|
||||
|
||||
function changeKind(wrapper: ReactWrapper, value: string) {
|
||||
wrapper.find("select").simulate("change", { target: { value: value } });
|
||||
function changeKind(wrapper: RenderResult, value: string) {
|
||||
fireEvent.change(wrapper.container.querySelector("select")!, { target: { value: value } });
|
||||
}
|
||||
|
||||
function submitIsDisabled(wrapper: ReactWrapper) {
|
||||
return wrapper.find('button[type="submit"]').prop("aria-disabled") === true;
|
||||
function expectSubmitToBeDisabled(wrapper: RenderResult, disabled: boolean) {
|
||||
if (disabled) {
|
||||
expect(wrapper.container.querySelector('button[type="submit"]')).toHaveAttribute("aria-disabled", "true");
|
||||
} else {
|
||||
expect(wrapper.container.querySelector('button[type="submit"]')).not.toHaveAttribute("aria-disabled", "true");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,560 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`PollCreateDialog renders a blank poll 1`] = `"<div data-focus-guard="true" tabindex="0" style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"></div><div data-focus-lock-disabled="false" role="dialog" aria-labelledby="mx_CompoundDialog_title" aria-describedby="mx_CompoundDialog_content" class="mx_CompoundDialog mx_ScrollableBaseDialog"><div class="mx_CompoundDialog_header"><h1>Create poll</h1><div aria-label="Close dialog" role="button" tabindex="0" class="mx_AccessibleButton mx_CompoundDialog_cancelButton"></div></div><form class="mx_CompoundDialog_form"><div class="mx_CompoundDialog_content"><div class="mx_PollCreateDialog"><h2>Poll type</h2><div class="mx_Field mx_Field_select"><select type="text" id="mx_Field_1"><option value="org.matrix.msc3381.poll.disclosed">Open poll</option><option value="org.matrix.msc3381.poll.undisclosed">Closed poll</option></select><label for="mx_Field_1"></label></div><p>Voters see results as soon as they have voted</p><h2>What is your poll question or topic?</h2><div class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint"><input id="poll-topic-input" maxlength="340" label="Question or topic" placeholder="Write something…" type="text" value=""><label for="poll-topic-input">Question or topic</label></div><h2>Create options</h2><div class="mx_PollCreateDialog_option"><div class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint"><input id="pollcreate_option_0" maxlength="340" label="Option 1" placeholder="Write an option" type="text" value=""><label for="pollcreate_option_0">Option 1</label></div><div role="button" tabindex="0" class="mx_AccessibleButton mx_PollCreateDialog_removeOption"></div></div><div class="mx_PollCreateDialog_option"><div class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint"><input id="pollcreate_option_1" maxlength="340" label="Option 2" placeholder="Write an option" type="text" value=""><label for="pollcreate_option_1">Option 2</label></div><div role="button" tabindex="0" class="mx_AccessibleButton mx_PollCreateDialog_removeOption"></div></div><div role="button" tabindex="0" class="mx_AccessibleButton mx_PollCreateDialog_addOption mx_AccessibleButton_hasKind mx_AccessibleButton_kind_secondary">Add option</div></div></div><div class="mx_CompoundDialog_footer"><div role="button" tabindex="0" class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline">Cancel</div><button type="submit" role="button" tabindex="0" aria-disabled="true" disabled="" class="mx_AccessibleButton mx_Dialog_nonDialogButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary mx_AccessibleButton_disabled">Create Poll</button></div></form></div><div data-focus-guard="true" tabindex="0" style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"></div>"`;
|
||||
exports[`PollCreateDialog renders a blank poll 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
data-focus-guard="true"
|
||||
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
|
||||
tabindex="0"
|
||||
/>
|
||||
<div
|
||||
aria-describedby="mx_CompoundDialog_content"
|
||||
aria-labelledby="mx_CompoundDialog_title"
|
||||
class="mx_CompoundDialog mx_ScrollableBaseDialog"
|
||||
data-focus-lock-disabled="false"
|
||||
role="dialog"
|
||||
>
|
||||
<div
|
||||
class="mx_CompoundDialog_header"
|
||||
>
|
||||
<h1>
|
||||
Create poll
|
||||
</h1>
|
||||
<div
|
||||
aria-label="Close dialog"
|
||||
class="mx_AccessibleButton mx_CompoundDialog_cancelButton"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
/>
|
||||
</div>
|
||||
<form
|
||||
class="mx_CompoundDialog_form"
|
||||
>
|
||||
<div
|
||||
class="mx_CompoundDialog_content"
|
||||
>
|
||||
<div
|
||||
class="mx_PollCreateDialog"
|
||||
>
|
||||
<h2>
|
||||
Poll type
|
||||
</h2>
|
||||
<div
|
||||
class="mx_Field mx_Field_select"
|
||||
>
|
||||
<select
|
||||
id="mx_Field_1"
|
||||
type="text"
|
||||
>
|
||||
<option
|
||||
value="org.matrix.msc3381.poll.disclosed"
|
||||
>
|
||||
Open poll
|
||||
</option>
|
||||
<option
|
||||
value="org.matrix.msc3381.poll.undisclosed"
|
||||
>
|
||||
Closed poll
|
||||
</option>
|
||||
</select>
|
||||
<label
|
||||
for="mx_Field_1"
|
||||
/>
|
||||
</div>
|
||||
<p>
|
||||
Voters see results as soon as they have voted
|
||||
</p>
|
||||
<h2>
|
||||
What is your poll question or topic?
|
||||
</h2>
|
||||
<div
|
||||
class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint"
|
||||
>
|
||||
<input
|
||||
id="poll-topic-input"
|
||||
label="Question or topic"
|
||||
maxlength="340"
|
||||
placeholder="Write something…"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<label
|
||||
for="poll-topic-input"
|
||||
>
|
||||
Question or topic
|
||||
</label>
|
||||
</div>
|
||||
<h2>
|
||||
Create options
|
||||
</h2>
|
||||
<div
|
||||
class="mx_PollCreateDialog_option"
|
||||
>
|
||||
<div
|
||||
class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint"
|
||||
>
|
||||
<input
|
||||
id="pollcreate_option_0"
|
||||
label="Option 1"
|
||||
maxlength="340"
|
||||
placeholder="Write an option"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<label
|
||||
for="pollcreate_option_0"
|
||||
>
|
||||
Option 1
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_PollCreateDialog_removeOption"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_PollCreateDialog_option"
|
||||
>
|
||||
<div
|
||||
class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint"
|
||||
>
|
||||
<input
|
||||
id="pollcreate_option_1"
|
||||
label="Option 2"
|
||||
maxlength="340"
|
||||
placeholder="Write an option"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<label
|
||||
for="pollcreate_option_1"
|
||||
>
|
||||
Option 2
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_PollCreateDialog_removeOption"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_PollCreateDialog_addOption mx_AccessibleButton_hasKind mx_AccessibleButton_kind_secondary"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Add option
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_CompoundDialog_footer"
|
||||
>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Cancel
|
||||
</div>
|
||||
<button
|
||||
aria-disabled="true"
|
||||
class="mx_AccessibleButton mx_Dialog_nonDialogButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary mx_AccessibleButton_disabled"
|
||||
disabled=""
|
||||
role="button"
|
||||
tabindex="0"
|
||||
type="submit"
|
||||
>
|
||||
Create Poll
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div
|
||||
data-focus-guard="true"
|
||||
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
|
||||
tabindex="0"
|
||||
/>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`PollCreateDialog renders a question and some options 1`] = `"<div data-focus-guard="true" tabindex="0" style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"></div><div data-focus-lock-disabled="false" role="dialog" aria-labelledby="mx_CompoundDialog_title" aria-describedby="mx_CompoundDialog_content" class="mx_CompoundDialog mx_ScrollableBaseDialog"><div class="mx_CompoundDialog_header"><h1>Create poll</h1><div aria-label="Close dialog" role="button" tabindex="0" class="mx_AccessibleButton mx_CompoundDialog_cancelButton"></div></div><form class="mx_CompoundDialog_form"><div class="mx_CompoundDialog_content"><div class="mx_PollCreateDialog"><h2>Poll type</h2><div class="mx_Field mx_Field_select"><select type="text" id="mx_Field_4"><option value="org.matrix.msc3381.poll.disclosed">Open poll</option><option value="org.matrix.msc3381.poll.undisclosed">Closed poll</option></select><label for="mx_Field_4"></label></div><p>Voters see results as soon as they have voted</p><h2>What is your poll question or topic?</h2><div class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint"><input id="poll-topic-input" maxlength="340" label="Question or topic" placeholder="Write something…" type="text" value="How many turnips is the optimal number?"><label for="poll-topic-input">Question or topic</label></div><h2>Create options</h2><div class="mx_PollCreateDialog_option"><div class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint"><input id="pollcreate_option_0" maxlength="340" label="Option 1" placeholder="Write an option" type="text" value="As many as my neighbour"><label for="pollcreate_option_0">Option 1</label></div><div role="button" tabindex="0" class="mx_AccessibleButton mx_PollCreateDialog_removeOption"></div></div><div class="mx_PollCreateDialog_option"><div class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint"><input id="pollcreate_option_1" maxlength="340" label="Option 2" placeholder="Write an option" type="text" value="The question is meaningless"><label for="pollcreate_option_1">Option 2</label></div><div role="button" tabindex="0" class="mx_AccessibleButton mx_PollCreateDialog_removeOption"></div></div><div class="mx_PollCreateDialog_option"><div class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint"><input id="pollcreate_option_2" maxlength="340" label="Option 3" placeholder="Write an option" type="text" value="Mu"><label for="pollcreate_option_2">Option 3</label></div><div role="button" tabindex="0" class="mx_AccessibleButton mx_PollCreateDialog_removeOption"></div></div><div role="button" tabindex="0" class="mx_AccessibleButton mx_PollCreateDialog_addOption mx_AccessibleButton_hasKind mx_AccessibleButton_kind_secondary">Add option</div></div></div><div class="mx_CompoundDialog_footer"><div role="button" tabindex="0" class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline">Cancel</div><button type="submit" role="button" tabindex="0" class="mx_AccessibleButton mx_Dialog_nonDialogButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary">Create Poll</button></div></form></div><div data-focus-guard="true" tabindex="0" style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"></div>"`;
|
||||
exports[`PollCreateDialog renders a question and some options 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
data-focus-guard="true"
|
||||
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
|
||||
tabindex="0"
|
||||
/>
|
||||
<div
|
||||
aria-describedby="mx_CompoundDialog_content"
|
||||
aria-labelledby="mx_CompoundDialog_title"
|
||||
class="mx_CompoundDialog mx_ScrollableBaseDialog"
|
||||
data-focus-lock-disabled="false"
|
||||
role="dialog"
|
||||
>
|
||||
<div
|
||||
class="mx_CompoundDialog_header"
|
||||
>
|
||||
<h1>
|
||||
Create poll
|
||||
</h1>
|
||||
<div
|
||||
aria-label="Close dialog"
|
||||
class="mx_AccessibleButton mx_CompoundDialog_cancelButton"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
/>
|
||||
</div>
|
||||
<form
|
||||
class="mx_CompoundDialog_form"
|
||||
>
|
||||
<div
|
||||
class="mx_CompoundDialog_content"
|
||||
>
|
||||
<div
|
||||
class="mx_PollCreateDialog"
|
||||
>
|
||||
<h2>
|
||||
Poll type
|
||||
</h2>
|
||||
<div
|
||||
class="mx_Field mx_Field_select"
|
||||
>
|
||||
<select
|
||||
id="mx_Field_4"
|
||||
type="text"
|
||||
>
|
||||
<option
|
||||
value="org.matrix.msc3381.poll.disclosed"
|
||||
>
|
||||
Open poll
|
||||
</option>
|
||||
<option
|
||||
value="org.matrix.msc3381.poll.undisclosed"
|
||||
>
|
||||
Closed poll
|
||||
</option>
|
||||
</select>
|
||||
<label
|
||||
for="mx_Field_4"
|
||||
/>
|
||||
</div>
|
||||
<p>
|
||||
Voters see results as soon as they have voted
|
||||
</p>
|
||||
<h2>
|
||||
What is your poll question or topic?
|
||||
</h2>
|
||||
<div
|
||||
class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint"
|
||||
>
|
||||
<input
|
||||
id="poll-topic-input"
|
||||
label="Question or topic"
|
||||
maxlength="340"
|
||||
placeholder="Write something…"
|
||||
type="text"
|
||||
value="How many turnips is the optimal number?"
|
||||
/>
|
||||
<label
|
||||
for="poll-topic-input"
|
||||
>
|
||||
Question or topic
|
||||
</label>
|
||||
</div>
|
||||
<h2>
|
||||
Create options
|
||||
</h2>
|
||||
<div
|
||||
class="mx_PollCreateDialog_option"
|
||||
>
|
||||
<div
|
||||
class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint"
|
||||
>
|
||||
<input
|
||||
id="pollcreate_option_0"
|
||||
label="Option 1"
|
||||
maxlength="340"
|
||||
placeholder="Write an option"
|
||||
type="text"
|
||||
value="As many as my neighbour"
|
||||
/>
|
||||
<label
|
||||
for="pollcreate_option_0"
|
||||
>
|
||||
Option 1
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_PollCreateDialog_removeOption"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_PollCreateDialog_option"
|
||||
>
|
||||
<div
|
||||
class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint"
|
||||
>
|
||||
<input
|
||||
id="pollcreate_option_1"
|
||||
label="Option 2"
|
||||
maxlength="340"
|
||||
placeholder="Write an option"
|
||||
type="text"
|
||||
value="The question is meaningless"
|
||||
/>
|
||||
<label
|
||||
for="pollcreate_option_1"
|
||||
>
|
||||
Option 2
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_PollCreateDialog_removeOption"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_PollCreateDialog_option"
|
||||
>
|
||||
<div
|
||||
class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint"
|
||||
>
|
||||
<input
|
||||
id="pollcreate_option_2"
|
||||
label="Option 3"
|
||||
maxlength="340"
|
||||
placeholder="Write an option"
|
||||
type="text"
|
||||
value="Mu"
|
||||
/>
|
||||
<label
|
||||
for="pollcreate_option_2"
|
||||
>
|
||||
Option 3
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_PollCreateDialog_removeOption"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_PollCreateDialog_addOption mx_AccessibleButton_hasKind mx_AccessibleButton_kind_secondary"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Add option
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_CompoundDialog_footer"
|
||||
>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Cancel
|
||||
</div>
|
||||
<button
|
||||
class="mx_AccessibleButton mx_Dialog_nonDialogButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
type="submit"
|
||||
>
|
||||
Create Poll
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div
|
||||
data-focus-guard="true"
|
||||
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
|
||||
tabindex="0"
|
||||
/>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`PollCreateDialog renders info from a previous event 1`] = `"<div data-focus-guard="true" tabindex="0" style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"></div><div data-focus-lock-disabled="false" role="dialog" aria-labelledby="mx_CompoundDialog_title" aria-describedby="mx_CompoundDialog_content" class="mx_CompoundDialog mx_ScrollableBaseDialog"><div class="mx_CompoundDialog_header"><h1>Edit poll</h1><div aria-label="Close dialog" role="button" tabindex="0" class="mx_AccessibleButton mx_CompoundDialog_cancelButton"></div></div><form class="mx_CompoundDialog_form"><div class="mx_CompoundDialog_content"><div class="mx_PollCreateDialog"><h2>Poll type</h2><div class="mx_Field mx_Field_select"><select type="text" id="mx_Field_5"><option value="org.matrix.msc3381.poll.disclosed">Open poll</option><option value="org.matrix.msc3381.poll.undisclosed">Closed poll</option></select><label for="mx_Field_5"></label></div><p>Voters see results as soon as they have voted</p><h2>What is your poll question or topic?</h2><div class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint"><input id="poll-topic-input" maxlength="340" label="Question or topic" placeholder="Write something…" type="text" value="Poll Q"><label for="poll-topic-input">Question or topic</label></div><h2>Create options</h2><div class="mx_PollCreateDialog_option"><div class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint"><input id="pollcreate_option_0" maxlength="340" label="Option 1" placeholder="Write an option" type="text" value="Answer 1"><label for="pollcreate_option_0">Option 1</label></div><div role="button" tabindex="0" class="mx_AccessibleButton mx_PollCreateDialog_removeOption"></div></div><div class="mx_PollCreateDialog_option"><div class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint"><input id="pollcreate_option_1" maxlength="340" label="Option 2" placeholder="Write an option" type="text" value="Answer 2"><label for="pollcreate_option_1">Option 2</label></div><div role="button" tabindex="0" class="mx_AccessibleButton mx_PollCreateDialog_removeOption"></div></div><div role="button" tabindex="0" class="mx_AccessibleButton mx_PollCreateDialog_addOption mx_AccessibleButton_hasKind mx_AccessibleButton_kind_secondary">Add option</div></div></div><div class="mx_CompoundDialog_footer"><div role="button" tabindex="0" class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline">Cancel</div><button type="submit" role="button" tabindex="0" class="mx_AccessibleButton mx_Dialog_nonDialogButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary">Done</button></div></form></div><div data-focus-guard="true" tabindex="0" style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"></div>"`;
|
||||
exports[`PollCreateDialog renders info from a previous event 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
data-focus-guard="true"
|
||||
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
|
||||
tabindex="0"
|
||||
/>
|
||||
<div
|
||||
aria-describedby="mx_CompoundDialog_content"
|
||||
aria-labelledby="mx_CompoundDialog_title"
|
||||
class="mx_CompoundDialog mx_ScrollableBaseDialog"
|
||||
data-focus-lock-disabled="false"
|
||||
role="dialog"
|
||||
>
|
||||
<div
|
||||
class="mx_CompoundDialog_header"
|
||||
>
|
||||
<h1>
|
||||
Edit poll
|
||||
</h1>
|
||||
<div
|
||||
aria-label="Close dialog"
|
||||
class="mx_AccessibleButton mx_CompoundDialog_cancelButton"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
/>
|
||||
</div>
|
||||
<form
|
||||
class="mx_CompoundDialog_form"
|
||||
>
|
||||
<div
|
||||
class="mx_CompoundDialog_content"
|
||||
>
|
||||
<div
|
||||
class="mx_PollCreateDialog"
|
||||
>
|
||||
<h2>
|
||||
Poll type
|
||||
</h2>
|
||||
<div
|
||||
class="mx_Field mx_Field_select"
|
||||
>
|
||||
<select
|
||||
id="mx_Field_5"
|
||||
type="text"
|
||||
>
|
||||
<option
|
||||
value="org.matrix.msc3381.poll.disclosed"
|
||||
>
|
||||
Open poll
|
||||
</option>
|
||||
<option
|
||||
value="org.matrix.msc3381.poll.undisclosed"
|
||||
>
|
||||
Closed poll
|
||||
</option>
|
||||
</select>
|
||||
<label
|
||||
for="mx_Field_5"
|
||||
/>
|
||||
</div>
|
||||
<p>
|
||||
Voters see results as soon as they have voted
|
||||
</p>
|
||||
<h2>
|
||||
What is your poll question or topic?
|
||||
</h2>
|
||||
<div
|
||||
class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint"
|
||||
>
|
||||
<input
|
||||
id="poll-topic-input"
|
||||
label="Question or topic"
|
||||
maxlength="340"
|
||||
placeholder="Write something…"
|
||||
type="text"
|
||||
value="Poll Q"
|
||||
/>
|
||||
<label
|
||||
for="poll-topic-input"
|
||||
>
|
||||
Question or topic
|
||||
</label>
|
||||
</div>
|
||||
<h2>
|
||||
Create options
|
||||
</h2>
|
||||
<div
|
||||
class="mx_PollCreateDialog_option"
|
||||
>
|
||||
<div
|
||||
class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint"
|
||||
>
|
||||
<input
|
||||
id="pollcreate_option_0"
|
||||
label="Option 1"
|
||||
maxlength="340"
|
||||
placeholder="Write an option"
|
||||
type="text"
|
||||
value="Answer 1"
|
||||
/>
|
||||
<label
|
||||
for="pollcreate_option_0"
|
||||
>
|
||||
Option 1
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_PollCreateDialog_removeOption"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_PollCreateDialog_option"
|
||||
>
|
||||
<div
|
||||
class="mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint"
|
||||
>
|
||||
<input
|
||||
id="pollcreate_option_1"
|
||||
label="Option 2"
|
||||
maxlength="340"
|
||||
placeholder="Write an option"
|
||||
type="text"
|
||||
value="Answer 2"
|
||||
/>
|
||||
<label
|
||||
for="pollcreate_option_1"
|
||||
>
|
||||
Option 2
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_PollCreateDialog_removeOption"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_PollCreateDialog_addOption mx_AccessibleButton_hasKind mx_AccessibleButton_kind_secondary"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Add option
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_CompoundDialog_footer"
|
||||
>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Cancel
|
||||
</div>
|
||||
<button
|
||||
class="mx_AccessibleButton mx_Dialog_nonDialogButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
type="submit"
|
||||
>
|
||||
Done
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div
|
||||
data-focus-guard="true"
|
||||
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
|
||||
tabindex="0"
|
||||
/>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
|
|
@ -15,9 +15,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import React, { ComponentProps } from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount } from "enzyme";
|
||||
import { act } from "react-dom/test-utils";
|
||||
import { act, fireEvent, render } from "@testing-library/react";
|
||||
import * as maplibregl from "maplibre-gl";
|
||||
import { BeaconEvent, getBeaconInfoIdentifier, RelationType, MatrixEvent, EventType } from "matrix-js-sdk/src/matrix";
|
||||
import { Relations } from "matrix-js-sdk/src/models/relations";
|
||||
|
@ -36,7 +34,6 @@ import { MediaEventHelper } from "../../../../src/utils/MediaEventHelper";
|
|||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||
import Modal from "../../../../src/Modal";
|
||||
import { TILE_SERVER_WK_KEY } from "../../../../src/utils/WellKnownUtils";
|
||||
import { MapError } from "../../../../src/components/views/location/MapError";
|
||||
import * as mapUtilHooks from "../../../../src/utils/location/useMap";
|
||||
import { LocationShareError } from "../../../../src/utils/location";
|
||||
|
||||
|
@ -75,10 +72,11 @@ describe("<MBeaconBody />", () => {
|
|||
};
|
||||
|
||||
const getComponent = (props = {}) =>
|
||||
mount(<MBeaconBody {...defaultProps} {...props} />, {
|
||||
wrappingComponent: MatrixClientContext.Provider,
|
||||
wrappingComponentProps: { value: mockClient },
|
||||
});
|
||||
render(
|
||||
<MatrixClientContext.Provider value={mockClient}>
|
||||
<MBeaconBody {...defaultProps} {...props} />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
|
||||
const modalSpy = jest.spyOn(Modal, "createDialog").mockReturnValue({
|
||||
finished: Promise.resolve([true]),
|
||||
|
@ -94,7 +92,7 @@ describe("<MBeaconBody />", () => {
|
|||
const beaconInfoEvent = makeBeaconInfoEvent(aliceId, roomId, { isLive: false }, "$alice-room1-1");
|
||||
makeRoomWithStateEvents([beaconInfoEvent], { roomId, mockClient });
|
||||
const component = getComponent({ mxEvent: beaconInfoEvent });
|
||||
expect(component.text()).toEqual("Live location ended");
|
||||
expect(component.container).toHaveTextContent("Live location ended");
|
||||
});
|
||||
|
||||
it("renders stopped beacon UI for an expired beacon", () => {
|
||||
|
@ -107,7 +105,7 @@ describe("<MBeaconBody />", () => {
|
|||
);
|
||||
makeRoomWithStateEvents([beaconInfoEvent], { roomId, mockClient });
|
||||
const component = getComponent({ mxEvent: beaconInfoEvent });
|
||||
expect(component.text()).toEqual("Live location ended");
|
||||
expect(component.container).toHaveTextContent("Live location ended");
|
||||
});
|
||||
|
||||
it("renders loading beacon UI for a beacon that has not started yet", () => {
|
||||
|
@ -120,7 +118,7 @@ describe("<MBeaconBody />", () => {
|
|||
);
|
||||
makeRoomWithStateEvents([beaconInfoEvent], { roomId, mockClient });
|
||||
const component = getComponent({ mxEvent: beaconInfoEvent });
|
||||
expect(component.text()).toEqual("Loading live location…");
|
||||
expect(component.container).toHaveTextContent("Loading live location…");
|
||||
});
|
||||
|
||||
it("does not open maximised map when on click when beacon is stopped", () => {
|
||||
|
@ -133,9 +131,7 @@ describe("<MBeaconBody />", () => {
|
|||
);
|
||||
makeRoomWithStateEvents([beaconInfoEvent], { roomId, mockClient });
|
||||
const component = getComponent({ mxEvent: beaconInfoEvent });
|
||||
act(() => {
|
||||
component.find(".mx_MBeaconBody_map").at(0).simulate("click");
|
||||
});
|
||||
fireEvent.click(component.container.querySelector(".mx_MBeaconBody_map")!);
|
||||
|
||||
expect(modalSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
@ -155,7 +151,7 @@ describe("<MBeaconBody />", () => {
|
|||
|
||||
const component = getComponent({ mxEvent: aliceBeaconInfo1 });
|
||||
// beacon1 has been superceded by beacon2
|
||||
expect(component.text()).toEqual("Live location ended");
|
||||
expect(component.container).toHaveTextContent("Live location ended");
|
||||
});
|
||||
|
||||
it("renders stopped UI when a beacon event is replaced", () => {
|
||||
|
@ -179,10 +175,8 @@ describe("<MBeaconBody />", () => {
|
|||
beaconInstance.update(aliceBeaconInfo2);
|
||||
});
|
||||
|
||||
component.setProps({});
|
||||
|
||||
// beacon1 has been superceded by beacon2
|
||||
expect(component.text()).toEqual("Live location ended");
|
||||
expect(component.container).toHaveTextContent("Live location ended");
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -202,10 +196,8 @@ describe("<MBeaconBody />", () => {
|
|||
beaconInstance.emit(BeaconEvent.LivenessChange, false, beaconInstance);
|
||||
});
|
||||
|
||||
component.setProps({});
|
||||
|
||||
// stopped UI
|
||||
expect(component.text()).toEqual("Live location ended");
|
||||
expect(component.container).toHaveTextContent("Live location ended");
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -227,16 +219,14 @@ describe("<MBeaconBody />", () => {
|
|||
makeRoomWithStateEvents([aliceBeaconInfo], { roomId, mockClient });
|
||||
const component = getComponent({ mxEvent: aliceBeaconInfo });
|
||||
|
||||
expect(component.text()).toEqual("Loading live location…");
|
||||
expect(component.container).toHaveTextContent("Loading live location…");
|
||||
});
|
||||
|
||||
it("does nothing on click when a beacon has no location", () => {
|
||||
makeRoomWithStateEvents([aliceBeaconInfo], { roomId, mockClient });
|
||||
const component = getComponent({ mxEvent: aliceBeaconInfo });
|
||||
|
||||
act(() => {
|
||||
component.find(".mx_MBeaconBody_map").at(0).simulate("click");
|
||||
});
|
||||
fireEvent.click(component.container.querySelector(".mx_MBeaconBody_map")!);
|
||||
|
||||
expect(modalSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
@ -247,7 +237,7 @@ describe("<MBeaconBody />", () => {
|
|||
beaconInstance.addLocations([location1]);
|
||||
const component = getComponent({ mxEvent: aliceBeaconInfo });
|
||||
|
||||
expect(component.find("Map").length).toBeTruthy;
|
||||
expect(component.container.querySelector(".maplibregl-canvas-container")).toBeDefined();
|
||||
});
|
||||
|
||||
it("opens maximised map view on click when beacon has a live location", () => {
|
||||
|
@ -256,9 +246,7 @@ describe("<MBeaconBody />", () => {
|
|||
beaconInstance.addLocations([location1]);
|
||||
const component = getComponent({ mxEvent: aliceBeaconInfo });
|
||||
|
||||
act(() => {
|
||||
component.find("Map").simulate("click");
|
||||
});
|
||||
fireEvent.click(component.container.querySelector(".mx_Map")!);
|
||||
|
||||
// opens modal
|
||||
expect(modalSpy).toHaveBeenCalled();
|
||||
|
@ -268,44 +256,18 @@ describe("<MBeaconBody />", () => {
|
|||
makeRoomWithStateEvents([aliceBeaconInfo], { roomId, mockClient });
|
||||
const component = getComponent({ mxEvent: aliceBeaconInfo });
|
||||
|
||||
act(() => {
|
||||
component.find(".mx_MBeaconBody_map").at(0).simulate("click");
|
||||
});
|
||||
fireEvent.click(component.container.querySelector(".mx_MBeaconBody_map")!);
|
||||
|
||||
expect(modalSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("renders a live beacon with a location correctly", () => {
|
||||
const room = makeRoomWithStateEvents([aliceBeaconInfo], { roomId, mockClient });
|
||||
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(aliceBeaconInfo))!;
|
||||
beaconInstance.addLocations([location1]);
|
||||
const component = getComponent({ mxEvent: aliceBeaconInfo });
|
||||
|
||||
expect(component.find("Map").length).toBeTruthy;
|
||||
});
|
||||
|
||||
it("opens maximised map view on click when beacon has a live location", () => {
|
||||
const room = makeRoomWithStateEvents([aliceBeaconInfo], { roomId, mockClient });
|
||||
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(aliceBeaconInfo))!;
|
||||
beaconInstance.addLocations([location1]);
|
||||
const component = getComponent({ mxEvent: aliceBeaconInfo });
|
||||
|
||||
act(() => {
|
||||
component.find("Map").simulate("click");
|
||||
});
|
||||
|
||||
// opens modal
|
||||
expect(modalSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("updates latest location", () => {
|
||||
const room = makeRoomWithStateEvents([aliceBeaconInfo], { roomId, mockClient });
|
||||
const component = getComponent({ mxEvent: aliceBeaconInfo });
|
||||
getComponent({ mxEvent: aliceBeaconInfo });
|
||||
|
||||
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(aliceBeaconInfo))!;
|
||||
act(() => {
|
||||
beaconInstance.addLocations([location1]);
|
||||
component.setProps({});
|
||||
});
|
||||
|
||||
expect(mockMap.setCenter).toHaveBeenCalledWith({ lat: 51, lon: 41 });
|
||||
|
@ -313,7 +275,6 @@ describe("<MBeaconBody />", () => {
|
|||
|
||||
act(() => {
|
||||
beaconInstance.addLocations([location2]);
|
||||
component.setProps({});
|
||||
});
|
||||
|
||||
expect(mockMap.setCenter).toHaveBeenCalledWith({ lat: 52, lon: 42 });
|
||||
|
@ -455,7 +416,7 @@ describe("<MBeaconBody />", () => {
|
|||
makeRoomWithBeacons(roomId, mockClient, [beaconInfoEvent], [location1]);
|
||||
|
||||
const component = getComponent({ mxEvent: beaconInfoEvent });
|
||||
expect(component.find(MapError)).toMatchSnapshot();
|
||||
expect(component.getByTestId("map-rendering-error")).toMatchSnapshot();
|
||||
});
|
||||
|
||||
// test that statuses display as expected with a map display error
|
||||
|
|
|
@ -21,6 +21,7 @@ import { LocationAssetType } from "matrix-js-sdk/src/@types/location";
|
|||
import { ClientEvent, RoomMember } from "matrix-js-sdk/src/matrix";
|
||||
import * as maplibregl from "maplibre-gl";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { act } from "react-dom/test-utils";
|
||||
import { SyncState } from "matrix-js-sdk/src/sync";
|
||||
|
||||
|
|
|
@ -1,35 +1,22 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<MBeaconBody /> when map display is not configured renders maps unavailable error for a live beacon with location 1`] = `
|
||||
<MapError
|
||||
className="mx_MBeaconBody_mapError mx_MBeaconBody_mapErrorInteractive"
|
||||
error="MapStyleUrlNotConfigured"
|
||||
isMinimised={true}
|
||||
onClick={[Function]}
|
||||
<div
|
||||
class="mx_MapError mx_MBeaconBody_mapError mx_MBeaconBody_mapErrorInteractive mx_MapError_isMinimised"
|
||||
data-testid="map-rendering-error"
|
||||
>
|
||||
<div
|
||||
className="mx_MapError mx_MBeaconBody_mapError mx_MBeaconBody_mapErrorInteractive mx_MapError_isMinimised"
|
||||
data-testid="map-rendering-error"
|
||||
onClick={[Function]}
|
||||
class="mx_MapError_icon"
|
||||
/>
|
||||
<h3
|
||||
class="mx_Heading_h3 mx_MapError_heading"
|
||||
>
|
||||
<div
|
||||
className="mx_MapError_icon"
|
||||
/>
|
||||
<Heading
|
||||
className="mx_MapError_heading"
|
||||
size="h3"
|
||||
>
|
||||
<h3
|
||||
className="mx_Heading_h3 mx_MapError_heading"
|
||||
>
|
||||
Unable to load map
|
||||
</h3>
|
||||
</Heading>
|
||||
<p
|
||||
className="mx_MapError_message"
|
||||
>
|
||||
This homeserver is not configured to display maps.
|
||||
</p>
|
||||
</div>
|
||||
</MapError>
|
||||
Unable to load map
|
||||
</h3>
|
||||
<p
|
||||
class="mx_MapError_message"
|
||||
>
|
||||
This homeserver is not configured to display maps.
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
@ -16,6 +16,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import React, { Component } from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import ReactTestUtils from "react-dom/test-utils";
|
||||
import ReactDOM from "react-dom";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
|
|
|
@ -15,9 +15,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount, ReactWrapper } from "enzyme";
|
||||
import { render, screen, act, fireEvent, waitFor, getByRole } from "@testing-library/react";
|
||||
import { render, screen, act, fireEvent, waitFor, getByRole, RenderResult } from "@testing-library/react";
|
||||
import { mocked, Mocked } from "jest-mock";
|
||||
import { EventType, RoomType } from "matrix-js-sdk/src/@types/event";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
|
@ -60,291 +58,7 @@ import WidgetUtils from "../../../../src/utils/WidgetUtils";
|
|||
import { ElementWidgetActions } from "../../../../src/stores/widgets/ElementWidgetActions";
|
||||
import MediaDeviceHandler, { MediaDeviceKindEnum } from "../../../../src/MediaDeviceHandler";
|
||||
|
||||
describe("RoomHeader (Enzyme)", () => {
|
||||
it("shows the room avatar in a room with only ourselves", () => {
|
||||
// When we render a non-DM room with 1 person in it
|
||||
const room = createRoom({ name: "X Room", isDm: false, userIds: [] });
|
||||
const rendered = mountHeader(room);
|
||||
|
||||
// Then the room's avatar is the initial of its name
|
||||
const initial = findSpan(rendered, ".mx_BaseAvatar_initial");
|
||||
expect(initial.text()).toEqual("X");
|
||||
|
||||
// And there is no image avatar (because it's not set on this room)
|
||||
const image = findImg(rendered, ".mx_BaseAvatar_image");
|
||||
expect(image.prop("src")).toEqual("data:image/png;base64,00");
|
||||
});
|
||||
|
||||
it("shows the room avatar in a room with 2 people", () => {
|
||||
// When we render a non-DM room with 2 people in it
|
||||
const room = createRoom({ name: "Y Room", isDm: false, userIds: ["other"] });
|
||||
const rendered = mountHeader(room);
|
||||
|
||||
// Then the room's avatar is the initial of its name
|
||||
const initial = findSpan(rendered, ".mx_BaseAvatar_initial");
|
||||
expect(initial.text()).toEqual("Y");
|
||||
|
||||
// And there is no image avatar (because it's not set on this room)
|
||||
const image = findImg(rendered, ".mx_BaseAvatar_image");
|
||||
expect(image.prop("src")).toEqual("data:image/png;base64,00");
|
||||
});
|
||||
|
||||
it("shows the room avatar in a room with >2 people", () => {
|
||||
// When we render a non-DM room with 3 people in it
|
||||
const room = createRoom({ name: "Z Room", isDm: false, userIds: ["other1", "other2"] });
|
||||
const rendered = mountHeader(room);
|
||||
|
||||
// Then the room's avatar is the initial of its name
|
||||
const initial = findSpan(rendered, ".mx_BaseAvatar_initial");
|
||||
expect(initial.text()).toEqual("Z");
|
||||
|
||||
// And there is no image avatar (because it's not set on this room)
|
||||
const image = findImg(rendered, ".mx_BaseAvatar_image");
|
||||
expect(image.prop("src")).toEqual("data:image/png;base64,00");
|
||||
});
|
||||
|
||||
it("shows the room avatar in a DM with only ourselves", () => {
|
||||
// When we render a non-DM room with 1 person in it
|
||||
const room = createRoom({ name: "Z Room", isDm: true, userIds: [] });
|
||||
const rendered = mountHeader(room);
|
||||
|
||||
// Then the room's avatar is the initial of its name
|
||||
const initial = findSpan(rendered, ".mx_BaseAvatar_initial");
|
||||
expect(initial.text()).toEqual("Z");
|
||||
|
||||
// And there is no image avatar (because it's not set on this room)
|
||||
const image = findImg(rendered, ".mx_BaseAvatar_image");
|
||||
expect(image.prop("src")).toEqual("data:image/png;base64,00");
|
||||
});
|
||||
|
||||
it("shows the user avatar in a DM with 2 people", () => {
|
||||
// Note: this is the interesting case - this is the ONLY
|
||||
// time we should use the user's avatar.
|
||||
|
||||
// When we render a DM room with only 2 people in it
|
||||
const room = createRoom({ name: "Y Room", isDm: true, userIds: ["other"] });
|
||||
const rendered = mountHeader(room);
|
||||
|
||||
// Then we use the other user's avatar as our room's image avatar
|
||||
const image = findImg(rendered, ".mx_BaseAvatar_image");
|
||||
expect(image.prop("src")).toEqual("http://this.is.a.url/example.org/other");
|
||||
|
||||
// And there is no initial avatar
|
||||
expect(rendered.find(".mx_BaseAvatar_initial")).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("shows the room avatar in a DM with >2 people", () => {
|
||||
// When we render a DM room with 3 people in it
|
||||
const room = createRoom({
|
||||
name: "Z Room",
|
||||
isDm: true,
|
||||
userIds: ["other1", "other2"],
|
||||
});
|
||||
const rendered = mountHeader(room);
|
||||
|
||||
// Then the room's avatar is the initial of its name
|
||||
const initial = findSpan(rendered, ".mx_BaseAvatar_initial");
|
||||
expect(initial.text()).toEqual("Z");
|
||||
|
||||
// And there is no image avatar (because it's not set on this room)
|
||||
const image = findImg(rendered, ".mx_BaseAvatar_image");
|
||||
expect(image.prop("src")).toEqual("data:image/png;base64,00");
|
||||
});
|
||||
|
||||
it("renders call buttons normally", () => {
|
||||
const room = createRoom({ name: "Room", isDm: false, userIds: ["other"] });
|
||||
const wrapper = mountHeader(room);
|
||||
|
||||
expect(wrapper.find('[aria-label="Voice call"]').hostNodes()).toHaveLength(1);
|
||||
expect(wrapper.find('[aria-label="Video call"]').hostNodes()).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("hides call buttons when the room is tombstoned", () => {
|
||||
const room = createRoom({ name: "Room", isDm: false, userIds: [] });
|
||||
const wrapper = mountHeader(
|
||||
room,
|
||||
{},
|
||||
{
|
||||
tombstone: mkEvent({
|
||||
event: true,
|
||||
type: "m.room.tombstone",
|
||||
room: room.roomId,
|
||||
user: "@user1:server",
|
||||
skey: "",
|
||||
content: {},
|
||||
ts: Date.now(),
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
expect(wrapper.find('[aria-label="Voice call"]').hostNodes()).toHaveLength(0);
|
||||
expect(wrapper.find('[aria-label="Video call"]').hostNodes()).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("should render buttons if not passing showButtons (default true)", () => {
|
||||
const room = createRoom({ name: "Room", isDm: false, userIds: [] });
|
||||
const wrapper = mountHeader(room);
|
||||
expect(wrapper.find(".mx_RoomHeader_button")).not.toHaveLength(0);
|
||||
});
|
||||
|
||||
it("should not render buttons if passing showButtons = false", () => {
|
||||
const room = createRoom({ name: "Room", isDm: false, userIds: [] });
|
||||
const wrapper = mountHeader(room, { showButtons: false });
|
||||
expect(wrapper.find(".mx_RoomHeader_button")).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("should render the room options context menu if not passing enableRoomOptionsMenu (default true)", () => {
|
||||
const room = createRoom({ name: "Room", isDm: false, userIds: [] });
|
||||
const wrapper = mountHeader(room);
|
||||
expect(wrapper.find(".mx_RoomHeader_name.mx_AccessibleButton")).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("should not render the room options context menu if passing enableRoomOptionsMenu = false", () => {
|
||||
const room = createRoom({ name: "Room", isDm: false, userIds: [] });
|
||||
const wrapper = mountHeader(room, { enableRoomOptionsMenu: false });
|
||||
expect(wrapper.find(".mx_RoomHeader_name.mx_AccessibleButton")).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
interface IRoomCreationInfo {
|
||||
name: string;
|
||||
isDm: boolean;
|
||||
userIds: string[];
|
||||
}
|
||||
|
||||
function createRoom(info: IRoomCreationInfo) {
|
||||
stubClient();
|
||||
const client: MatrixClient = MatrixClientPeg.get();
|
||||
|
||||
const roomId = "!1234567890:domain";
|
||||
const userId = client.getUserId()!;
|
||||
if (info.isDm) {
|
||||
client.getAccountData = (eventType) => {
|
||||
expect(eventType).toEqual("m.direct");
|
||||
return mkDirectEvent(roomId, userId, info.userIds);
|
||||
};
|
||||
}
|
||||
|
||||
DMRoomMap.makeShared().start();
|
||||
|
||||
const room = new Room(roomId, client, userId, {
|
||||
pendingEventOrdering: PendingEventOrdering.Detached,
|
||||
});
|
||||
|
||||
const otherJoinEvents: MatrixEvent[] = [];
|
||||
for (const otherUserId of info.userIds) {
|
||||
otherJoinEvents.push(mkJoinEvent(roomId, otherUserId));
|
||||
}
|
||||
|
||||
room.currentState.setStateEvents([
|
||||
mkCreationEvent(roomId, userId),
|
||||
mkNameEvent(roomId, userId, info.name),
|
||||
mkJoinEvent(roomId, userId),
|
||||
...otherJoinEvents,
|
||||
]);
|
||||
room.recalculate();
|
||||
|
||||
return room;
|
||||
}
|
||||
|
||||
function mountHeader(room: Room, propsOverride = {}, roomContext?: Partial<IRoomState>): ReactWrapper {
|
||||
const props: RoomHeaderProps = {
|
||||
room,
|
||||
inRoom: true,
|
||||
onSearchClick: () => {},
|
||||
onInviteClick: null,
|
||||
onForgetClick: () => {},
|
||||
onAppsClick: () => {},
|
||||
e2eStatus: E2EStatus.Normal,
|
||||
appsShown: true,
|
||||
searchInfo: {
|
||||
searchId: Math.random(),
|
||||
promise: new Promise<ISearchResults>(() => {}),
|
||||
term: "",
|
||||
scope: SearchScope.Room,
|
||||
count: 0,
|
||||
},
|
||||
viewingCall: false,
|
||||
activeCall: null,
|
||||
...propsOverride,
|
||||
};
|
||||
|
||||
return mount(
|
||||
<RoomContext.Provider value={{ ...roomContext, room } as IRoomState}>
|
||||
<RoomHeader {...props} />
|
||||
</RoomContext.Provider>,
|
||||
);
|
||||
}
|
||||
|
||||
function mkCreationEvent(roomId: string, userId: string): MatrixEvent {
|
||||
return mkEvent({
|
||||
event: true,
|
||||
type: "m.room.create",
|
||||
room: roomId,
|
||||
user: userId,
|
||||
content: {
|
||||
creator: userId,
|
||||
room_version: "5",
|
||||
predecessor: {
|
||||
room_id: "!prevroom",
|
||||
event_id: "$someevent",
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function mkNameEvent(roomId: string, userId: string, name: string): MatrixEvent {
|
||||
return mkEvent({
|
||||
event: true,
|
||||
type: "m.room.name",
|
||||
room: roomId,
|
||||
user: userId,
|
||||
content: { name },
|
||||
});
|
||||
}
|
||||
|
||||
function mkJoinEvent(roomId: string, userId: string) {
|
||||
const ret = mkEvent({
|
||||
event: true,
|
||||
type: "m.room.member",
|
||||
room: roomId,
|
||||
user: userId,
|
||||
content: {
|
||||
membership: "join",
|
||||
avatar_url: "mxc://example.org/" + userId,
|
||||
},
|
||||
});
|
||||
ret.event.state_key = userId;
|
||||
return ret;
|
||||
}
|
||||
|
||||
function mkDirectEvent(roomId: string, userId: string, otherUsers: string[]): MatrixEvent {
|
||||
const content: Record<string, string[]> = {};
|
||||
for (const otherUserId of otherUsers) {
|
||||
content[otherUserId] = [roomId];
|
||||
}
|
||||
return mkEvent({
|
||||
event: true,
|
||||
type: "m.direct",
|
||||
room: roomId,
|
||||
user: userId,
|
||||
content,
|
||||
});
|
||||
}
|
||||
|
||||
function findSpan(wrapper: ReactWrapper, selector: string): ReactWrapper {
|
||||
const els = wrapper.find(selector).hostNodes();
|
||||
expect(els).toHaveLength(1);
|
||||
return els.at(0);
|
||||
}
|
||||
|
||||
function findImg(wrapper: ReactWrapper, selector: string): ReactWrapper {
|
||||
const els = wrapper.find(selector).hostNodes();
|
||||
expect(els).toHaveLength(1);
|
||||
return els.at(0);
|
||||
}
|
||||
|
||||
describe("RoomHeader (React Testing Library)", () => {
|
||||
describe("RoomHeader", () => {
|
||||
let client: Mocked<MatrixClient>;
|
||||
let room: Room;
|
||||
let alice: RoomMember;
|
||||
|
@ -397,6 +111,9 @@ describe("RoomHeader (React Testing Library)", () => {
|
|||
[MediaDeviceKindEnum.VideoInput]: [],
|
||||
[MediaDeviceKindEnum.AudioOutput]: [],
|
||||
});
|
||||
|
||||
DMRoomMap.makeShared();
|
||||
jest.spyOn(DMRoomMap.shared(), "getUserIdForRoomId").mockReturnValue(carol.userId);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
|
@ -879,4 +596,274 @@ describe("RoomHeader (React Testing Library)", () => {
|
|||
|
||||
expect(screen.queryByRole("button", { name: /invite/i })).toBeNull();
|
||||
});
|
||||
|
||||
it("shows the room avatar in a room with only ourselves", () => {
|
||||
// When we render a non-DM room with 1 person in it
|
||||
const room = createRoom({ name: "X Room", isDm: false, userIds: [] });
|
||||
const rendered = mountHeader(room);
|
||||
|
||||
// Then the room's avatar is the initial of its name
|
||||
const initial = rendered.container.querySelector(".mx_BaseAvatar_initial");
|
||||
expect(initial).toHaveTextContent("X");
|
||||
|
||||
// And there is no image avatar (because it's not set on this room)
|
||||
const image = rendered.container.querySelector(".mx_BaseAvatar_image");
|
||||
expect(image).toHaveAttribute("src", "data:image/png;base64,00");
|
||||
});
|
||||
|
||||
it("shows the room avatar in a room with 2 people", () => {
|
||||
// When we render a non-DM room with 2 people in it
|
||||
const room = createRoom({ name: "Y Room", isDm: false, userIds: ["other"] });
|
||||
const rendered = mountHeader(room);
|
||||
|
||||
// Then the room's avatar is the initial of its name
|
||||
const initial = rendered.container.querySelector(".mx_BaseAvatar_initial");
|
||||
expect(initial).toHaveTextContent("Y");
|
||||
|
||||
// And there is no image avatar (because it's not set on this room)
|
||||
const image = rendered.container.querySelector(".mx_BaseAvatar_image");
|
||||
expect(image).toHaveAttribute("src", "data:image/png;base64,00");
|
||||
});
|
||||
|
||||
it("shows the room avatar in a room with >2 people", () => {
|
||||
// When we render a non-DM room with 3 people in it
|
||||
const room = createRoom({ name: "Z Room", isDm: false, userIds: ["other1", "other2"] });
|
||||
const rendered = mountHeader(room);
|
||||
|
||||
// Then the room's avatar is the initial of its name
|
||||
const initial = rendered.container.querySelector(".mx_BaseAvatar_initial");
|
||||
expect(initial).toHaveTextContent("Z");
|
||||
|
||||
// And there is no image avatar (because it's not set on this room)
|
||||
const image = rendered.container.querySelector(".mx_BaseAvatar_image");
|
||||
expect(image).toHaveAttribute("src", "data:image/png;base64,00");
|
||||
});
|
||||
|
||||
it("shows the room avatar in a DM with only ourselves", () => {
|
||||
// When we render a non-DM room with 1 person in it
|
||||
const room = createRoom({ name: "Z Room", isDm: true, userIds: [] });
|
||||
const rendered = mountHeader(room);
|
||||
|
||||
// Then the room's avatar is the initial of its name
|
||||
const initial = rendered.container.querySelector(".mx_BaseAvatar_initial");
|
||||
expect(initial).toHaveTextContent("Z");
|
||||
|
||||
// And there is no image avatar (because it's not set on this room)
|
||||
const image = rendered.container.querySelector(".mx_BaseAvatar_image");
|
||||
expect(image).toHaveAttribute("src", "data:image/png;base64,00");
|
||||
});
|
||||
|
||||
it("shows the user avatar in a DM with 2 people", () => {
|
||||
// Note: this is the interesting case - this is the ONLY
|
||||
// time we should use the user's avatar.
|
||||
|
||||
// When we render a DM room with only 2 people in it
|
||||
const room = createRoom({ name: "Y Room", isDm: true, userIds: ["other"] });
|
||||
const rendered = mountHeader(room);
|
||||
|
||||
// Then we use the other user's avatar as our room's image avatar
|
||||
const image = rendered.container.querySelector(".mx_BaseAvatar_image");
|
||||
expect(image).toHaveAttribute("src", "http://this.is.a.url/example.org/other");
|
||||
|
||||
// And there is no initial avatar
|
||||
expect(rendered.container.querySelector(".mx_BaseAvatar_initial")).toBeFalsy();
|
||||
});
|
||||
|
||||
it("shows the room avatar in a DM with >2 people", () => {
|
||||
// When we render a DM room with 3 people in it
|
||||
const room = createRoom({
|
||||
name: "Z Room",
|
||||
isDm: true,
|
||||
userIds: ["other1", "other2"],
|
||||
});
|
||||
const rendered = mountHeader(room);
|
||||
|
||||
// Then the room's avatar is the initial of its name
|
||||
const initial = rendered.container.querySelector(".mx_BaseAvatar_initial");
|
||||
expect(initial).toHaveTextContent("Z");
|
||||
|
||||
// And there is no image avatar (because it's not set on this room)
|
||||
const image = rendered.container.querySelector(".mx_BaseAvatar_image");
|
||||
expect(image).toHaveAttribute("src", "data:image/png;base64,00");
|
||||
});
|
||||
|
||||
it("renders call buttons normally", () => {
|
||||
const room = createRoom({ name: "Room", isDm: false, userIds: ["other"] });
|
||||
const wrapper = mountHeader(room);
|
||||
|
||||
expect(wrapper.container.querySelector('[aria-label="Voice call"]')).toBeDefined();
|
||||
expect(wrapper.container.querySelector('[aria-label="Video call"]')).toBeDefined();
|
||||
});
|
||||
|
||||
it("hides call buttons when the room is tombstoned", () => {
|
||||
const room = createRoom({ name: "Room", isDm: false, userIds: [] });
|
||||
const wrapper = mountHeader(
|
||||
room,
|
||||
{},
|
||||
{
|
||||
tombstone: mkEvent({
|
||||
event: true,
|
||||
type: "m.room.tombstone",
|
||||
room: room.roomId,
|
||||
user: "@user1:server",
|
||||
skey: "",
|
||||
content: {},
|
||||
ts: Date.now(),
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
expect(wrapper.container.querySelector('[aria-label="Voice call"]')).toBeFalsy();
|
||||
expect(wrapper.container.querySelector('[aria-label="Video call"]')).toBeFalsy();
|
||||
});
|
||||
|
||||
it("should render buttons if not passing showButtons (default true)", () => {
|
||||
const room = createRoom({ name: "Room", isDm: false, userIds: [] });
|
||||
const wrapper = mountHeader(room);
|
||||
expect(wrapper.container.querySelector(".mx_RoomHeader_button")).toBeDefined();
|
||||
});
|
||||
|
||||
it("should not render buttons if passing showButtons = false", () => {
|
||||
const room = createRoom({ name: "Room", isDm: false, userIds: [] });
|
||||
const wrapper = mountHeader(room, { showButtons: false });
|
||||
expect(wrapper.container.querySelector(".mx_RoomHeader_button")).toBeFalsy();
|
||||
});
|
||||
|
||||
it("should render the room options context menu if not passing enableRoomOptionsMenu (default true)", () => {
|
||||
const room = createRoom({ name: "Room", isDm: false, userIds: [] });
|
||||
const wrapper = mountHeader(room);
|
||||
expect(wrapper.container.querySelector(".mx_RoomHeader_name.mx_AccessibleButton")).toBeDefined();
|
||||
});
|
||||
|
||||
it("should not render the room options context menu if passing enableRoomOptionsMenu = false", () => {
|
||||
const room = createRoom({ name: "Room", isDm: false, userIds: [] });
|
||||
const wrapper = mountHeader(room, { enableRoomOptionsMenu: false });
|
||||
expect(wrapper.container.querySelector(".mx_RoomHeader_name.mx_AccessibleButton")).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
interface IRoomCreationInfo {
|
||||
name: string;
|
||||
isDm: boolean;
|
||||
userIds: string[];
|
||||
}
|
||||
|
||||
function createRoom(info: IRoomCreationInfo) {
|
||||
stubClient();
|
||||
const client: MatrixClient = MatrixClientPeg.get();
|
||||
|
||||
const roomId = "!1234567890:domain";
|
||||
const userId = client.getUserId()!;
|
||||
if (info.isDm) {
|
||||
client.getAccountData = (eventType) => {
|
||||
expect(eventType).toEqual("m.direct");
|
||||
return mkDirectEvent(roomId, userId, info.userIds);
|
||||
};
|
||||
}
|
||||
|
||||
DMRoomMap.makeShared().start();
|
||||
|
||||
const room = new Room(roomId, client, userId, {
|
||||
pendingEventOrdering: PendingEventOrdering.Detached,
|
||||
});
|
||||
|
||||
const otherJoinEvents: MatrixEvent[] = [];
|
||||
for (const otherUserId of info.userIds) {
|
||||
otherJoinEvents.push(mkJoinEvent(roomId, otherUserId));
|
||||
}
|
||||
|
||||
room.currentState.setStateEvents([
|
||||
mkCreationEvent(roomId, userId),
|
||||
mkNameEvent(roomId, userId, info.name),
|
||||
mkJoinEvent(roomId, userId),
|
||||
...otherJoinEvents,
|
||||
]);
|
||||
room.recalculate();
|
||||
|
||||
return room;
|
||||
}
|
||||
|
||||
function mountHeader(room: Room, propsOverride = {}, roomContext?: Partial<IRoomState>): RenderResult {
|
||||
const props: RoomHeaderProps = {
|
||||
room,
|
||||
inRoom: true,
|
||||
onSearchClick: () => {},
|
||||
onInviteClick: null,
|
||||
onForgetClick: () => {},
|
||||
onAppsClick: () => {},
|
||||
e2eStatus: E2EStatus.Normal,
|
||||
appsShown: true,
|
||||
searchInfo: {
|
||||
searchId: Math.random(),
|
||||
promise: new Promise<ISearchResults>(() => {}),
|
||||
term: "",
|
||||
scope: SearchScope.Room,
|
||||
count: 0,
|
||||
},
|
||||
viewingCall: false,
|
||||
activeCall: null,
|
||||
...propsOverride,
|
||||
};
|
||||
|
||||
return render(
|
||||
<RoomContext.Provider value={{ ...roomContext, room } as IRoomState}>
|
||||
<RoomHeader {...props} />
|
||||
</RoomContext.Provider>,
|
||||
);
|
||||
}
|
||||
|
||||
function mkCreationEvent(roomId: string, userId: string): MatrixEvent {
|
||||
return mkEvent({
|
||||
event: true,
|
||||
type: "m.room.create",
|
||||
room: roomId,
|
||||
user: userId,
|
||||
content: {
|
||||
creator: userId,
|
||||
room_version: "5",
|
||||
predecessor: {
|
||||
room_id: "!prevroom",
|
||||
event_id: "$someevent",
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function mkNameEvent(roomId: string, userId: string, name: string): MatrixEvent {
|
||||
return mkEvent({
|
||||
event: true,
|
||||
type: "m.room.name",
|
||||
room: roomId,
|
||||
user: userId,
|
||||
content: { name },
|
||||
});
|
||||
}
|
||||
|
||||
function mkJoinEvent(roomId: string, userId: string) {
|
||||
const ret = mkEvent({
|
||||
event: true,
|
||||
type: "m.room.member",
|
||||
room: roomId,
|
||||
user: userId,
|
||||
content: {
|
||||
membership: "join",
|
||||
avatar_url: "mxc://example.org/" + userId,
|
||||
},
|
||||
});
|
||||
ret.event.state_key = userId;
|
||||
return ret;
|
||||
}
|
||||
|
||||
function mkDirectEvent(roomId: string, userId: string, otherUsers: string[]): MatrixEvent {
|
||||
const content: Record<string, string[]> = {};
|
||||
for (const otherUserId of otherUsers) {
|
||||
content[otherUserId] = [roomId];
|
||||
}
|
||||
return mkEvent({
|
||||
event: true,
|
||||
type: "m.direct",
|
||||
room: roomId,
|
||||
user: userId,
|
||||
content,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -14,26 +14,36 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount, ReactWrapper } from "enzyme";
|
||||
import React, { createRef, RefObject } from "react";
|
||||
import { render } from "@testing-library/react";
|
||||
import { MatrixClient, MsgType, Room } from "matrix-js-sdk/src/matrix";
|
||||
import { mocked } from "jest-mock";
|
||||
|
||||
import VoiceRecordComposerTile from "../../../../src/components/views/rooms/VoiceRecordComposerTile";
|
||||
import { VoiceRecording } from "../../../../src/audio/VoiceRecording";
|
||||
import { doMaybeLocalRoomAction } from "../../../../src/utils/local-room";
|
||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||
import { IUpload } from "../../../../src/audio/VoiceMessageRecording";
|
||||
import { IUpload, VoiceMessageRecording } from "../../../../src/audio/VoiceMessageRecording";
|
||||
import { RoomPermalinkCreator } from "../../../../src/utils/permalinks/Permalinks";
|
||||
import { VoiceRecordingStore } from "../../../../src/stores/VoiceRecordingStore";
|
||||
import { PlaybackClock } from "../../../../src/audio/PlaybackClock";
|
||||
|
||||
jest.mock("../../../../src/utils/local-room", () => ({
|
||||
doMaybeLocalRoomAction: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock("../../../../src/stores/VoiceRecordingStore", () => ({
|
||||
VoiceRecordingStore: {
|
||||
getVoiceRecordingId: jest.fn().mockReturnValue("voice-recording-id"),
|
||||
instance: {
|
||||
getActiveRecording: jest.fn(),
|
||||
disposeRecording: jest.fn(),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
describe("<VoiceRecordComposerTile/>", () => {
|
||||
let voiceRecordComposerTile: ReactWrapper<VoiceRecordComposerTile>;
|
||||
let mockRecorder: VoiceRecording;
|
||||
let voiceRecordComposerTile: RefObject<VoiceRecordComposerTile>;
|
||||
let mockRecorder: VoiceMessageRecording;
|
||||
let mockUpload: IUpload;
|
||||
let mockClient: MatrixClient;
|
||||
const roomId = "!room:example.com";
|
||||
|
@ -47,26 +57,42 @@ describe("<VoiceRecordComposerTile/>", () => {
|
|||
const room = {
|
||||
roomId,
|
||||
} as unknown as Room;
|
||||
|
||||
voiceRecordComposerTile = createRef();
|
||||
const props = {
|
||||
room,
|
||||
ref: voiceRecordComposerTile,
|
||||
permalinkCreator: new RoomPermalinkCreator(room),
|
||||
};
|
||||
mockUpload = {
|
||||
mxc: "mxc://example.com/voice",
|
||||
};
|
||||
mockRecorder = {
|
||||
on: jest.fn(),
|
||||
off: jest.fn(),
|
||||
stop: jest.fn(),
|
||||
upload: () => Promise.resolve(mockUpload),
|
||||
durationSeconds: 1337,
|
||||
contentType: "audio/ogg",
|
||||
getPlayback: () => ({
|
||||
on: jest.fn(),
|
||||
off: jest.fn(),
|
||||
prepare: jest.fn().mockResolvedValue(void 0),
|
||||
clockInfo: {
|
||||
timeSeconds: 0,
|
||||
liveData: {
|
||||
onUpdate: jest.fn(),
|
||||
},
|
||||
} as unknown as PlaybackClock,
|
||||
waveform: [1.4, 2.5, 3.6],
|
||||
waveformData: {
|
||||
onUpdate: jest.fn(),
|
||||
},
|
||||
thumbnailWaveform: [1.4, 2.5, 3.6],
|
||||
}),
|
||||
} as unknown as VoiceRecording;
|
||||
voiceRecordComposerTile = mount(<VoiceRecordComposerTile {...props} />);
|
||||
voiceRecordComposerTile.setState({
|
||||
recorder: mockRecorder,
|
||||
});
|
||||
} as unknown as VoiceMessageRecording;
|
||||
mocked(VoiceRecordingStore.instance.getActiveRecording).mockReturnValue(mockRecorder);
|
||||
render(<VoiceRecordComposerTile {...props} />);
|
||||
|
||||
mocked(doMaybeLocalRoomAction).mockImplementation(
|
||||
<T,>(roomId: string, fn: (actualRoomId: string) => Promise<T>, _client?: MatrixClient) => {
|
||||
|
@ -77,7 +103,7 @@ describe("<VoiceRecordComposerTile/>", () => {
|
|||
|
||||
describe("send", () => {
|
||||
it("should send the voice recording", async () => {
|
||||
await (voiceRecordComposerTile.instance() as VoiceRecordComposerTile).send();
|
||||
await voiceRecordComposerTile.current!.send();
|
||||
expect(mockClient.sendMessage).toHaveBeenCalledWith(roomId, {
|
||||
"body": "Voice message",
|
||||
"file": undefined,
|
||||
|
|
|
@ -16,8 +16,7 @@ limitations under the License.
|
|||
|
||||
import React from "react";
|
||||
import { mocked } from "jest-mock";
|
||||
import { act, Simulate } from "react-dom/test-utils";
|
||||
import { fireEvent, render, RenderResult } from "@testing-library/react";
|
||||
import { act, fireEvent, render, RenderResult } from "@testing-library/react";
|
||||
import { EventType, MatrixClient, Room } from "matrix-js-sdk/src/matrix";
|
||||
import { GuestAccess, HistoryVisibility, JoinRule } from "matrix-js-sdk/src/@types/partials";
|
||||
|
||||
|
@ -163,8 +162,8 @@ describe("<SpaceSettingsVisibilityTab />", () => {
|
|||
(mockMatrixClient.sendStateEvent as jest.Mock).mockRejectedValue({});
|
||||
const component = getComponent({ space });
|
||||
await toggleGuestAccessSection(component);
|
||||
await act(async () => {
|
||||
Simulate.click(getGuestAccessToggle(component)!);
|
||||
await act(() => {
|
||||
fireEvent.click(getGuestAccessToggle(component)!);
|
||||
});
|
||||
|
||||
expect(getErrorMessage(component)).toEqual("Failed to update the guest access of this space");
|
||||
|
@ -213,14 +212,14 @@ describe("<SpaceSettingsVisibilityTab />", () => {
|
|||
(mockMatrixClient.sendStateEvent as jest.Mock).mockRejectedValue({});
|
||||
const component = getComponent({ space });
|
||||
|
||||
await act(async () => {
|
||||
Simulate.click(getHistoryVisibilityToggle(component)!);
|
||||
await act(() => {
|
||||
fireEvent.click(getHistoryVisibilityToggle(component)!);
|
||||
});
|
||||
|
||||
expect(getErrorMessage(component)).toEqual("Failed to update the history visibility of this space");
|
||||
});
|
||||
|
||||
it("disables room preview toggle when history visability changes are not allowed", () => {
|
||||
it("disables room preview toggle when history visibility changes are not allowed", () => {
|
||||
const space = makeMockSpace(mockMatrixClient, joinRule, guestRule, historyRule);
|
||||
(space.currentState.maySendStateEvent as jest.Mock).mockReturnValue(false);
|
||||
const component = getComponent({ space });
|
||||
|
|
|
@ -14,10 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { ReactWrapper } from "enzyme";
|
||||
import { act } from "react-dom/test-utils";
|
||||
import { act as actRTL, fireEvent, RenderResult } from "@testing-library/react";
|
||||
import { act, fireEvent, RenderResult } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
|
||||
export const addTextToComposer = (container: HTMLElement, text: string) =>
|
||||
|
@ -34,23 +31,8 @@ export const addTextToComposer = (container: HTMLElement, text: string) =>
|
|||
fireEvent.paste(container.querySelector('[role="textbox"]')!, pasteEvent);
|
||||
});
|
||||
|
||||
export const addTextToComposerEnzyme = (wrapper: ReactWrapper, text: string) =>
|
||||
act(() => {
|
||||
// couldn't get input event on contenteditable to work
|
||||
// paste works without illegal private method access
|
||||
const pasteEvent: Partial<ClipboardEvent> = {
|
||||
clipboardData: {
|
||||
types: [],
|
||||
files: [],
|
||||
getData: (type: string) => (type === "text/plain" ? text : undefined),
|
||||
} as unknown as DataTransfer,
|
||||
};
|
||||
wrapper.find('[role="textbox"]').simulate("paste", pasteEvent);
|
||||
wrapper.update();
|
||||
});
|
||||
|
||||
export const addTextToComposerRTL = async (renderResult: RenderResult, text: string): Promise<void> => {
|
||||
await actRTL(async () => {
|
||||
await act(async () => {
|
||||
await userEvent.click(renderResult.getByLabelText("Send a message…"));
|
||||
await userEvent.keyboard(text);
|
||||
});
|
||||
|
|
|
@ -96,7 +96,7 @@ export function createTestClient(): MatrixClient {
|
|||
getUserId: jest.fn().mockReturnValue("@userId:matrix.org"),
|
||||
getSafeUserId: jest.fn().mockReturnValue("@userId:matrix.org"),
|
||||
getUserIdLocalpart: jest.fn().mockResolvedValue("userId"),
|
||||
getUser: jest.fn().mockReturnValue({ on: jest.fn() }),
|
||||
getUser: jest.fn().mockReturnValue({ on: jest.fn(), off: jest.fn() }),
|
||||
getDevice: jest.fn(),
|
||||
getDeviceId: jest.fn().mockReturnValue("ABCDEFGHI"),
|
||||
getStoredCrossSigningForUser: jest.fn(),
|
||||
|
@ -455,6 +455,7 @@ export function mkRoomMember(roomId: string, userId: string, membership = "join"
|
|||
getAvatarUrl: () => {},
|
||||
getMxcAvatarUrl: () => {},
|
||||
getDMInviter: () => {},
|
||||
off: () => {},
|
||||
} as unknown as RoomMember;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,6 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { ReactWrapper } from "enzyme";
|
||||
import EventEmitter from "events";
|
||||
|
||||
import { ActionPayload } from "../../src/dispatcher/payloads";
|
||||
|
@ -128,17 +126,6 @@ export function untilEmission(
|
|||
});
|
||||
}
|
||||
|
||||
export const findByAttr = (attr: string) => (component: ReactWrapper, value: string) =>
|
||||
component.find(`[${attr}="${value}"]`);
|
||||
export const findByTestId = findByAttr("data-test-id");
|
||||
export const findById = findByAttr("id");
|
||||
export const findByAriaLabel = findByAttr("aria-label");
|
||||
|
||||
const findByTagAndAttr = (attr: string) => (component: ReactWrapper, value: string, tag: string) =>
|
||||
component.find(`${tag}[${attr}="${value}"]`);
|
||||
|
||||
export const findByTagAndTestId = findByTagAndAttr("data-test-id");
|
||||
|
||||
export const flushPromises = async () => await new Promise((resolve) => window.setTimeout(resolve));
|
||||
|
||||
// with jest's modern fake timers process.nextTick is also mocked,
|
||||
|
|
|
@ -30,7 +30,7 @@ describe("DMRoomMap", () => {
|
|||
"user@example.com": [roomId1, roomId2],
|
||||
"@user:example.com": [roomId1, roomId3, roomId4],
|
||||
"@user2:example.com": [] as string[],
|
||||
} satisfies IContent;
|
||||
} as IContent;
|
||||
|
||||
let client: Mocked<MatrixClient>;
|
||||
let dmRoomMap: DMRoomMap;
|
||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { renderToString } from "react-dom/server";
|
||||
import { render } from "@testing-library/react";
|
||||
import {
|
||||
IContent,
|
||||
MatrixClient,
|
||||
|
@ -227,6 +227,10 @@ describe("export", function () {
|
|||
return matrixEvents;
|
||||
}
|
||||
|
||||
function renderToString(elem: JSX.Element): string {
|
||||
return render(elem).container.outerHTML;
|
||||
}
|
||||
|
||||
it("checks if the export format is valid", function () {
|
||||
function isValidFormat(format: string): boolean {
|
||||
const options: string[] = Object.values(ExportFormat);
|
||||
|
@ -255,7 +259,7 @@ describe("export", function () {
|
|||
},
|
||||
setProgressText,
|
||||
);
|
||||
const imageRegex = /<img.+ src="mxc:\/\/test.org" alt="image.png"\/>/;
|
||||
const imageRegex = /<img.+ src="mxc:\/\/test.org" alt="image\.png"\/?>/;
|
||||
expect(imageRegex.test(renderToString(exporter.getEventTile(mkImageEvent(), true)))).toBeTruthy();
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue