{
public render(): JSX.Element {
const { children: content, language } = this.props;
- const highlighted = language ? hljs.highlight(language, content) : hljs.highlightAuto(content);
+ const highlighted = language ? hljs.highlight(content, { language }) : hljs.highlightAuto(content);
return (
diff --git a/src/components/views/messages/MPollBody.tsx b/src/components/views/messages/MPollBody.tsx
index 805368b1b6..a9317957c6 100644
--- a/src/components/views/messages/MPollBody.tsx
+++ b/src/components/views/messages/MPollBody.tsx
@@ -20,17 +20,11 @@ import { logger } from "matrix-js-sdk/src/logger";
import { MatrixEvent, MatrixEventEvent } from "matrix-js-sdk/src/models/event";
import { Relations, RelationsEvent } from "matrix-js-sdk/src/models/relations";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
-import {
- M_POLL_END,
- M_POLL_KIND_DISCLOSED,
- M_POLL_RESPONSE,
- M_POLL_START,
- NamespacedValue,
- PollAnswerSubevent,
- PollResponseEvent,
- PollStartEvent,
-} from "matrix-events-sdk";
+import { M_POLL_END, M_POLL_KIND_DISCLOSED, M_POLL_RESPONSE, M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { RelatedRelations } from "matrix-js-sdk/src/models/related-relations";
+import { NamespacedValue } from "matrix-events-sdk";
+import { PollStartEvent, PollAnswerSubevent } from "matrix-js-sdk/src/extensible_events_v1/PollStartEvent";
+import { PollResponseEvent } from "matrix-js-sdk/src/extensible_events_v1/PollResponseEvent";
import { _t } from "../../../languageHandler";
import Modal from "../../../Modal";
@@ -454,7 +448,7 @@ export default class MPollBody extends React.Component {
return (
-
+
{poll.question.text}
{editedSpan}
@@ -477,7 +471,12 @@ export default class MPollBody extends React.Component {
const answerPercent = totalVotes === 0 ? 0 : Math.round((100.0 * answerVotes) / totalVotes);
return (
- this.selectOption(answer.id)}>
+
this.selectOption(answer.id)}
+ >
{ended ? (
) : (
@@ -499,7 +498,9 @@ export default class MPollBody extends React.Component {
);
})}
-
{totalText}
+
+ {totalText}
+
);
}
diff --git a/src/components/views/messages/MessageEvent.tsx b/src/components/views/messages/MessageEvent.tsx
index b61f871f7f..781afc9ad5 100644
--- a/src/components/views/messages/MessageEvent.tsx
+++ b/src/components/views/messages/MessageEvent.tsx
@@ -18,7 +18,7 @@ import React, { createRef } from "react";
import { EventType, MsgType } from "matrix-js-sdk/src/@types/event";
import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon";
import { M_LOCATION } from "matrix-js-sdk/src/@types/location";
-import { M_POLL_START } from "matrix-events-sdk";
+import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { MatrixEventEvent } from "matrix-js-sdk/src/models/event";
import SettingsStore from "../../../settings/SettingsStore";
diff --git a/src/components/views/rooms/MessageComposerButtons.tsx b/src/components/views/rooms/MessageComposerButtons.tsx
index 6dfb18f524..17522e3be6 100644
--- a/src/components/views/rooms/MessageComposerButtons.tsx
+++ b/src/components/views/rooms/MessageComposerButtons.tsx
@@ -16,7 +16,7 @@ limitations under the License.
import classNames from "classnames";
import { IEventRelation } from "matrix-js-sdk/src/models/event";
-import { M_POLL_START } from "matrix-events-sdk";
+import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import React, { createContext, MouseEventHandler, ReactElement, useContext, useRef } from "react";
import { Room } from "matrix-js-sdk/src/models/room";
import { MatrixClient } from "matrix-js-sdk/src/client";
diff --git a/src/components/views/rooms/PinnedEventTile.tsx b/src/components/views/rooms/PinnedEventTile.tsx
index c5064d5f9c..26b7f63c25 100644
--- a/src/components/views/rooms/PinnedEventTile.tsx
+++ b/src/components/views/rooms/PinnedEventTile.tsx
@@ -20,7 +20,7 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { Relations } from "matrix-js-sdk/src/models/relations";
import { EventType, RelationType } from "matrix-js-sdk/src/@types/event";
import { logger } from "matrix-js-sdk/src/logger";
-import { M_POLL_START, M_POLL_RESPONSE, M_POLL_END } from "matrix-events-sdk";
+import { M_POLL_START, M_POLL_RESPONSE, M_POLL_END } from "matrix-js-sdk/src/@types/polls";
import dis from "../../../dispatcher/dispatcher";
import { Action } from "../../../dispatcher/actions";
diff --git a/src/components/views/rooms/wysiwyg_composer/components/Editor.tsx b/src/components/views/rooms/wysiwyg_composer/components/Editor.tsx
index 215d3be84f..43e46572d6 100644
--- a/src/components/views/rooms/wysiwyg_composer/components/Editor.tsx
+++ b/src/components/views/rooms/wysiwyg_composer/components/Editor.tsx
@@ -20,7 +20,7 @@ import React, { CSSProperties, forwardRef, memo, MutableRefObject, ReactNode } f
import { useIsExpanded } from "../hooks/useIsExpanded";
import { useSelection } from "../hooks/useSelection";
-const HEIGHT_BREAKING_POINT = 20;
+const HEIGHT_BREAKING_POINT = 24;
interface EditorProps {
disabled: boolean;
diff --git a/src/components/views/rooms/wysiwyg_composer/components/FormattingButtons.tsx b/src/components/views/rooms/wysiwyg_composer/components/FormattingButtons.tsx
index 1d3f44bee7..7c1601b441 100644
--- a/src/components/views/rooms/wysiwyg_composer/components/FormattingButtons.tsx
+++ b/src/components/views/rooms/wysiwyg_composer/components/FormattingButtons.tsx
@@ -24,6 +24,8 @@ import { Icon as UnderlineIcon } from "../../../../../../res/img/element-icons/r
import { Icon as StrikeThroughIcon } from "../../../../../../res/img/element-icons/room/composer/strikethrough.svg";
import { Icon as InlineCodeIcon } from "../../../../../../res/img/element-icons/room/composer/inline_code.svg";
import { Icon as LinkIcon } from "../../../../../../res/img/element-icons/room/composer/link.svg";
+import { Icon as BulletedListIcon } from "../../../../../../res/img/element-icons/room/composer/bulleted_list.svg";
+import { Icon as NumberedListIcon } from "../../../../../../res/img/element-icons/room/composer/numbered_list.svg";
import AccessibleTooltipButton from "../../../elements/AccessibleTooltipButton";
import { Alignment } from "../../../elements/Tooltip";
import { KeyboardShortcut } from "../../../settings/KeyboardShortcut";
@@ -109,6 +111,18 @@ export function FormattingButtons({ composer, actionStates }: FormattingButtonsP
onClick={() => composer.strikeThrough()}
icon={}
/>
+
-
{_t("Sessions")}
diff --git a/src/events/EventTileFactory.tsx b/src/events/EventTileFactory.tsx
index f3cddcbb4c..1d30416f0f 100644
--- a/src/events/EventTileFactory.tsx
+++ b/src/events/EventTileFactory.tsx
@@ -17,7 +17,8 @@ limitations under the License.
import React from "react";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { EventType, MsgType, RelationType } from "matrix-js-sdk/src/@types/event";
-import { M_POLL_START, Optional } from "matrix-events-sdk";
+import { Optional } from "matrix-events-sdk";
+import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { MatrixClient } from "matrix-js-sdk/src/client";
import { GroupCallIntent } from "matrix-js-sdk/src/webrtc/groupCall";
diff --git a/src/events/forward/getForwardableEvent.ts b/src/events/forward/getForwardableEvent.ts
index 7d1782d7ae..2ceaedc108 100644
--- a/src/events/forward/getForwardableEvent.ts
+++ b/src/events/forward/getForwardableEvent.ts
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import { M_POLL_START } from "matrix-events-sdk";
+import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon";
import { MatrixEvent, MatrixClient } from "matrix-js-sdk/src/matrix";
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index c502cb8f40..54272b871c 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -2135,6 +2135,8 @@
"Stop recording": "Stop recording",
"Italic": "Italic",
"Underline": "Underline",
+ "Bulleted list": "Bulleted list",
+ "Numbered list": "Numbered list",
"Code": "Code",
"Link": "Link",
"Edit link": "Edit link",
@@ -3450,6 +3452,7 @@
"User menu": "User menu",
"Could not load user profile": "Could not load user profile",
"Decrypted event source": "Decrypted event source",
+ "Decrypted source unavailable": "Decrypted source unavailable",
"Original event source": "Original event source",
"Event ID: %(eventId)s": "Event ID: %(eventId)s",
"Thread root ID: %(threadRootId)s": "Thread root ID: %(threadRootId)s",
diff --git a/src/stores/room-list/MessagePreviewStore.ts b/src/stores/room-list/MessagePreviewStore.ts
index cd8ebb6a84..75469ebb0a 100644
--- a/src/stores/room-list/MessagePreviewStore.ts
+++ b/src/stores/room-list/MessagePreviewStore.ts
@@ -17,7 +17,7 @@ limitations under the License.
import { Room } from "matrix-js-sdk/src/models/room";
import { isNullOrUndefined } from "matrix-js-sdk/src/utils";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
-import { M_POLL_START } from "matrix-events-sdk";
+import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { ActionPayload } from "../../dispatcher/payloads";
import { AsyncStoreWithClient } from "../AsyncStoreWithClient";
diff --git a/src/stores/room-list/previews/PollStartEventPreview.ts b/src/stores/room-list/previews/PollStartEventPreview.ts
index c4c85ca82c..404a808989 100644
--- a/src/stores/room-list/previews/PollStartEventPreview.ts
+++ b/src/stores/room-list/previews/PollStartEventPreview.ts
@@ -15,7 +15,9 @@ limitations under the License.
*/
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
-import { InvalidEventError, M_POLL_START_EVENT_CONTENT, PollStartEvent } from "matrix-events-sdk";
+import { PollStartEventContent } from "matrix-js-sdk/src/@types/polls";
+import { InvalidEventError } from "matrix-js-sdk/src/extensible_events_v1/InvalidEventError";
+import { PollStartEvent } from "matrix-js-sdk/src/extensible_events_v1/PollStartEvent";
import { IPreview } from "./IPreview";
import { TagID } from "../models";
@@ -43,7 +45,7 @@ export class PollStartEventPreview implements IPreview {
try {
const poll = new PollStartEvent({
type: event.getType(),
- content: eventContent as M_POLL_START_EVENT_CONTENT,
+ content: eventContent as PollStartEventContent,
});
let question = poll.question.text.trim();
diff --git a/src/utils/EventRenderingUtils.ts b/src/utils/EventRenderingUtils.ts
index ad8061973b..3acd95e48a 100644
--- a/src/utils/EventRenderingUtils.ts
+++ b/src/utils/EventRenderingUtils.ts
@@ -16,7 +16,7 @@ limitations under the License.
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { EventType, MsgType } from "matrix-js-sdk/src/@types/event";
-import { M_POLL_START } from "matrix-events-sdk";
+import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon";
import { IContent } from "matrix-js-sdk/src/matrix";
diff --git a/src/utils/EventUtils.ts b/src/utils/EventUtils.ts
index 2459a9f745..e80ffb83e2 100644
--- a/src/utils/EventUtils.ts
+++ b/src/utils/EventUtils.ts
@@ -18,7 +18,7 @@ import { EventStatus, MatrixEvent } from "matrix-js-sdk/src/models/event";
import { EventType, EVENT_VISIBILITY_CHANGE_TYPE, MsgType, RelationType } from "matrix-js-sdk/src/@types/event";
import { MatrixClient } from "matrix-js-sdk/src/client";
import { logger } from "matrix-js-sdk/src/logger";
-import { M_POLL_START } from "matrix-events-sdk";
+import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { M_LOCATION } from "matrix-js-sdk/src/@types/location";
import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon";
import { THREAD_RELATION_TYPE } from "matrix-js-sdk/src/models/thread";
diff --git a/src/utils/PinningUtils.ts b/src/utils/PinningUtils.ts
index 5bc1901db0..8e146e9876 100644
--- a/src/utils/PinningUtils.ts
+++ b/src/utils/PinningUtils.ts
@@ -16,7 +16,7 @@ limitations under the License.
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { EventType } from "matrix-js-sdk/src/@types/event";
-import { M_POLL_START } from "matrix-events-sdk";
+import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
export default class PinningUtils {
/**
diff --git a/test/components/structures/ViewSource-test.tsx b/test/components/structures/ViewSource-test.tsx
new file mode 100644
index 0000000000..a4bc8b1eca
--- /dev/null
+++ b/test/components/structures/ViewSource-test.tsx
@@ -0,0 +1,59 @@
+/*
+Copyright 2023 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { render } from "@testing-library/react";
+import { EventType, MatrixEvent } from "matrix-js-sdk/src/matrix";
+import React from "react";
+
+import ViewSource from "../../../src/components/structures/ViewSource";
+import { mkEvent, stubClient } from "../../test-utils/test-utils";
+
+describe("ThreadView", () => {
+ const ROOM_ID = "!roomId:example.org";
+ const SENDER = "@alice:example.org";
+
+ let messageEvent: MatrixEvent;
+
+ const redactionEvent = mkEvent({
+ user: SENDER,
+ event: true,
+ type: EventType.RoomRedaction,
+ content: {},
+ });
+
+ beforeEach(() => {
+ messageEvent = new MatrixEvent({
+ type: EventType.RoomMessageEncrypted,
+ room_id: ROOM_ID,
+ sender: SENDER,
+ content: {},
+ state_key: undefined,
+ });
+ messageEvent.makeRedacted(redactionEvent);
+ });
+
+ beforeEach(stubClient);
+
+ // See https://github.com/vector-im/element-web/issues/24165
+ it("doesn't error when viewing redacted encrypted messages", () => {
+ // Sanity checks
+ expect(messageEvent.isEncrypted()).toBeTruthy();
+ // @ts-ignore clearEvent is private, but it's being used directly
+ expect(messageEvent.clearEvent).toBe(undefined);
+
+ expect(() => render( {}} />)).not.toThrow();
+ });
+});
diff --git a/test/components/views/context_menus/MessageContextMenu-test.tsx b/test/components/views/context_menus/MessageContextMenu-test.tsx
index a0ad320c5b..91ee949879 100644
--- a/test/components/views/context_menus/MessageContextMenu-test.tsx
+++ b/test/components/views/context_menus/MessageContextMenu-test.tsx
@@ -26,7 +26,8 @@ import {
getBeaconInfoIdentifier,
EventType,
} from "matrix-js-sdk/src/matrix";
-import { M_POLL_KIND_DISCLOSED, PollStartEvent } from "matrix-events-sdk";
+import { M_POLL_KIND_DISCLOSED } from "matrix-js-sdk/src/@types/polls";
+import { PollStartEvent } from "matrix-js-sdk/src/extensible_events_v1/PollStartEvent";
import { FeatureSupport, Thread } from "matrix-js-sdk/src/models/thread";
import { mocked } from "jest-mock";
import { act } from "@testing-library/react";
diff --git a/test/components/views/dialogs/ForwardDialog-test.tsx b/test/components/views/dialogs/ForwardDialog-test.tsx
index 9e534a6c88..d997450522 100644
--- a/test/components/views/dialogs/ForwardDialog-test.tsx
+++ b/test/components/views/dialogs/ForwardDialog-test.tsx
@@ -18,7 +18,7 @@ import React from "react";
import { act } from "react-dom/test-utils";
import { MatrixEvent, EventType } from "matrix-js-sdk/src/matrix";
import { LocationAssetType, M_ASSET, M_LOCATION, M_TIMESTAMP } from "matrix-js-sdk/src/@types/location";
-import { TEXT_NODE_TYPE } from "matrix-js-sdk/src/@types/extensible_events";
+import { M_TEXT } from "matrix-js-sdk/src/@types/extensible_events";
import { fireEvent, getByTestId, render, RenderResult, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
@@ -248,7 +248,7 @@ describe("ForwardDialog", () => {
const expectedStrippedContent = {
...modernLocationEvent.getContent(),
body: text,
- [TEXT_NODE_TYPE.name]: text,
+ [M_TEXT.name]: text,
[M_TIMESTAMP.name]: now,
[M_ASSET.name]: { type: LocationAssetType.Pin },
[M_LOCATION.name]: {
@@ -276,7 +276,7 @@ describe("ForwardDialog", () => {
const expectedStrippedContent = {
...modernLocationEvent.getContent(),
body: text,
- [TEXT_NODE_TYPE.name]: text,
+ [M_TEXT.name]: text,
[M_ASSET.name]: { type: LocationAssetType.Pin },
[M_LOCATION.name]: {
uri: geoUri,
@@ -297,7 +297,7 @@ describe("ForwardDialog", () => {
const expectedContent = {
msgtype: "m.location",
body: text,
- [TEXT_NODE_TYPE.name]: text,
+ [M_TEXT.name]: text,
[M_ASSET.name]: { type: LocationAssetType.Pin },
[M_LOCATION.name]: {
uri: geoUri,
diff --git a/test/components/views/elements/PollCreateDialog-test.tsx b/test/components/views/elements/PollCreateDialog-test.tsx
index fdfb4b50e7..2a0087b355 100644
--- a/test/components/views/elements/PollCreateDialog-test.tsx
+++ b/test/components/views/elements/PollCreateDialog-test.tsx
@@ -18,14 +18,10 @@ import React from "react";
// eslint-disable-next-line deprecate/import
import { mount, ReactWrapper } from "enzyme";
import { Room } from "matrix-js-sdk/src/models/room";
-import {
- M_POLL_KIND_DISCLOSED,
- M_POLL_KIND_UNDISCLOSED,
- M_POLL_START,
- M_TEXT,
- PollStartEvent,
-} from "matrix-events-sdk";
+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 { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
diff --git a/test/components/views/elements/SyntaxHighlight-test.tsx b/test/components/views/elements/SyntaxHighlight-test.tsx
new file mode 100644
index 0000000000..bdd3e50cf0
--- /dev/null
+++ b/test/components/views/elements/SyntaxHighlight-test.tsx
@@ -0,0 +1,38 @@
+/* eslint @typescript-eslint/no-unused-vars: ["error", { "varsIgnorePattern": "^_" }] */
+/*
+Copyright 2023 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { render } from "@testing-library/react";
+import hljs, { type HighlightOptions } from "highlight.js";
+import React from "react";
+
+import SyntaxHighlight from "../../../../src/components/views/elements/SyntaxHighlight";
+
+describe("", () => {
+ it("renders", () => {
+ const { container } = render(console.log("Hello, World!"););
+ expect(container).toMatchSnapshot();
+ });
+
+ it.each(["json", "javascript", "css"])("uses the provided language", (lang) => {
+ const mock = jest.spyOn(hljs, "highlight");
+
+ render(// Hello, World);
+
+ const [_lang, opts] = mock.mock.lastCall!;
+ expect((opts as HighlightOptions)["language"]).toBe(lang);
+ });
+});
diff --git a/test/components/views/elements/__snapshots__/SyntaxHighlight-test.tsx.snap b/test/components/views/elements/__snapshots__/SyntaxHighlight-test.tsx.snap
new file mode 100644
index 0000000000..e7ad9c057b
--- /dev/null
+++ b/test/components/views/elements/__snapshots__/SyntaxHighlight-test.tsx.snap
@@ -0,0 +1,30 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` renders 1`] = `
+
+
+
+
+ console
+
+ .
+
+ log
+
+ (
+
+ "Hello, World!"
+
+ );
+
+
+
+`;
diff --git a/test/components/views/messages/MPollBody-test.tsx b/test/components/views/messages/MPollBody-test.tsx
index c3907a61b9..a6f9b5e11c 100644
--- a/test/components/views/messages/MPollBody-test.tsx
+++ b/test/components/views/messages/MPollBody-test.tsx
@@ -15,8 +15,7 @@ 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 { MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
import { Relations } from "matrix-js-sdk/src/models/relations";
import { RelatedRelations } from "matrix-js-sdk/src/models/related-relations";
@@ -26,10 +25,10 @@ import {
M_POLL_KIND_UNDISCLOSED,
M_POLL_RESPONSE,
M_POLL_START,
- M_POLL_START_EVENT_CONTENT,
- M_TEXT,
- POLL_ANSWER,
-} from "matrix-events-sdk";
+ PollStartEventContent,
+ PollAnswer,
+} from "matrix-js-sdk/src/@types/polls";
+import { M_TEXT } from "matrix-js-sdk/src/@types/extensible_events";
import { MockedObject } from "jest-mock";
import {
@@ -44,6 +43,8 @@ import { IBodyProps } from "../../../../src/components/views/messages/IBodyProps
import { getMockClientWithEventEmitter } from "../../../test-utils";
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
import MPollBody from "../../../../src/components/views/messages/MPollBody";
+import { RoomPermalinkCreator } from "../../../../src/utils/permalinks/Permalinks";
+import { MediaEventHelper } from "../../../../src/utils/MediaEventHelper";
const CHECKED = "mx_MPollBody_option_checked";
@@ -85,13 +86,13 @@ describe("MPollBody", () => {
new RelatedRelations([newEndRelations([])]),
),
).toEqual([
- new UserVote(ev1.getTs(), ev1.getSender(), ev1.getContent()[M_POLL_RESPONSE.name].answers),
+ new UserVote(ev1.getTs(), ev1.getSender()!, ev1.getContent()[M_POLL_RESPONSE.name].answers),
new UserVote(
badEvent.getTs(),
- badEvent.getSender(),
+ badEvent.getSender()!,
[], // should be spoiled
),
- new UserVote(ev2.getTs(), ev2.getSender(), ev2.getContent()[M_POLL_RESPONSE.name].answers),
+ new UserVote(ev2.getTs(), ev2.getSender()!, ev2.getContent()[M_POLL_RESPONSE.name].answers),
]);
});
@@ -146,14 +147,14 @@ describe("MPollBody", () => {
});
it("renders no votes if none were made", () => {
- const votes = [];
- const body = newMPollBody(votes);
- expect(votesCount(body, "pizza")).toBe("");
- expect(votesCount(body, "poutine")).toBe("");
- expect(votesCount(body, "italian")).toBe("");
- expect(votesCount(body, "wings")).toBe("");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("No votes cast");
- expect(body.find("h2").html()).toEqual("What should we order for the party?
");
+ const votes: MatrixEvent[] = [];
+ const renderResult = newMPollBody(votes);
+ expect(votesCount(renderResult, "pizza")).toBe("");
+ expect(votesCount(renderResult, "poutine")).toBe("");
+ expect(votesCount(renderResult, "italian")).toBe("");
+ expect(votesCount(renderResult, "wings")).toBe("");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("No votes cast");
+ expect(renderResult.getByText("What should we order for the party?")).toBeTruthy();
});
it("finds votes from multiple people", () => {
@@ -163,12 +164,12 @@ describe("MPollBody", () => {
responseEvent("@catrd:example.com", "poutine"),
responseEvent("@dune2:example.com", "wings"),
];
- const body = newMPollBody(votes);
- expect(votesCount(body, "pizza")).toBe("2 votes");
- expect(votesCount(body, "poutine")).toBe("1 vote");
- expect(votesCount(body, "italian")).toBe("0 votes");
- expect(votesCount(body, "wings")).toBe("1 vote");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Based on 4 votes");
+ const renderResult = newMPollBody(votes);
+ expect(votesCount(renderResult, "pizza")).toBe("2 votes");
+ expect(votesCount(renderResult, "poutine")).toBe("1 vote");
+ expect(votesCount(renderResult, "italian")).toBe("0 votes");
+ expect(votesCount(renderResult, "wings")).toBe("1 vote");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Based on 4 votes");
});
it("ignores end poll events from unauthorised users", () => {
@@ -179,15 +180,15 @@ describe("MPollBody", () => {
responseEvent("@dune2:example.com", "wings"),
];
const ends = [endEvent("@notallowed:example.com", 12)];
- const body = newMPollBody(votes, ends);
+ const renderResult = newMPollBody(votes, ends);
// Even though an end event was sent, we render the poll as unfinished
// because this person is not allowed to send these events
- expect(votesCount(body, "pizza")).toBe("2 votes");
- expect(votesCount(body, "poutine")).toBe("1 vote");
- expect(votesCount(body, "italian")).toBe("0 votes");
- expect(votesCount(body, "wings")).toBe("1 vote");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Based on 4 votes");
+ expect(votesCount(renderResult, "pizza")).toBe("2 votes");
+ expect(votesCount(renderResult, "poutine")).toBe("1 vote");
+ expect(votesCount(renderResult, "italian")).toBe("0 votes");
+ expect(votesCount(renderResult, "wings")).toBe("1 vote");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Based on 4 votes");
});
it("hides scores if I have not voted", () => {
@@ -197,22 +198,22 @@ describe("MPollBody", () => {
responseEvent("@catrd:example.com", "poutine"),
responseEvent("@dune2:example.com", "wings"),
];
- const body = newMPollBody(votes);
- expect(votesCount(body, "pizza")).toBe("");
- expect(votesCount(body, "poutine")).toBe("");
- expect(votesCount(body, "italian")).toBe("");
- expect(votesCount(body, "wings")).toBe("");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("4 votes cast. Vote to see the results");
+ const renderResult = newMPollBody(votes);
+ expect(votesCount(renderResult, "pizza")).toBe("");
+ expect(votesCount(renderResult, "poutine")).toBe("");
+ expect(votesCount(renderResult, "italian")).toBe("");
+ expect(votesCount(renderResult, "wings")).toBe("");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("4 votes cast. Vote to see the results");
});
it("hides a single vote if I have not voted", () => {
const votes = [responseEvent("@alice:example.com", "pizza")];
- const body = newMPollBody(votes);
- expect(votesCount(body, "pizza")).toBe("");
- expect(votesCount(body, "poutine")).toBe("");
- expect(votesCount(body, "italian")).toBe("");
- expect(votesCount(body, "wings")).toBe("");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("1 vote cast. Vote to see the results");
+ const renderResult = newMPollBody(votes);
+ expect(votesCount(renderResult, "pizza")).toBe("");
+ expect(votesCount(renderResult, "poutine")).toBe("");
+ expect(votesCount(renderResult, "italian")).toBe("");
+ expect(votesCount(renderResult, "wings")).toBe("");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("1 vote cast. Vote to see the results");
});
it("takes someone's most recent vote if they voted several times", () => {
@@ -223,12 +224,12 @@ describe("MPollBody", () => {
responseEvent("@qbert:example.com", "poutine", 16), // latest qbert
responseEvent("@qbert:example.com", "wings", 15),
];
- const body = newMPollBody(votes);
- expect(votesCount(body, "pizza")).toBe("0 votes");
- expect(votesCount(body, "poutine")).toBe("1 vote");
- expect(votesCount(body, "italian")).toBe("0 votes");
- expect(votesCount(body, "wings")).toBe("1 vote");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Based on 2 votes");
+ const renderResult = newMPollBody(votes);
+ expect(votesCount(renderResult, "pizza")).toBe("0 votes");
+ expect(votesCount(renderResult, "poutine")).toBe("1 vote");
+ expect(votesCount(renderResult, "italian")).toBe("0 votes");
+ expect(votesCount(renderResult, "wings")).toBe("1 vote");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Based on 2 votes");
});
it("uses my local vote", () => {
@@ -238,18 +239,18 @@ describe("MPollBody", () => {
responseEvent("@fg:example.com", "pizza", 15),
responseEvent("@hi:example.com", "pizza", 15),
];
- const body = newMPollBody(votes);
+ const renderResult = newMPollBody(votes);
// When I vote for Italian
- clickRadio(body, "italian");
+ clickOption(renderResult, "italian");
// My vote is counted
- expect(votesCount(body, "pizza")).toBe("3 votes");
- expect(votesCount(body, "poutine")).toBe("0 votes");
- expect(votesCount(body, "italian")).toBe("1 vote");
- expect(votesCount(body, "wings")).toBe("0 votes");
+ expect(votesCount(renderResult, "pizza")).toBe("3 votes");
+ expect(votesCount(renderResult, "poutine")).toBe("0 votes");
+ expect(votesCount(renderResult, "italian")).toBe("1 vote");
+ expect(votesCount(renderResult, "wings")).toBe("0 votes");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Based on 4 votes");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Based on 4 votes");
});
it("overrides my other votes with my local vote", () => {
@@ -260,53 +261,66 @@ describe("MPollBody", () => {
responseEvent("@me:example.com", "italian", 14),
responseEvent("@nf:example.com", "italian", 15),
];
- const body = newMPollBody(votes);
+ const renderResult = newMPollBody(votes);
// When I click Wings
- clickRadio(body, "wings");
+ clickOption(renderResult, "wings");
// Then my vote is counted for Wings, and not for Italian
- expect(votesCount(body, "pizza")).toBe("0 votes");
- expect(votesCount(body, "poutine")).toBe("0 votes");
- expect(votesCount(body, "italian")).toBe("1 vote");
- expect(votesCount(body, "wings")).toBe("1 vote");
+ expect(votesCount(renderResult, "pizza")).toBe("0 votes");
+ expect(votesCount(renderResult, "poutine")).toBe("0 votes");
+ expect(votesCount(renderResult, "italian")).toBe("1 vote");
+ expect(votesCount(renderResult, "wings")).toBe("1 vote");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Based on 2 votes");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Based on 2 votes");
// And my vote is highlighted
- expect(voteButton(body, "wings").hasClass(CHECKED)).toBe(true);
- expect(voteButton(body, "italian").hasClass(CHECKED)).toBe(false);
+ expect(voteButton(renderResult, "wings").className.includes(CHECKED)).toBe(true);
+ expect(voteButton(renderResult, "italian").className.includes(CHECKED)).toBe(false);
});
it("cancels my local vote if another comes in", () => {
// Given I voted locally
const votes = [responseEvent("@me:example.com", "pizza", 100)];
- const body = newMPollBody(votes);
- const props: IBodyProps = body.instance().props as IBodyProps;
+ const mxEvent = new MatrixEvent({
+ type: M_POLL_START.name,
+ event_id: "$mypoll",
+ room_id: "#myroom:example.com",
+ content: newPollStart(undefined, undefined, true),
+ });
+ const props = getMPollBodyPropsFromEvent(mxEvent, votes);
+ const renderResult = renderMPollBodyWithWrapper(props);
const voteRelations = props!.getRelationsForEvent!("$mypoll", "m.reference", M_POLL_RESPONSE.name);
expect(voteRelations).toBeDefined();
- clickRadio(body, "pizza");
+ clickOption(renderResult, "pizza");
// When a new vote from me comes in
voteRelations!.addEvent(responseEvent("@me:example.com", "wings", 101));
// Then the new vote is counted, not the old one
- expect(votesCount(body, "pizza")).toBe("0 votes");
- expect(votesCount(body, "poutine")).toBe("0 votes");
- expect(votesCount(body, "italian")).toBe("0 votes");
- expect(votesCount(body, "wings")).toBe("1 vote");
+ expect(votesCount(renderResult, "pizza")).toBe("0 votes");
+ expect(votesCount(renderResult, "poutine")).toBe("0 votes");
+ expect(votesCount(renderResult, "italian")).toBe("0 votes");
+ expect(votesCount(renderResult, "wings")).toBe("1 vote");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Based on 1 vote");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Based on 1 vote");
});
it("doesn't cancel my local vote if someone else votes", () => {
// Given I voted locally
const votes = [responseEvent("@me:example.com", "pizza")];
- const body = newMPollBody(votes);
- const props: IBodyProps = body.instance().props as IBodyProps;
+ const mxEvent = new MatrixEvent({
+ type: M_POLL_START.name,
+ event_id: "$mypoll",
+ room_id: "#myroom:example.com",
+ content: newPollStart(undefined, undefined, true),
+ });
+ const props = getMPollBodyPropsFromEvent(mxEvent, votes);
+ const renderResult = renderMPollBodyWithWrapper(props);
+
const voteRelations = props!.getRelationsForEvent!("$mypoll", "m.reference", M_POLL_RESPONSE.name);
expect(voteRelations).toBeDefined();
- clickRadio(body, "pizza");
+ clickOption(renderResult, "pizza");
// When a new vote from someone else comes in
voteRelations!.addEvent(responseEvent("@xx:example.com", "wings", 101));
@@ -315,39 +329,39 @@ describe("MPollBody", () => {
// NOTE: the new event does not affect the counts for other people -
// that is handled through the Relations, not by listening to
// these timeline events.
- expect(votesCount(body, "pizza")).toBe("1 vote");
- expect(votesCount(body, "poutine")).toBe("0 votes");
- expect(votesCount(body, "italian")).toBe("0 votes");
- expect(votesCount(body, "wings")).toBe("1 vote");
+ expect(votesCount(renderResult, "pizza")).toBe("1 vote");
+ expect(votesCount(renderResult, "poutine")).toBe("0 votes");
+ expect(votesCount(renderResult, "italian")).toBe("0 votes");
+ expect(votesCount(renderResult, "wings")).toBe("1 vote");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Based on 2 votes");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Based on 2 votes");
// And my vote is highlighted
- expect(voteButton(body, "pizza").hasClass(CHECKED)).toBe(true);
- expect(voteButton(body, "wings").hasClass(CHECKED)).toBe(false);
+ expect(voteButton(renderResult, "pizza").className.includes(CHECKED)).toBe(true);
+ expect(voteButton(renderResult, "wings").className.includes(CHECKED)).toBe(false);
});
it("highlights my vote even if I did it on another device", () => {
// Given I voted italian
const votes = [responseEvent("@me:example.com", "italian"), responseEvent("@nf:example.com", "wings")];
- const body = newMPollBody(votes);
+ const renderResult = newMPollBody(votes);
// But I didn't click anything locally
// Then my vote is highlighted, and others are not
- expect(voteButton(body, "italian").hasClass(CHECKED)).toBe(true);
- expect(voteButton(body, "wings").hasClass(CHECKED)).toBe(false);
+ expect(voteButton(renderResult, "italian").className.includes(CHECKED)).toBe(true);
+ expect(voteButton(renderResult, "wings").className.includes(CHECKED)).toBe(false);
});
it("ignores extra answers", () => {
// When cb votes for 2 things, we consider the first only
const votes = [responseEvent("@cb:example.com", ["pizza", "wings"]), responseEvent("@me:example.com", "wings")];
- const body = newMPollBody(votes);
- expect(votesCount(body, "pizza")).toBe("1 vote");
- expect(votesCount(body, "poutine")).toBe("0 votes");
- expect(votesCount(body, "italian")).toBe("0 votes");
- expect(votesCount(body, "wings")).toBe("1 vote");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Based on 2 votes");
+ const renderResult = newMPollBody(votes);
+ expect(votesCount(renderResult, "pizza")).toBe("1 vote");
+ expect(votesCount(renderResult, "poutine")).toBe("0 votes");
+ expect(votesCount(renderResult, "italian")).toBe("0 votes");
+ expect(votesCount(renderResult, "wings")).toBe("1 vote");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Based on 2 votes");
});
it("allows un-voting by passing an empty vote", () => {
@@ -356,12 +370,12 @@ describe("MPollBody", () => {
responseEvent("@nc:example.com", [], 13),
responseEvent("@me:example.com", "italian"),
];
- const body = newMPollBody(votes);
- expect(votesCount(body, "pizza")).toBe("0 votes");
- expect(votesCount(body, "poutine")).toBe("0 votes");
- expect(votesCount(body, "italian")).toBe("1 vote");
- expect(votesCount(body, "wings")).toBe("0 votes");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Based on 1 vote");
+ const renderResult = newMPollBody(votes);
+ expect(votesCount(renderResult, "pizza")).toBe("0 votes");
+ expect(votesCount(renderResult, "poutine")).toBe("0 votes");
+ expect(votesCount(renderResult, "italian")).toBe("1 vote");
+ expect(votesCount(renderResult, "wings")).toBe("0 votes");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Based on 1 vote");
});
it("allows re-voting after un-voting", () => {
@@ -371,12 +385,12 @@ describe("MPollBody", () => {
responseEvent("@op:example.com", "italian", 14),
responseEvent("@me:example.com", "italian"),
];
- const body = newMPollBody(votes);
- expect(votesCount(body, "pizza")).toBe("0 votes");
- expect(votesCount(body, "poutine")).toBe("0 votes");
- expect(votesCount(body, "italian")).toBe("2 votes");
- expect(votesCount(body, "wings")).toBe("0 votes");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Based on 2 votes");
+ const renderResult = newMPollBody(votes);
+ expect(votesCount(renderResult, "pizza")).toBe("0 votes");
+ expect(votesCount(renderResult, "poutine")).toBe("0 votes");
+ expect(votesCount(renderResult, "italian")).toBe("2 votes");
+ expect(votesCount(renderResult, "wings")).toBe("0 votes");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Based on 2 votes");
});
it("treats any invalid answer as a spoiled ballot", () => {
@@ -389,12 +403,12 @@ describe("MPollBody", () => {
responseEvent("@uy:example.com", "italian", 14),
responseEvent("@uy:example.com", "doesntexist", 15),
];
- const body = newMPollBody(votes);
- expect(votesCount(body, "pizza")).toBe("0 votes");
- expect(votesCount(body, "poutine")).toBe("0 votes");
- expect(votesCount(body, "italian")).toBe("0 votes");
- expect(votesCount(body, "wings")).toBe("0 votes");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Based on 0 votes");
+ const renderResult = newMPollBody(votes);
+ expect(votesCount(renderResult, "pizza")).toBe("0 votes");
+ expect(votesCount(renderResult, "poutine")).toBe("0 votes");
+ expect(votesCount(renderResult, "italian")).toBe("0 votes");
+ expect(votesCount(renderResult, "wings")).toBe("0 votes");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Based on 0 votes");
});
it("allows re-voting after a spoiled ballot", () => {
@@ -405,31 +419,31 @@ describe("MPollBody", () => {
responseEvent("@uy:example.com", "doesntexist", 15),
responseEvent("@uy:example.com", "poutine", 16),
];
- const body = newMPollBody(votes);
- expect(body.find('input[type="radio"]')).toHaveLength(4);
- expect(votesCount(body, "pizza")).toBe("0 votes");
- expect(votesCount(body, "poutine")).toBe("1 vote");
- expect(votesCount(body, "italian")).toBe("0 votes");
- expect(votesCount(body, "wings")).toBe("0 votes");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Based on 1 vote");
+ const renderResult = newMPollBody(votes);
+ expect(renderResult.container.querySelectorAll('input[type="radio"]')).toHaveLength(4);
+ expect(votesCount(renderResult, "pizza")).toBe("0 votes");
+ expect(votesCount(renderResult, "poutine")).toBe("1 vote");
+ expect(votesCount(renderResult, "italian")).toBe("0 votes");
+ expect(votesCount(renderResult, "wings")).toBe("0 votes");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Based on 1 vote");
});
it("renders nothing if poll has no answers", () => {
- const answers = [];
- const votes = [];
- const ends = [];
- const body = newMPollBody(votes, ends, answers);
- expect(body.html()).toBeNull();
+ const answers: PollAnswer[] = [];
+ const votes: MatrixEvent[] = [];
+ const ends: MatrixEvent[] = [];
+ const { container } = newMPollBody(votes, ends, answers);
+ expect(container.childElementCount).toEqual(0);
});
it("renders the first 20 answers if 21 were given", () => {
const answers = Array.from(Array(21).keys()).map((i) => {
return { id: `id${i}`, [M_TEXT.name]: `Name ${i}` };
});
- const votes = [];
- const ends = [];
- const body = newMPollBody(votes, ends, answers);
- expect(body.find(".mx_MPollBody_option").length).toBe(20);
+ const votes: MatrixEvent[] = [];
+ const ends: MatrixEvent[] = [];
+ const { container } = newMPollBody(votes, ends, answers);
+ expect(container.querySelectorAll(".mx_MPollBody_option").length).toBe(20);
});
it("hides scores if I voted but the poll is undisclosed", () => {
@@ -440,12 +454,12 @@ describe("MPollBody", () => {
responseEvent("@catrd:example.com", "poutine"),
responseEvent("@dune2:example.com", "wings"),
];
- const body = newMPollBody(votes, [], null, false);
- expect(votesCount(body, "pizza")).toBe("");
- expect(votesCount(body, "poutine")).toBe("");
- expect(votesCount(body, "italian")).toBe("");
- expect(votesCount(body, "wings")).toBe("");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Results will be visible when the poll is ended");
+ const renderResult = newMPollBody(votes, [], undefined, false);
+ expect(votesCount(renderResult, "pizza")).toBe("");
+ expect(votesCount(renderResult, "poutine")).toBe("");
+ expect(votesCount(renderResult, "italian")).toBe("");
+ expect(votesCount(renderResult, "wings")).toBe("");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Results will be visible when the poll is ended");
});
it("highlights my vote if the poll is undisclosed", () => {
@@ -456,13 +470,13 @@ describe("MPollBody", () => {
responseEvent("@catrd:example.com", "poutine"),
responseEvent("@dune2:example.com", "wings"),
];
- const body = newMPollBody(votes, [], null, false);
+ const { container } = newMPollBody(votes, [], undefined, false);
// My vote is marked
- expect(body.find('input[value="pizza"]').prop("checked")).toBeTruthy();
+ expect(container.querySelector('input[value="pizza"]')!).toBeChecked();
// Sanity: other items are not checked
- expect(body.find('input[value="poutine"]').prop("checked")).toBeFalsy();
+ expect(container.querySelector('input[value="poutine"]')!).not.toBeChecked();
});
it("shows scores if the poll is undisclosed but ended", () => {
@@ -474,47 +488,47 @@ describe("MPollBody", () => {
responseEvent("@dune2:example.com", "wings"),
];
const ends = [endEvent("@me:example.com", 12)];
- const body = newMPollBody(votes, ends, null, false);
- expect(endedVotesCount(body, "pizza")).toBe("3 votes");
- expect(endedVotesCount(body, "poutine")).toBe("1 vote");
- expect(endedVotesCount(body, "italian")).toBe("0 votes");
- expect(endedVotesCount(body, "wings")).toBe("1 vote");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Final result based on 5 votes");
+ const renderResult = newMPollBody(votes, ends, undefined, false);
+ expect(endedVotesCount(renderResult, "pizza")).toBe("3 votes");
+ expect(endedVotesCount(renderResult, "poutine")).toBe("1 vote");
+ expect(endedVotesCount(renderResult, "italian")).toBe("0 votes");
+ expect(endedVotesCount(renderResult, "wings")).toBe("1 vote");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Final result based on 5 votes");
});
it("sends a vote event when I choose an option", () => {
- const votes = [];
- const body = newMPollBody(votes);
- clickRadio(body, "wings");
+ const votes: MatrixEvent[] = [];
+ const renderResult = newMPollBody(votes);
+ clickOption(renderResult, "wings");
expect(mockClient.sendEvent).toHaveBeenCalledWith(...expectedResponseEventCall("wings"));
});
it("sends only one vote event when I click several times", () => {
- const votes = [];
- const body = newMPollBody(votes);
- clickRadio(body, "wings");
- clickRadio(body, "wings");
- clickRadio(body, "wings");
- clickRadio(body, "wings");
+ const votes: MatrixEvent[] = [];
+ const renderResult = newMPollBody(votes);
+ clickOption(renderResult, "wings");
+ clickOption(renderResult, "wings");
+ clickOption(renderResult, "wings");
+ clickOption(renderResult, "wings");
expect(mockClient.sendEvent).toHaveBeenCalledWith(...expectedResponseEventCall("wings"));
});
it("sends no vote event when I click what I already chose", () => {
const votes = [responseEvent("@me:example.com", "wings")];
- const body = newMPollBody(votes);
- clickRadio(body, "wings");
- clickRadio(body, "wings");
- clickRadio(body, "wings");
- clickRadio(body, "wings");
+ const renderResult = newMPollBody(votes);
+ clickOption(renderResult, "wings");
+ clickOption(renderResult, "wings");
+ clickOption(renderResult, "wings");
+ clickOption(renderResult, "wings");
expect(mockClient.sendEvent).not.toHaveBeenCalled();
});
it("sends several events when I click different options", () => {
- const votes = [];
- const body = newMPollBody(votes);
- clickRadio(body, "wings");
- clickRadio(body, "italian");
- clickRadio(body, "poutine");
+ const votes: MatrixEvent[] = [];
+ const renderResult = newMPollBody(votes);
+ clickOption(renderResult, "wings");
+ clickOption(renderResult, "italian");
+ clickOption(renderResult, "poutine");
expect(mockClient.sendEvent).toHaveBeenCalledTimes(3);
expect(mockClient.sendEvent).toHaveBeenCalledWith(...expectedResponseEventCall("wings"));
expect(mockClient.sendEvent).toHaveBeenCalledWith(...expectedResponseEventCall("italian"));
@@ -524,10 +538,10 @@ describe("MPollBody", () => {
it("sends no events when I click in an ended poll", () => {
const ends = [endEvent("@me:example.com", 25)];
const votes = [responseEvent("@uy:example.com", "wings", 15), responseEvent("@uy:example.com", "poutine", 15)];
- const body = newMPollBody(votes, ends);
- clickEndedOption(body, "wings");
- clickEndedOption(body, "italian");
- clickEndedOption(body, "poutine");
+ const renderResult = newMPollBody(votes, ends);
+ clickOption(renderResult, "wings");
+ clickOption(renderResult, "italian");
+ clickOption(renderResult, "poutine");
expect(mockClient.sendEvent).not.toHaveBeenCalled();
});
@@ -577,9 +591,9 @@ describe("MPollBody", () => {
it("shows non-radio buttons if the poll is ended", () => {
const events = [endEvent()];
- const body = newMPollBody([], events);
- expect(body.find(".mx_StyledRadioButton")).toHaveLength(0);
- expect(body.find('input[type="radio"]')).toHaveLength(0);
+ const { container } = newMPollBody([], events);
+ expect(container.querySelector(".mx_StyledRadioButton")).not.toBeInTheDocument();
+ expect(container.querySelector('input[type="radio"]')).not.toBeInTheDocument();
});
it("counts votes as normal if the poll is ended", () => {
@@ -591,23 +605,23 @@ describe("MPollBody", () => {
responseEvent("@qbert:example.com", "wings", 15),
];
const ends = [endEvent("@me:example.com", 25)];
- const body = newMPollBody(votes, ends);
- expect(endedVotesCount(body, "pizza")).toBe("0 votes");
- expect(endedVotesCount(body, "poutine")).toBe("1 vote");
- expect(endedVotesCount(body, "italian")).toBe("0 votes");
- expect(endedVotesCount(body, "wings")).toBe("1 vote");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Final result based on 2 votes");
+ const renderResult = newMPollBody(votes, ends);
+ expect(endedVotesCount(renderResult, "pizza")).toBe("0 votes");
+ expect(endedVotesCount(renderResult, "poutine")).toBe("1 vote");
+ expect(endedVotesCount(renderResult, "italian")).toBe("0 votes");
+ expect(endedVotesCount(renderResult, "wings")).toBe("1 vote");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Final result based on 2 votes");
});
it("counts a single vote as normal if the poll is ended", () => {
const votes = [responseEvent("@qbert:example.com", "poutine", 16)];
const ends = [endEvent("@me:example.com", 25)];
- const body = newMPollBody(votes, ends);
- expect(endedVotesCount(body, "pizza")).toBe("0 votes");
- expect(endedVotesCount(body, "poutine")).toBe("1 vote");
- expect(endedVotesCount(body, "italian")).toBe("0 votes");
- expect(endedVotesCount(body, "wings")).toBe("0 votes");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Final result based on 1 vote");
+ const renderResult = newMPollBody(votes, ends);
+ expect(endedVotesCount(renderResult, "pizza")).toBe("0 votes");
+ expect(endedVotesCount(renderResult, "poutine")).toBe("1 vote");
+ expect(endedVotesCount(renderResult, "italian")).toBe("0 votes");
+ expect(endedVotesCount(renderResult, "wings")).toBe("0 votes");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Final result based on 1 vote");
});
it("shows ended vote counts of different numbers", () => {
@@ -619,15 +633,15 @@ describe("MPollBody", () => {
responseEvent("@hi:example.com", "pizza", 15),
];
const ends = [endEvent("@me:example.com", 25)];
- const body = newMPollBody(votes, ends);
+ const renderResult = newMPollBody(votes, ends);
- expect(body.find(".mx_StyledRadioButton")).toHaveLength(0);
- expect(body.find('input[type="radio"]')).toHaveLength(0);
- expect(endedVotesCount(body, "pizza")).toBe("2 votes");
- expect(endedVotesCount(body, "poutine")).toBe("0 votes");
- expect(endedVotesCount(body, "italian")).toBe("0 votes");
- expect(endedVotesCount(body, "wings")).toBe("3 votes");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Final result based on 5 votes");
+ expect(renderResult.container.querySelectorAll(".mx_StyledRadioButton")).toHaveLength(0);
+ expect(renderResult.container.querySelectorAll('input[type="radio"]')).toHaveLength(0);
+ expect(endedVotesCount(renderResult, "pizza")).toBe("2 votes");
+ expect(endedVotesCount(renderResult, "poutine")).toBe("0 votes");
+ expect(endedVotesCount(renderResult, "italian")).toBe("0 votes");
+ expect(endedVotesCount(renderResult, "wings")).toBe("3 votes");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Final result based on 5 votes");
});
it("ignores votes that arrived after poll ended", () => {
@@ -641,13 +655,13 @@ describe("MPollBody", () => {
responseEvent("@ld:example.com", "pizza", 15),
];
const ends = [endEvent("@me:example.com", 25)];
- const body = newMPollBody(votes, ends);
+ const renderResult = newMPollBody(votes, ends);
- expect(endedVotesCount(body, "pizza")).toBe("2 votes");
- expect(endedVotesCount(body, "poutine")).toBe("0 votes");
- expect(endedVotesCount(body, "italian")).toBe("0 votes");
- expect(endedVotesCount(body, "wings")).toBe("3 votes");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Final result based on 5 votes");
+ expect(endedVotesCount(renderResult, "pizza")).toBe("2 votes");
+ expect(endedVotesCount(renderResult, "poutine")).toBe("0 votes");
+ expect(endedVotesCount(renderResult, "italian")).toBe("0 votes");
+ expect(endedVotesCount(renderResult, "wings")).toBe("3 votes");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Final result based on 5 votes");
});
it("counts votes that arrived after an unauthorised poll end event", () => {
@@ -664,13 +678,13 @@ describe("MPollBody", () => {
endEvent("@unauthorised:example.com", 5), // Should be ignored
endEvent("@me:example.com", 25),
];
- const body = newMPollBody(votes, ends);
+ const renderResult = newMPollBody(votes, ends);
- expect(endedVotesCount(body, "pizza")).toBe("2 votes");
- expect(endedVotesCount(body, "poutine")).toBe("0 votes");
- expect(endedVotesCount(body, "italian")).toBe("0 votes");
- expect(endedVotesCount(body, "wings")).toBe("3 votes");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Final result based on 5 votes");
+ expect(endedVotesCount(renderResult, "pizza")).toBe("2 votes");
+ expect(endedVotesCount(renderResult, "poutine")).toBe("0 votes");
+ expect(endedVotesCount(renderResult, "italian")).toBe("0 votes");
+ expect(endedVotesCount(renderResult, "wings")).toBe("3 votes");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Final result based on 5 votes");
});
it("ignores votes that arrived after the first end poll event", () => {
@@ -691,13 +705,13 @@ describe("MPollBody", () => {
endEvent("@me:example.com", 25),
endEvent("@me:example.com", 75),
];
- const body = newMPollBody(votes, ends);
+ const renderResult = newMPollBody(votes, ends);
- expect(endedVotesCount(body, "pizza")).toBe("2 votes");
- expect(endedVotesCount(body, "poutine")).toBe("0 votes");
- expect(endedVotesCount(body, "italian")).toBe("0 votes");
- expect(endedVotesCount(body, "wings")).toBe("3 votes");
- expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Final result based on 5 votes");
+ expect(endedVotesCount(renderResult, "pizza")).toBe("2 votes");
+ expect(endedVotesCount(renderResult, "poutine")).toBe("0 votes");
+ expect(endedVotesCount(renderResult, "italian")).toBe("0 votes");
+ expect(endedVotesCount(renderResult, "wings")).toBe("3 votes");
+ expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Final result based on 5 votes");
});
it("highlights the winning vote in an ended poll", () => {
@@ -708,15 +722,15 @@ describe("MPollBody", () => {
responseEvent("@xy:example.com", "wings", 15),
];
const ends = [endEvent("@me:example.com", 25)];
- const body = newMPollBody(votes, ends);
+ const renderResult = newMPollBody(votes, ends);
// Then the winner is highlighted
- expect(endedVoteChecked(body, "wings")).toBe(true);
- expect(endedVoteChecked(body, "pizza")).toBe(false);
+ expect(endedVoteChecked(renderResult, "wings")).toBe(true);
+ expect(endedVoteChecked(renderResult, "pizza")).toBe(false);
// Double-check by looking for the endedOptionWinner class
- expect(endedVoteDiv(body, "wings").hasClass("mx_MPollBody_endedOptionWinner")).toBe(true);
- expect(endedVoteDiv(body, "pizza").hasClass("mx_MPollBody_endedOptionWinner")).toBe(false);
+ expect(endedVoteDiv(renderResult, "wings").className.includes("mx_MPollBody_endedOptionWinner")).toBe(true);
+ expect(endedVoteDiv(renderResult, "pizza").className.includes("mx_MPollBody_endedOptionWinner")).toBe(false);
});
it("highlights multiple winning votes", () => {
@@ -726,23 +740,23 @@ describe("MPollBody", () => {
responseEvent("@fg:example.com", "poutine", 15),
];
const ends = [endEvent("@me:example.com", 25)];
- const body = newMPollBody(votes, ends);
+ const renderResult = newMPollBody(votes, ends);
- expect(endedVoteChecked(body, "pizza")).toBe(true);
- expect(endedVoteChecked(body, "wings")).toBe(true);
- expect(endedVoteChecked(body, "poutine")).toBe(true);
- expect(endedVoteChecked(body, "italian")).toBe(false);
- expect(body.find(".mx_MPollBody_option_checked")).toHaveLength(3);
+ expect(endedVoteChecked(renderResult, "pizza")).toBe(true);
+ expect(endedVoteChecked(renderResult, "wings")).toBe(true);
+ expect(endedVoteChecked(renderResult, "poutine")).toBe(true);
+ expect(endedVoteChecked(renderResult, "italian")).toBe(false);
+ expect(renderResult.container.getElementsByClassName("mx_MPollBody_option_checked")).toHaveLength(3);
});
it("highlights nothing if poll has no votes", () => {
const ends = [endEvent("@me:example.com", 25)];
- const body = newMPollBody([], ends);
- expect(body.find(".mx_MPollBody_option_checked")).toHaveLength(0);
+ const renderResult = newMPollBody([], ends);
+ expect(renderResult.container.getElementsByClassName("mx_MPollBody_option_checked")).toHaveLength(0);
});
it("says poll is not ended if there is no end event", () => {
- const ends = [];
+ const ends: MatrixEvent[] = [];
expect(runIsPollEnded(ends)).toBe(false);
});
@@ -810,26 +824,26 @@ describe("MPollBody", () => {
},
});
pollEvent.makeReplaced(replacingEvent);
- const body = newMPollBodyFromEvent(pollEvent, []);
- expect(body.find("h2").html()).toEqual(
- "new question" + ' (edited)' + "
",
+ const { getByTestId, container } = newMPollBodyFromEvent(pollEvent, []);
+ expect(getByTestId("pollQuestion").innerHTML).toEqual(
+ 'new question (edited)',
);
- const inputs = body.find('input[type="radio"]');
+ const inputs = container.querySelectorAll('input[type="radio"]');
expect(inputs).toHaveLength(3);
- expect(inputs.at(0).prop("value")).toEqual("n1");
- expect(inputs.at(1).prop("value")).toEqual("n2");
- expect(inputs.at(2).prop("value")).toEqual("n3");
- const options = body.find(".mx_MPollBody_optionText");
+ expect(inputs[0].getAttribute("value")).toEqual("n1");
+ expect(inputs[1].getAttribute("value")).toEqual("n2");
+ expect(inputs[2].getAttribute("value")).toEqual("n3");
+ const options = container.querySelectorAll(".mx_MPollBody_optionText");
expect(options).toHaveLength(3);
- expect(options.at(0).text()).toEqual("new answer 1");
- expect(options.at(1).text()).toEqual("new answer 2");
- expect(options.at(2).text()).toEqual("new answer 3");
+ expect(options[0].innerHTML).toEqual("new answer 1");
+ expect(options[1].innerHTML).toEqual("new answer 2");
+ expect(options[2].innerHTML).toEqual("new answer 3");
});
it("renders a poll with no votes", () => {
- const votes = [];
- const body = newMPollBody(votes);
- expect(body).toMatchSnapshot();
+ const votes: MatrixEvent[] = [];
+ const { container } = newMPollBody(votes);
+ expect(container).toMatchSnapshot();
});
it("renders a poll with only non-local votes", () => {
@@ -840,8 +854,8 @@ describe("MPollBody", () => {
responseEvent("@me:example.com", "wings", 15),
responseEvent("@qr:example.com", "italian", 16),
];
- const body = newMPollBody(votes);
- expect(body).toMatchSnapshot();
+ const { container } = newMPollBody(votes);
+ expect(container).toMatchSnapshot();
});
it("renders a poll with local, non-local and invalid votes", () => {
@@ -853,9 +867,9 @@ describe("MPollBody", () => {
responseEvent("@e:example.com", "wings", 15),
responseEvent("@me:example.com", "italian", 16),
];
- const body = newMPollBody(votes);
- clickRadio(body, "italian");
- expect(body).toMatchSnapshot();
+ const renderResult = newMPollBody(votes);
+ clickOption(renderResult, "italian");
+ expect(renderResult.container).toMatchSnapshot();
});
it("renders a poll that I have not voted in", () => {
@@ -866,14 +880,14 @@ describe("MPollBody", () => {
responseEvent("@yo:example.com", "wings", 15),
responseEvent("@qr:example.com", "italian", 16),
];
- const body = newMPollBody(votes);
- expect(body).toMatchSnapshot();
+ const { container } = newMPollBody(votes);
+ expect(container).toMatchSnapshot();
});
it("renders a finished poll with no votes", () => {
const ends = [endEvent("@me:example.com", 25)];
- const body = newMPollBody([], ends);
- expect(body).toMatchSnapshot();
+ const { container } = newMPollBody([], ends);
+ expect(container).toMatchSnapshot();
});
it("renders a finished poll", () => {
@@ -885,8 +899,8 @@ describe("MPollBody", () => {
responseEvent("@qr:example.com", "italian", 16),
];
const ends = [endEvent("@me:example.com", 25)];
- const body = newMPollBody(votes, ends);
- expect(body).toMatchSnapshot();
+ const { container } = newMPollBody(votes, ends);
+ expect(container).toMatchSnapshot();
});
it("renders a finished poll with multiple winners", () => {
@@ -899,8 +913,8 @@ describe("MPollBody", () => {
responseEvent("@yh:example.com", "poutine", 14),
];
const ends = [endEvent("@me:example.com", 25)];
- const body = newMPollBody(votes, ends);
- expect(body).toMatchSnapshot();
+ const { container } = newMPollBody(votes, ends);
+ expect(container).toMatchSnapshot();
});
it("renders an undisclosed, unfinished poll", () => {
@@ -912,9 +926,9 @@ describe("MPollBody", () => {
responseEvent("@th:example.com", "poutine", 13),
responseEvent("@yh:example.com", "poutine", 14),
];
- const ends = [];
- const body = newMPollBody(votes, ends, null, false);
- expect(body.html()).toMatchSnapshot();
+ const ends: MatrixEvent[] = [];
+ const { container } = newMPollBody(votes, ends, undefined, false);
+ expect(container).toMatchSnapshot();
});
it("renders an undisclosed, finished poll", () => {
@@ -927,8 +941,8 @@ describe("MPollBody", () => {
responseEvent("@yh:example.com", "poutine", 14),
];
const ends = [endEvent("@me:example.com", 25)];
- const body = newMPollBody(votes, ends, null, false);
- expect(body.html()).toMatchSnapshot();
+ const { container } = newMPollBody(votes, ends, undefined, false);
+ expect(container).toMatchSnapshot();
});
});
@@ -941,7 +955,7 @@ function newEndRelations(relationEvents: Array): Relations {
}
function newRelations(relationEvents: Array, eventType: string): Relations {
- const voteRelations = new Relations("m.reference", eventType, null);
+ const voteRelations = new Relations("m.reference", eventType, mockClient);
for (const ev of relationEvents) {
voteRelations.addEvent(ev);
}
@@ -951,89 +965,93 @@ function newRelations(relationEvents: Array, eventType: string): Re
function newMPollBody(
relationEvents: Array,
endEvents: Array = [],
- answers?: POLL_ANSWER[],
+ answers?: PollAnswer[],
disclosed = true,
-): ReactWrapper {
+): RenderResult {
const mxEvent = new MatrixEvent({
type: M_POLL_START.name,
event_id: "$mypoll",
room_id: "#myroom:example.com",
- content: newPollStart(answers, null, disclosed),
+ content: newPollStart(answers, undefined, disclosed),
});
return newMPollBodyFromEvent(mxEvent, relationEvents, endEvents);
}
+function getMPollBodyPropsFromEvent(
+ mxEvent: MatrixEvent,
+ relationEvents: Array,
+ endEvents: Array = [],
+): IBodyProps {
+ const voteRelations = newVoteRelations(relationEvents);
+ const endRelations = newEndRelations(endEvents);
+
+ const getRelationsForEvent = (eventId: string, relationType: string, eventType: string) => {
+ expect(eventId).toBe("$mypoll");
+ expect(relationType).toBe("m.reference");
+ if (M_POLL_RESPONSE.matches(eventType)) {
+ return voteRelations;
+ } else if (M_POLL_END.matches(eventType)) {
+ return endRelations;
+ } else {
+ fail("Unexpected eventType: " + eventType);
+ }
+ };
+
+ return {
+ mxEvent,
+ getRelationsForEvent,
+ // We don't use any of these props, but they're required.
+ highlightLink: "unused",
+ highlights: [],
+ mediaEventHelper: {} as unknown as MediaEventHelper,
+ onHeightChanged: () => {},
+ onMessageAllowed: () => {},
+ permalinkCreator: {} as unknown as RoomPermalinkCreator,
+ };
+}
+
+function renderMPollBodyWithWrapper(props: IBodyProps): RenderResult {
+ return render(, {
+ wrapper: ({ children }) => (
+ {children}
+ ),
+ });
+}
+
function newMPollBodyFromEvent(
mxEvent: MatrixEvent,
relationEvents: Array,
endEvents: Array = [],
-): ReactWrapper {
- const voteRelations = newVoteRelations(relationEvents);
- const endRelations = newEndRelations(endEvents);
- return mount(
- {
- expect(eventId).toBe("$mypoll");
- expect(relationType).toBe("m.reference");
- if (M_POLL_RESPONSE.matches(eventType)) {
- return voteRelations;
- } else if (M_POLL_END.matches(eventType)) {
- return endRelations;
- } else {
- fail("Unexpected eventType: " + eventType);
- }
- }}
- // We don't use any of these props, but they're required.
- highlightLink="unused"
- highlights={[]}
- mediaEventHelper={null}
- onHeightChanged={() => {}}
- onMessageAllowed={() => {}}
- permalinkCreator={null}
- />,
- {
- wrappingComponent: MatrixClientContext.Provider,
- wrappingComponentProps: {
- value: mockClient,
- },
- },
- );
+): RenderResult {
+ const props = getMPollBodyPropsFromEvent(mxEvent, relationEvents, endEvents);
+ return renderMPollBodyWithWrapper(props);
}
-function clickRadio(wrapper: ReactWrapper, value: string) {
- const div = wrapper.find(`StyledRadioButton[value="${value}"]`);
- expect(div).toHaveLength(1);
- div.simulate("click");
+function clickOption({ getByTestId }: RenderResult, value: string) {
+ fireEvent.click(getByTestId(`pollOption-${value}`));
}
-function clickEndedOption(wrapper: ReactWrapper, value: string) {
- const div = wrapper.find(`div[data-value="${value}"]`);
- expect(div).toHaveLength(1);
- div.simulate("click");
+function voteButton({ getByTestId }: RenderResult, value: string): Element {
+ return getByTestId(`pollOption-${value}`);
}
-function voteButton(wrapper: ReactWrapper, value: string): ReactWrapper {
- return wrapper.find(`div.mx_MPollBody_option`).findWhere((w) => w.key() === value);
+function votesCount({ getByTestId }: RenderResult, value: string): string {
+ return getByTestId(`pollOption-${value}`).querySelector(".mx_MPollBody_optionVoteCount")!.innerHTML;
}
-function votesCount(wrapper: ReactWrapper, value: string): string {
- return wrapper.find(`StyledRadioButton[value="${value}"] .mx_MPollBody_optionVoteCount`).text();
+function endedVoteChecked({ getByTestId }: RenderResult, value: string): boolean {
+ return getByTestId(`pollOption-${value}`).className.includes("mx_MPollBody_option_checked");
}
-function endedVoteChecked(wrapper: ReactWrapper, value: string): boolean {
- return endedVoteDiv(wrapper, value).closest(".mx_MPollBody_option").hasClass("mx_MPollBody_option_checked");
+function endedVoteDiv({ getByTestId }: RenderResult, value: string): Element {
+ return getByTestId(`pollOption-${value}`).firstElementChild!;
}
-function endedVoteDiv(wrapper: ReactWrapper, value: string): ReactWrapper {
- return wrapper.find(`div[data-value="${value}"]`);
+function endedVotesCount(renderResult: RenderResult, value: string): string {
+ return votesCount(renderResult, value);
}
-function endedVotesCount(wrapper: ReactWrapper, value: string): string {
- return wrapper.find(`div[data-value="${value}"] .mx_MPollBody_optionVoteCount`).text();
-}
-
-function newPollStart(answers?: POLL_ANSWER[], question?: string, disclosed = true): M_POLL_START_EVENT_CONTENT {
+function newPollStart(answers?: PollAnswer[], question?: string, disclosed = true): PollStartEventContent {
if (!answers) {
answers = [
{ id: "pizza", [M_TEXT.name]: "Pizza" },
@@ -1047,7 +1065,7 @@ function newPollStart(answers?: POLL_ANSWER[], question?: string, disclosed = tr
question = "What should we order for the party?";
}
- const answersFallback = answers.map((a, i) => `${i + 1}. ${a[M_TEXT.name]}`).join("\n");
+ const answersFallback = answers.map((a, i) => `${i + 1}. ${M_TEXT.findIn(a)}`).join("\n");
const fallback = `${question}\n${answersFallback}`;
diff --git a/test/components/views/messages/__snapshots__/MPollBody-test.tsx.snap b/test/components/views/messages/__snapshots__/MPollBody-test.tsx.snap
index e4039b82b6..2263527148 100644
--- a/test/components/views/messages/__snapshots__/MPollBody-test.tsx.snap
+++ b/test/components/views/messages/__snapshots__/MPollBody-test.tsx.snap
@@ -1,2626 +1,1627 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`MPollBody renders a finished poll 1`] = `
-
+
-
+
What should we order for the party?
-
+ Pizza
+
+
+ 0 votes
+
+
+
+
+
+
+
+
+
+ Poutine
+
+
+ 0 votes
+
+
+
+
+
+
+
+
+
+ Italian
+
+
+ 2 votes
+
+
+
+
+
+
+
+
+
+ Wings
+
+
+ 1 vote
+
+
+
+
+
+
+
+ Final result based on 3 votes
+
+
+
+`;
+
+exports[`MPollBody renders a finished poll with multiple winners 1`] = `
+
+
+
+ What should we order for the party?
+
+
+
+
+
+
+ Pizza
+
+
+ 2 votes
+
+
+
+
+
+
+
+
+
+ Poutine
+
+
+ 0 votes
+
+
+
+
+
+
+
+
+
+ Italian
+
+
+ 0 votes
+
+
+
+
+
+
+
+
+
+ Wings
+
+
+ 2 votes
+
+
+
+
+
+
+
+ Final result based on 4 votes
+
+
+
+`;
+
+exports[`MPollBody renders a finished poll with no votes 1`] = `
+
+
+
+ What should we order for the party?
+
+
+
+
+
+
+ Pizza
+
+
+ 0 votes
+
+
+
+
+
+
+
+
+
+ Poutine
+
+
+ 0 votes
+
+
+
+
+
+
+
+
+
+ Italian
+
+
+ 0 votes
+
+
+
+
+
+
+
+
+
+ Wings
+
+
+ 0 votes
+
+
+
+
+
+
+
+ Final result based on 0 votes
+
+
+
+`;
+
+exports[`MPollBody renders a poll that I have not voted in 1`] = `
+
+
+
+ What should we order for the party?
+
+
+
+
-
+
+
Poutine
- 0 votes
-
+ class="mx_MPollBody_optionVoteCount"
+ />
-
+
+
-
+
+
Italian
- 2 votes
-
+ class="mx_MPollBody_optionVoteCount"
+ />
-
+
+
+
+
+ 3 votes cast. Vote to see the results
+
+
+
+`;
+
+exports[`MPollBody renders a poll with local, non-local and invalid votes 1`] = `
+
+
+
+ What should we order for the party?
+
+
-
- Final result based on 3 votes
-
-
-
-`;
-
-exports[`MPollBody renders a finished poll with multiple winners 1`] = `
-
-
-
- What should we order for the party?
-
-
-
-
-
-
- Pizza
-
-
- 2 votes
-
-
+
+
-
-
-
-
-
+
+
Italian
- 0 votes
+ 3 votes
-
+
+
- Final result based on 4 votes
-
-
-
-`;
-
-exports[`MPollBody renders a finished poll with no votes 1`] = `
-
-
-
- What should we order for the party?
-
-
-
-
-
-
-
- Pizza
-
-
- 0 votes
-
-
-
-
-
-
-
-
-
-
-
- Poutine
-
-
- 0 votes
-
-
-
-
-
-
-
-
-
-
-
- Italian
-
-
- 0 votes
-
-
-
-
-
-
-
-
-
-
-
- Wings
-
-
- 0 votes
-
-
-
-
-
-
-
-
- Final result based on 0 votes
-
-
-
-`;
-
-exports[`MPollBody renders a poll that I have not voted in 1`] = `
-
-
-
- What should we order for the party?
-
-
-
- 3 votes cast. Vote to see the results
-
-
-
-`;
-
-exports[`MPollBody renders a poll with local, non-local and invalid votes 1`] = `
-
-
-
- What should we order for the party?
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Based on 5 votes
-
+
`;
exports[`MPollBody renders a poll with no votes 1`] = `
-
+
-
+
What should we order for the party?
+
+
+
+
+
+
No votes cast
-
+
`;
exports[`MPollBody renders a poll with only non-local votes 1`] = `
-
+
-
+
What should we order for the party?
-
-
+
+
-
-
-
+ class="mx_MPollBody_optionVoteCount"
+ >
+ 0 votes
+
+
+
+
+
-
-
+
+
-
-
-
+ class="mx_MPollBody_optionVoteCount"
+ >
+ 0 votes
+
+
+
+
+
-
-
+
+
-
-
-
+ class="mx_MPollBody_optionVoteCount"
+ >
+ 2 votes
+
+
+
+
+
-
-
+
+
-
-
-
+ class="mx_MPollBody_optionVoteCount"
+ >
+ 1 vote
+
+
+
+
+
Based on 3 votes
-
+
`;
-exports[`MPollBody renders an undisclosed, finished poll 1`] = `"What should we order for the party?
Final result based on 4 votes
"`;
+exports[`MPollBody renders an undisclosed, finished poll 1`] = `
+
+
+
+ What should we order for the party?
+
+
+
+
+
+
+ Pizza
+
+
+ 2 votes
+
+
+
+
+
+
+
+
+
+ Poutine
+
+
+ 0 votes
+
+
+
+
+
+
+
+
+
+ Italian
+
+
+ 0 votes
+
+
+
+
+
+
+
+
+
+ Wings
+
+
+ 2 votes
+
+
+
+
+
+
+
+ Final result based on 4 votes
+
+
+
+`;
-exports[`MPollBody renders an undisclosed, unfinished poll 1`] = `"What should we order for the party?
Results will be visible when the poll is ended
"`;
+exports[`MPollBody renders an undisclosed, unfinished poll 1`] = `
+
+
+
+ What should we order for the party?
+
+
+
+ Results will be visible when the poll is ended
+
+
+
+`;
diff --git a/test/components/views/right_panel/PinnedMessagesCard-test.tsx b/test/components/views/right_panel/PinnedMessagesCard-test.tsx
index e4be6191c3..1ce533837d 100644
--- a/test/components/views/right_panel/PinnedMessagesCard-test.tsx
+++ b/test/components/views/right_panel/PinnedMessagesCard-test.tsx
@@ -23,14 +23,10 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { EventType, RelationType, MsgType } from "matrix-js-sdk/src/@types/event";
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import { IEvent, Room, EventTimelineSet, IMinimalEvent } from "matrix-js-sdk/src/matrix";
-import {
- M_POLL_RESPONSE,
- M_POLL_END,
- M_POLL_KIND_DISCLOSED,
- PollStartEvent,
- PollResponseEvent,
- PollEndEvent,
-} from "matrix-events-sdk";
+import { M_POLL_RESPONSE, M_POLL_END, M_POLL_KIND_DISCLOSED } from "matrix-js-sdk/src/@types/polls";
+import { PollStartEvent } from "matrix-js-sdk/src/extensible_events_v1/PollStartEvent";
+import { PollResponseEvent } from "matrix-js-sdk/src/extensible_events_v1/PollResponseEvent";
+import { PollEndEvent } from "matrix-js-sdk/src/extensible_events_v1/PollEndEvent";
import { stubClient, mkStubRoom, mkEvent, mkMessage } from "../../../test-utils";
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
diff --git a/test/components/views/rooms/wysiwyg_composer/components/FormattingButtons-test.tsx b/test/components/views/rooms/wysiwyg_composer/components/FormattingButtons-test.tsx
index a467aa404e..012090d5d8 100644
--- a/test/components/views/rooms/wysiwyg_composer/components/FormattingButtons-test.tsx
+++ b/test/components/views/rooms/wysiwyg_composer/components/FormattingButtons-test.tsx
@@ -17,90 +17,118 @@ limitations under the License.
import React from "react";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
-import { AllActionStates, FormattingFunctions } from "@matrix-org/matrix-wysiwyg";
+import { ActionState, ActionTypes, AllActionStates, FormattingFunctions } from "@matrix-org/matrix-wysiwyg";
import { FormattingButtons } from "../../../../../../src/components/views/rooms/wysiwyg_composer/components/FormattingButtons";
import * as LinkModal from "../../../../../../src/components/views/rooms/wysiwyg_composer/components/LinkModal";
+const mockWysiwyg = {
+ bold: jest.fn(),
+ italic: jest.fn(),
+ underline: jest.fn(),
+ strikeThrough: jest.fn(),
+ inlineCode: jest.fn(),
+ link: jest.fn(),
+ orderedList: jest.fn(),
+ unorderedList: jest.fn(),
+} as unknown as FormattingFunctions;
+
+const openLinkModalSpy = jest.spyOn(LinkModal, "openLinkModal");
+
+const testCases: Record<
+ Exclude,
+ { label: string; mockFormatFn: jest.Func | jest.SpyInstance }
+> = {
+ bold: { label: "Bold", mockFormatFn: mockWysiwyg.bold },
+ italic: { label: "Italic", mockFormatFn: mockWysiwyg.italic },
+ underline: { label: "Underline", mockFormatFn: mockWysiwyg.underline },
+ strikeThrough: { label: "Strikethrough", mockFormatFn: mockWysiwyg.strikeThrough },
+ inlineCode: { label: "Code", mockFormatFn: mockWysiwyg.inlineCode },
+ link: { label: "Link", mockFormatFn: openLinkModalSpy },
+ orderedList: { label: "Numbered list", mockFormatFn: mockWysiwyg.orderedList },
+ unorderedList: { label: "Bulleted list", mockFormatFn: mockWysiwyg.unorderedList },
+};
+
+const createActionStates = (state: ActionState): AllActionStates => {
+ return Object.fromEntries(Object.keys(testCases).map((testKey) => [testKey, state])) as AllActionStates;
+};
+
+const defaultActionStates = createActionStates("enabled");
+
+const renderComponent = (props = {}) => {
+ return render();
+};
+
+const classes = {
+ active: "mx_FormattingButtons_active",
+ hover: "mx_FormattingButtons_Button_hover",
+};
+
describe("FormattingButtons", () => {
- const wysiwyg = {
- bold: jest.fn(),
- italic: jest.fn(),
- underline: jest.fn(),
- strikeThrough: jest.fn(),
- inlineCode: jest.fn(),
- link: jest.fn(),
- } as unknown as FormattingFunctions;
-
- const actionStates = {
- bold: "reversed",
- italic: "reversed",
- underline: "enabled",
- strikeThrough: "enabled",
- inlineCode: "enabled",
- link: "enabled",
- } as AllActionStates;
-
afterEach(() => {
jest.resetAllMocks();
});
- it("Should have the correspond CSS classes", () => {
- // When
- render();
+ it("Each button should not have active class when enabled", () => {
+ renderComponent();
- // Then
- expect(screen.getByLabelText("Bold")).toHaveClass("mx_FormattingButtons_active");
- expect(screen.getByLabelText("Italic")).toHaveClass("mx_FormattingButtons_active");
- expect(screen.getByLabelText("Underline")).not.toHaveClass("mx_FormattingButtons_active");
- expect(screen.getByLabelText("Strikethrough")).not.toHaveClass("mx_FormattingButtons_active");
- expect(screen.getByLabelText("Code")).not.toHaveClass("mx_FormattingButtons_active");
- expect(screen.getByLabelText("Link")).not.toHaveClass("mx_FormattingButtons_active");
+ Object.values(testCases).forEach(({ label }) => {
+ expect(screen.getByLabelText(label)).not.toHaveClass(classes.active);
+ });
});
- it("Should call wysiwyg function on button click", () => {
- // When
- const spy = jest.spyOn(LinkModal, "openLinkModal");
- render();
- screen.getByLabelText("Bold").click();
- screen.getByLabelText("Italic").click();
- screen.getByLabelText("Underline").click();
- screen.getByLabelText("Strikethrough").click();
- screen.getByLabelText("Code").click();
- screen.getByLabelText("Link").click();
+ it("Each button should have active class when reversed", () => {
+ const reversedActionStates = createActionStates("reversed");
+ renderComponent({ actionStates: reversedActionStates });
- // Then
- expect(wysiwyg.bold).toHaveBeenCalledTimes(1);
- expect(wysiwyg.italic).toHaveBeenCalledTimes(1);
- expect(wysiwyg.underline).toHaveBeenCalledTimes(1);
- expect(wysiwyg.strikeThrough).toHaveBeenCalledTimes(1);
- expect(wysiwyg.inlineCode).toHaveBeenCalledTimes(1);
- expect(spy).toHaveBeenCalledTimes(1);
+ Object.values(testCases).forEach((testCase) => {
+ const { label } = testCase;
+ expect(screen.getByLabelText(label)).toHaveClass(classes.active);
+ });
});
- it("Should display the tooltip on mouse over", async () => {
- // When
- const user = userEvent.setup();
- render();
- await user.hover(screen.getByLabelText("Bold"));
+ it("Should call wysiwyg function on button click", async () => {
+ renderComponent();
- // Then
- expect(await screen.findByText("Bold")).toBeTruthy();
+ for (const testCase of Object.values(testCases)) {
+ const { label, mockFormatFn } = testCase;
+
+ screen.getByLabelText(label).click();
+ expect(mockFormatFn).toHaveBeenCalledTimes(1);
+ }
});
- it("Should not have hover style when active", async () => {
- // When
- const user = userEvent.setup();
- render();
- await user.hover(screen.getByLabelText("Bold"));
+ it("Each button should display the tooltip on mouse over", async () => {
+ renderComponent();
- // Then
- expect(screen.getByLabelText("Bold")).not.toHaveClass("mx_FormattingButtons_Button_hover");
+ for (const testCase of Object.values(testCases)) {
+ const { label } = testCase;
- // When
- await user.hover(screen.getByLabelText("Underline"));
+ await userEvent.hover(screen.getByLabelText(label));
+ expect(await screen.findByText(label)).toBeTruthy();
+ }
+ });
- // Then
- expect(screen.getByLabelText("Underline")).toHaveClass("mx_FormattingButtons_Button_hover");
+ it("Each button should have hover style when hovered and enabled", async () => {
+ renderComponent();
+
+ for (const testCase of Object.values(testCases)) {
+ const { label } = testCase;
+
+ await userEvent.hover(screen.getByLabelText(label));
+ expect(screen.getByLabelText(label)).toHaveClass("mx_FormattingButtons_Button_hover");
+ }
+ });
+
+ it("Each button should not have hover style when hovered and reversed", async () => {
+ const reversedActionStates = createActionStates("reversed");
+ renderComponent({ actionStates: reversedActionStates });
+
+ for (const testCase of Object.values(testCases)) {
+ const { label } = testCase;
+
+ await userEvent.hover(screen.getByLabelText(label));
+ expect(screen.getByLabelText(label)).not.toHaveClass("mx_FormattingButtons_Button_hover");
+ }
});
});
diff --git a/test/test-utils/poll.ts b/test/test-utils/poll.ts
index 88b7c3035a..5096f8c51a 100644
--- a/test/test-utils/poll.ts
+++ b/test/test-utils/poll.ts
@@ -15,9 +15,10 @@ limitations under the License.
*/
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
-import { M_TEXT, M_POLL_START, POLL_ANSWER, M_POLL_KIND_DISCLOSED } from "matrix-events-sdk";
+import { M_POLL_START, PollAnswer, M_POLL_KIND_DISCLOSED } from "matrix-js-sdk/src/@types/polls";
+import { M_TEXT } from "matrix-js-sdk/src/@types/extensible_events";
-export const makePollStartEvent = (question: string, sender: string, answers?: POLL_ANSWER[]): MatrixEvent => {
+export const makePollStartEvent = (question: string, sender: string, answers?: PollAnswer[]): MatrixEvent => {
if (!answers) {
answers = [
{ id: "socks", [M_TEXT.name]: "Socks" },
diff --git a/test/utils/location/isSelfLocation-test.ts b/test/utils/location/isSelfLocation-test.ts
index fd89ae104b..d04149b681 100644
--- a/test/utils/location/isSelfLocation-test.ts
+++ b/test/utils/location/isSelfLocation-test.ts
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import { TEXT_NODE_TYPE } from "matrix-js-sdk/src/@types/extensible_events";
+import { M_TEXT } from "matrix-js-sdk/src/@types/extensible_events";
import {
ILocationContent,
LocationAssetType,
@@ -38,7 +38,7 @@ describe("isSelfLocation", () => {
msgtype: "m.location",
geo_uri: "",
[M_LOCATION.name]: { uri: "" },
- [TEXT_NODE_TYPE.name]: "",
+ [M_TEXT.name]: "",
[M_TIMESTAMP.name]: 0,
// Note: no m.asset!
};
@@ -51,7 +51,7 @@ describe("isSelfLocation", () => {
msgtype: "m.location",
geo_uri: "",
[M_LOCATION.name]: { uri: "" },
- [TEXT_NODE_TYPE.name]: "",
+ [M_TEXT.name]: "",
[M_TIMESTAMP.name]: 0,
[M_ASSET.name]: {
// Note: no type!