From 317ffcf1acee056e71df2a2868d67a4738c098cf Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 7 Mar 2023 17:50:02 +0000 Subject: [PATCH] Update to React 18 Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- package.json | 19 ++-- src/@types/react.d.ts | 3 + src/NodeAnimator.tsx | 9 +- .../structures/GenericDropdownMenu.tsx | 12 +- src/components/structures/ThreadPanel.tsx | 2 +- src/components/views/avatars/BaseAvatar.tsx | 4 +- .../views/dialogs/spotlight/Option.tsx | 1 + .../views/directory/NetworkDropdown.tsx | 8 +- .../views/elements/PersistentApp.tsx | 3 +- .../views/messages/RoomPredecessorTile.tsx | 10 +- .../views/messages/TextualEvent.tsx | 1 + .../views/messages/TimelineSeparator.tsx | 3 +- src/components/views/pips/WidgetPip.tsx | 5 +- src/components/views/right_panel/UserInfo.tsx | 3 +- src/components/views/rooms/RoomHeader.tsx | 5 +- .../views/settings/UserProfileSettings.tsx | 4 +- .../views/spaces/QuickSettingsButton.tsx | 2 +- src/hooks/useAccountData.ts | 4 +- src/languageHandler.tsx | 18 +-- .../views/dialogs/InviteDialog-test.tsx | 2 +- .../hooks/usePlainTextListeners-test.tsx | 3 +- .../spaces/useUnreadThreadRooms-test.tsx | 3 +- .../room/useRoomThreadNotifications-test.tsx | 2 +- test/hooks/useDebouncedCallback-test.tsx | 2 +- test/hooks/useLatestResult-test.tsx | 4 +- test/hooks/useNotificationSettings-test.tsx | 16 +-- test/hooks/useProfileInfo-test.tsx | 3 +- test/hooks/usePublicRoomDirectory-test.tsx | 3 +- test/hooks/useRoomMembers-test.tsx | 3 +- test/hooks/useSlidingSyncRoomSearch-test.tsx | 3 +- test/hooks/useUnreadNotifications-test.ts | 2 +- test/hooks/useUserDirectory-test.tsx | 3 +- test/hooks/useUserOnboardingTasks-test.tsx | 3 +- test/hooks/useWindowWidth-test.ts | 3 +- test/languageHandler-test.tsx | 10 +- test/modules/ProxiedModuleApi-test.tsx | 12 ++ yarn.lock | 104 ++++++------------ 37 files changed, 132 insertions(+), 165 deletions(-) diff --git a/package.json b/package.json index 2a2dd4bf00..489f789089 100644 --- a/package.json +++ b/package.json @@ -63,8 +63,8 @@ "lint:workflows": "find .github/workflows -type f \\( -iname '*.yaml' -o -iname '*.yml' \\) | xargs -I {} sh -c 'echo \"Linting {}\"; action-validator \"{}\"'" }, "resolutions": { - "@types/react-dom": "17.0.25", - "@types/react": "17.0.80", + "@types/react-dom": "18.3.0", + "@types/react": "18.3.3", "@types/seedrandom": "3.0.8", "oidc-client-ts": "3.0.1", "jwt-decode": "4.0.0", @@ -81,7 +81,6 @@ "@matrix-org/react-sdk-module-api": "^2.4.0", "@matrix-org/spec": "^1.7.0", "@sentry/browser": "^8.0.0", - "@testing-library/react-hooks": "^8.0.1", "@vector-im/compound-design-tokens": "^1.6.1", "@vector-im/compound-web": "^5.5.0", "@zxcvbn-ts/core": "^3.0.4", @@ -129,10 +128,10 @@ "posthog-js": "1.149.1", "qrcode": "1.5.3", "re-resizable": "^6.9.0", - "react": "17.0.2", + "react": "^18.3.1", "react-beautiful-dnd": "^13.1.0", "react-blurhash": "^0.3.0", - "react-dom": "17.0.2", + "react-dom": "^18.3.1", "react-focus-lock": "^2.5.1", "react-transition-group": "^4.4.1", "rfc4648": "^1.4.0", @@ -167,7 +166,7 @@ "@playwright/test": "^1.40.1", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^12.1.5", + "@testing-library/react": "^14", "@testing-library/user-event": "^14.4.3", "@types/commonmark": "^0.27.4", "@types/content-type": "^1.1.5", @@ -187,9 +186,9 @@ "@types/node-fetch": "^2.6.2", "@types/pako": "^2.0.0", "@types/qrcode": "^1.3.5", - "@types/react": "17.0.80", + "@types/react": "18.3.3", "@types/react-beautiful-dnd": "^13.0.0", - "@types/react-dom": "17.0.25", + "@types/react-dom": "18.3.0", "@types/react-transition-group": "^4.4.0", "@types/sanitize-html": "2.11.0", "@types/sdp-transform": "^2.4.6", @@ -246,6 +245,10 @@ "postcss": "^8.4.19", "webpack": "^4.0.0 || ^5.0.0" }, + "peerDependencies": { + "postcss": "^8.4.19", + "webpack": "^4.0.0 || ^5.0.0" + }, "@casualbot/jest-sonar-reporter": { "outputDirectory": "coverage", "outputName": "jest-sonar-report.xml", diff --git a/src/@types/react.d.ts b/src/@types/react.d.ts index f1f57c5400..c3b49fb1f8 100644 --- a/src/@types/react.d.ts +++ b/src/@types/react.d.ts @@ -21,4 +21,7 @@ declare module "react" { function forwardRef( render: (props: PropsWithChildren

, ref: React.ForwardedRef) => React.ReactElement | null, ): (props: P & React.RefAttributes) => React.ReactElement | null; + + // Fix lazy types - https://stackoverflow.com/a/71017028 + function lazy>(factory: () => Promise<{ default: T }>): T; } diff --git a/src/NodeAnimator.tsx b/src/NodeAnimator.tsx index 85151bf3b0..897c58ab2f 100644 --- a/src/NodeAnimator.tsx +++ b/src/NodeAnimator.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { Key, MutableRefObject, ReactElement, ReactFragment, ReactInstance, ReactPortal } from "react"; +import React, { Key, MutableRefObject, ReactElement, ReactInstance } from "react"; import ReactDom from "react-dom"; interface IChildProps { @@ -35,7 +35,7 @@ interface IProps { innerRef?: MutableRefObject; } -function isReactElement(c: ReactElement | ReactFragment | ReactPortal): c is ReactElement { +function isReactElement(c: ReturnType<(typeof React.Children)["toArray"]>[number]): c is ReactElement { return typeof c === "object" && "type" in c; } @@ -110,7 +110,8 @@ export default class NodeAnimator extends React.Component { } private collectNode(k: Key, node: React.ReactInstance, restingStyle: React.CSSProperties): void { - if (node && this.nodes[k] === undefined && this.props.startStyles.length > 0) { + const key = typeof k === "bigint" ? Number(k) : k; + if (node && this.nodes[key] === undefined && this.props.startStyles.length > 0) { const startStyles = this.props.startStyles; const domNode = ReactDom.findDOMNode(node); // start from startStyle 1: 0 is the one we gave it @@ -124,7 +125,7 @@ export default class NodeAnimator extends React.Component { this.applyStyles(domNode as HTMLElement, restingStyle); }, 0); } - this.nodes[k] = node; + this.nodes[key] = node; if (this.props.innerRef) { this.props.innerRef.current = node; diff --git a/src/components/structures/GenericDropdownMenu.tsx b/src/components/structures/GenericDropdownMenu.tsx index e0fd3b7f9b..06854768db 100644 --- a/src/components/structures/GenericDropdownMenu.tsx +++ b/src/components/structures/GenericDropdownMenu.tsx @@ -97,6 +97,12 @@ type WithKeyFunction = T extends Key toKey: (key: T) => Key; }; +export interface AdditionalOptionsProps { + menuDisplayed: boolean; + closeMenu: () => void; + openMenu: () => void; +} + type IProps = WithKeyFunction & { value: T; options: readonly GenericDropdownMenuOption[] | readonly GenericDropdownMenuGroup[]; @@ -105,11 +111,7 @@ type IProps = WithKeyFunction & { onOpen?: (ev: ButtonEvent) => void; onClose?: (ev: ButtonEvent) => void; className?: string; - AdditionalOptions?: FunctionComponent<{ - menuDisplayed: boolean; - closeMenu: () => void; - openMenu: () => void; - }>; + AdditionalOptions?: FunctionComponent; }; export function GenericDropdownMenu({ diff --git a/src/components/structures/ThreadPanel.tsx b/src/components/structures/ThreadPanel.tsx index 8951cfcb91..792c97bc52 100644 --- a/src/components/structures/ThreadPanel.tsx +++ b/src/components/structures/ThreadPanel.tsx @@ -117,7 +117,7 @@ export const ThreadPanelHeader: React.FC<{ ) : null; const onMarkAllThreadsReadClick = React.useCallback( - (e) => { + (e: React.MouseEvent) => { PosthogTrackers.trackInteraction("WebThreadsMarkAllReadButton", e); if (!roomContext.room) { logger.error("No room in context to mark all threads read"); diff --git a/src/components/views/avatars/BaseAvatar.tsx b/src/components/views/avatars/BaseAvatar.tsx index d956c26da2..b35109f5d7 100644 --- a/src/components/views/avatars/BaseAvatar.tsx +++ b/src/components/views/avatars/BaseAvatar.tsx @@ -19,7 +19,7 @@ limitations under the License. import React, { forwardRef, useCallback, useContext, useEffect, useState } from "react"; import classNames from "classnames"; -import { ClientEvent } from "matrix-js-sdk/src/matrix"; +import { ClientEvent, SyncState } from "matrix-js-sdk/src/matrix"; import { Avatar } from "@vector-im/compound-web"; import SettingsStore from "../../../settings/SettingsStore"; @@ -80,7 +80,7 @@ const useImageUrl = ({ url, urls }: { url?: string | null; urls?: string[] }): [ }, [url, JSON.stringify(urls)]); // eslint-disable-line react-hooks/exhaustive-deps const cli = useContext(MatrixClientContext); - const onClientSync = useCallback((syncState, prevState) => { + const onClientSync = useCallback((syncState: SyncState, prevState: SyncState | null) => { // Consider the client reconnected if there is no error with syncing. // This means the state could be RECONNECTING, SYNCING, PREPARED or CATCHUP. const reconnected = syncState !== "ERROR" && prevState !== syncState; diff --git a/src/components/views/dialogs/spotlight/Option.tsx b/src/components/views/dialogs/spotlight/Option.tsx index c7d504aa0b..d15b781fcf 100644 --- a/src/components/views/dialogs/spotlight/Option.tsx +++ b/src/components/views/dialogs/spotlight/Option.tsx @@ -26,6 +26,7 @@ interface OptionProps { id?: string; className?: string; onClick: ((ev: ButtonEvent) => void) | null; + children?: ReactNode; } export const Option: React.FC = ({ inputRef, children, endAdornment, className, ...props }) => { diff --git a/src/components/views/directory/NetworkDropdown.tsx b/src/components/views/directory/NetworkDropdown.tsx index 8736e974e8..deb9285853 100644 --- a/src/components/views/directory/NetworkDropdown.tsx +++ b/src/components/views/directory/NetworkDropdown.tsx @@ -26,7 +26,11 @@ import SdkConfig from "../../../SdkConfig"; import { SettingLevel } from "../../../settings/SettingLevel"; import SettingsStore from "../../../settings/SettingsStore"; import { Protocols } from "../../../utils/DirectoryUtils"; -import { GenericDropdownMenu, GenericDropdownMenuItem } from "../../structures/GenericDropdownMenu"; +import { + AdditionalOptionsProps, + GenericDropdownMenu, + GenericDropdownMenuItem, +} from "../../structures/GenericDropdownMenu"; import TextInputDialog from "../dialogs/TextInputDialog"; import AccessibleButton from "../elements/AccessibleButton"; import withValidation from "../elements/Validation"; @@ -181,7 +185,7 @@ export const NetworkDropdown: React.FC = ({ protocols, config, setConfig })); const addNewServer = useCallback( - ({ closeMenu }) => ( + ({ closeMenu }: AdditionalOptionsProps) => ( <> void) | undefined>; + children?: ReactNode; } export default class PersistentApp extends React.Component { diff --git a/src/components/views/messages/RoomPredecessorTile.tsx b/src/components/views/messages/RoomPredecessorTile.tsx index 3166373fe0..36679d906d 100644 --- a/src/components/views/messages/RoomPredecessorTile.tsx +++ b/src/components/views/messages/RoomPredecessorTile.tsx @@ -17,7 +17,7 @@ limitations under the License. import React, { useCallback, useContext } from "react"; import { logger } from "matrix-js-sdk/src/logger"; -import { MatrixEvent, Room } from "matrix-js-sdk/src/matrix"; +import { MatrixEvent, Room, RoomState } from "matrix-js-sdk/src/matrix"; import dis from "../../../dispatcher/dispatcher"; import { Action } from "../../../dispatcher/actions"; @@ -52,7 +52,7 @@ export const RoomPredecessorTile: React.FC = ({ mxEvent, timestamp }) => const predecessor = useRoomState( roomContext.room, useCallback( - (state) => state.findPredecessor(msc3946ProcessDynamicPredecessor), + (state: RoomState) => state.findPredecessor(msc3946ProcessDynamicPredecessor), [msc3946ProcessDynamicPredecessor], ), ); @@ -63,9 +63,9 @@ export const RoomPredecessorTile: React.FC = ({ mxEvent, timestamp }) => dis.dispatch({ action: Action.ViewRoom, - event_id: predecessor.eventId, + event_id: predecessor?.eventId, highlighted: true, - room_id: predecessor.roomId, + room_id: predecessor?.roomId, metricsTrigger: "Predecessor", metricsViaKeyboard: e.type !== "click", }); @@ -126,7 +126,7 @@ export const RoomPredecessorTile: React.FC = ({ mxEvent, timestamp }) => const predecessorPermalink = prevRoom ? createLinkWithRoom(prevRoom, predecessor.roomId, predecessor.eventId) - : createLinkWithoutRoom(predecessor.roomId, predecessor.viaServers, predecessor.eventId); + : createLinkWithoutRoom(predecessor.roomId, predecessor?.viaServers ?? [], predecessor.eventId); const link = ( diff --git a/src/components/views/messages/TextualEvent.tsx b/src/components/views/messages/TextualEvent.tsx index ae94fd31f9..35351ce531 100644 --- a/src/components/views/messages/TextualEvent.tsx +++ b/src/components/views/messages/TextualEvent.tsx @@ -27,6 +27,7 @@ interface IProps { export default class TextualEvent extends React.Component { public static contextType = RoomContext; + public declare context: React.ContextType; public render(): React.ReactNode { const text = TextForEvent.textForEvent( diff --git a/src/components/views/messages/TimelineSeparator.tsx b/src/components/views/messages/TimelineSeparator.tsx index 78e0d1fd65..b3a2b9ccfb 100644 --- a/src/components/views/messages/TimelineSeparator.tsx +++ b/src/components/views/messages/TimelineSeparator.tsx @@ -14,10 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from "react"; +import React, { ReactNode } from "react"; interface Props { label: string; + children?: ReactNode; } export const enum SeparatorKind { diff --git a/src/components/views/pips/WidgetPip.tsx b/src/components/views/pips/WidgetPip.tsx index 9bba2ccc53..a1710d16cc 100644 --- a/src/components/views/pips/WidgetPip.tsx +++ b/src/components/views/pips/WidgetPip.tsx @@ -34,6 +34,7 @@ import { WidgetType } from "../../../widgets/WidgetType"; import { WidgetMessagingStore } from "../../../stores/widgets/WidgetMessagingStore"; import WidgetUtils from "../../../utils/WidgetUtils"; import { ElementWidgetActions } from "../../../stores/widgets/ElementWidgetActions"; +import { ButtonEvent } from "../elements/AccessibleButton"; interface Props { widgetId: string; @@ -62,7 +63,7 @@ export const WidgetPip: FC = ({ widgetId, room, viewingRoom, onStartMovin const call = useCallForWidget(widgetId, room.roomId); const onBackClick = useCallback( - (ev) => { + (ev: ButtonEvent) => { ev.preventDefault(); ev.stopPropagation(); @@ -87,7 +88,7 @@ export const WidgetPip: FC = ({ widgetId, room, viewingRoom, onStartMovin ); const onLeaveClick = useCallback( - (ev) => { + (ev: ButtonEvent) => { ev.preventDefault(); ev.stopPropagation(); diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index 6f8fd9790b..159bc9dbf1 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -424,6 +424,7 @@ export const UserOptionsSection: React.FC<{ member: Member; canInvite: boolean; isSpace?: boolean; + children?: ReactNode; }> = ({ member, canInvite, isSpace, children }) => { const cli = useContext(MatrixClientContext); @@ -1036,7 +1037,7 @@ const IgnoreToggleButton: React.FC<{ }, [cli, member.userId]); // Recheck also if we receive new accountData m.ignored_user_list const accountDataHandler = useCallback( - (ev) => { + (ev: MatrixEvent) => { if (ev.getType() === "m.ignored_user_list") { setIsIgnored(cli.isUserIgnored(member.userId)); } diff --git a/src/components/views/rooms/RoomHeader.tsx b/src/components/views/rooms/RoomHeader.tsx index 9cf63e474d..11873ee129 100644 --- a/src/components/views/rooms/RoomHeader.tsx +++ b/src/components/views/rooms/RoomHeader.tsx @@ -116,7 +116,10 @@ export default function RoomHeader({ const askToJoinEnabled = useFeatureEnabled("feature_ask_to_join"); - const videoClick = useCallback((ev) => videoCallClick(ev, callOptions[0]), [callOptions, videoCallClick]); + const videoClick = useCallback( + (ev: React.MouseEvent) => videoCallClick(ev, callOptions[0]), + [callOptions, videoCallClick], + ); const toggleCallButton = ( diff --git a/src/components/views/settings/UserProfileSettings.tsx b/src/components/views/settings/UserProfileSettings.tsx index a104aabb1d..b793f27dd6 100644 --- a/src/components/views/settings/UserProfileSettings.tsx +++ b/src/components/views/settings/UserProfileSettings.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { ChangeEvent, useCallback, useEffect, useMemo, useState } from "react"; +import React, { ChangeEvent, ReactNode, useCallback, useEffect, useMemo, useState } from "react"; import { logger } from "matrix-js-sdk/src/logger"; import { EditInPlace, Alert, ErrorMessage } from "@vector-im/compound-web"; import { Icon as PopOutIcon } from "@vector-im/compound-design-tokens/icons/pop-out.svg"; @@ -37,7 +37,7 @@ import Modal from "../../../Modal"; import defaultDispatcher from "../../../dispatcher/dispatcher"; import { Flex } from "../../utils/Flex"; -const SpinnerToast: React.FC = ({ children }) => ( +const SpinnerToast: React.FC<{ children?: ReactNode }> = ({ children }) => ( <> {children} diff --git a/src/components/views/spaces/QuickSettingsButton.tsx b/src/components/views/spaces/QuickSettingsButton.tsx index cf031e4ff1..a118a13bbc 100644 --- a/src/components/views/spaces/QuickSettingsButton.tsx +++ b/src/components/views/spaces/QuickSettingsButton.tsx @@ -45,7 +45,7 @@ const QuickSettingsButton: React.FC<{ useSettingValue>("Spaces.enabledMetaSpaces"); const currentRoomId = SdkContextClass.instance.roomViewStore.getRoomId(); - const developerModeEnabled = useSettingValue("developerMode"); + const developerModeEnabled = useSettingValue("developerMode"); let contextMenu: JSX.Element | undefined; if (menuDisplayed && handle.current) { diff --git a/src/hooks/useAccountData.ts b/src/hooks/useAccountData.ts index d59910d503..ad25f61465 100644 --- a/src/hooks/useAccountData.ts +++ b/src/hooks/useAccountData.ts @@ -26,9 +26,9 @@ export const useAccountData = (cli: MatrixClient, eventType: strin const [value, setValue] = useState(() => tryGetContent(cli.getAccountData(eventType))); const handler = useCallback( - (event) => { + (event: MatrixEvent) => { if (event.getType() !== eventType) return; - setValue(event.getContent()); + setValue(event.getContent()); }, [eventType], ); diff --git a/src/languageHandler.tsx b/src/languageHandler.tsx index 0a80be89f4..dd8a2452f2 100644 --- a/src/languageHandler.tsx +++ b/src/languageHandler.tsx @@ -52,13 +52,6 @@ counterpart.setSeparator(KEY_SEPARATOR); const FALLBACK_LOCALE = "en"; counterpart.setFallbackLocale(FALLBACK_LOCALE); -export interface ErrorOptions { - // Because we're mixing the subsitution variables and `cause` into the same object - // below, we want them to always explicitly say whether there is an underlying error - // or not to avoid typos of "cause" slipping through unnoticed. - cause: unknown | undefined; -} - /** * Used to rethrow an error with a user-friendly translatable message while maintaining * access to that original underlying error. Downstream consumers can display the @@ -78,13 +71,8 @@ export interface ErrorOptions { export class UserFriendlyError extends Error { public readonly translatedMessage: string; - public constructor(message: TranslationKey, substitutionVariablesAndCause?: IVariables & ErrorOptions) { - const errorOptions = { - cause: substitutionVariablesAndCause?.cause, - }; - // Prevent "Could not find /%\(cause\)s/g in x" logs to the console by removing it from the list - const substitutionVariables = { ...substitutionVariablesAndCause }; - delete substitutionVariables["cause"]; + public constructor(message: TranslationKey, cause?: Error | unknown, substitutionVariables?: IVariables) { + const errorOptions = { cause }; // Create the error with the English version of the message that we want to show // up in the logs @@ -445,7 +433,7 @@ export function replaceByRegexes(text: string, mapping: IVariables | Tags): stri } if (shouldWrapInSpan) { - return React.createElement("span", null, ...output); + return React.createElement("span", null, ...(output as Array)); } else { return output.join(""); } diff --git a/test/components/views/dialogs/InviteDialog-test.tsx b/test/components/views/dialogs/InviteDialog-test.tsx index 4e1dca4193..e55dbf050a 100644 --- a/test/components/views/dialogs/InviteDialog-test.tsx +++ b/test/components/views/dialogs/InviteDialog-test.tsx @@ -429,7 +429,7 @@ describe("InviteDialog", () => { describe("when clicking »Start DM anyway«", () => { beforeEach(async () => { - await userEvent.click(screen.getByRole("button", { name: "Start DM anyway", exact: true })); + await userEvent.click(screen.getByRole("button", { name: "Start DM anyway" })); }); it("should start the DM", () => { diff --git a/test/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners-test.tsx b/test/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners-test.tsx index 779cca7333..e282c53a67 100644 --- a/test/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners-test.tsx +++ b/test/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners-test.tsx @@ -14,8 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { renderHook } from "@testing-library/react-hooks"; -import { act } from "@testing-library/react"; +import { renderHook, act } from "@testing-library/react"; import { usePlainTextListeners } from "../../../../../../src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners"; diff --git a/test/components/views/spaces/useUnreadThreadRooms-test.tsx b/test/components/views/spaces/useUnreadThreadRooms-test.tsx index d4dc04da96..d7ff360fb3 100644 --- a/test/components/views/spaces/useUnreadThreadRooms-test.tsx +++ b/test/components/views/spaces/useUnreadThreadRooms-test.tsx @@ -15,7 +15,6 @@ */ import React from "react"; -import { renderHook } from "@testing-library/react-hooks"; import { MatrixClient, MatrixEventEvent, @@ -23,7 +22,7 @@ import { PendingEventOrdering, Room, } from "matrix-js-sdk/src/matrix"; -import { act } from "@testing-library/react"; +import { renderHook, act } from "@testing-library/react"; import MatrixClientContext from "../../../../src/contexts/MatrixClientContext"; import { stubClient } from "../../../test-utils"; diff --git a/test/hooks/room/useRoomThreadNotifications-test.tsx b/test/hooks/room/useRoomThreadNotifications-test.tsx index 8946a1f2ec..4424e4e5d2 100644 --- a/test/hooks/room/useRoomThreadNotifications-test.tsx +++ b/test/hooks/room/useRoomThreadNotifications-test.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { renderHook } from "@testing-library/react-hooks/dom"; +import { renderHook } from "@testing-library/react"; import { MatrixClient, NotificationCountType, Room } from "matrix-js-sdk/src/matrix"; import { useRoomThreadNotifications } from "../../../src/hooks/room/useRoomThreadNotifications"; diff --git a/test/hooks/useDebouncedCallback-test.tsx b/test/hooks/useDebouncedCallback-test.tsx index 2d3b32e7f5..d8187a564f 100644 --- a/test/hooks/useDebouncedCallback-test.tsx +++ b/test/hooks/useDebouncedCallback-test.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { renderHook } from "@testing-library/react-hooks"; +import { renderHook } from "@testing-library/react"; import { useDebouncedCallback } from "../../src/hooks/spotlight/useDebouncedCallback"; diff --git a/test/hooks/useLatestResult-test.tsx b/test/hooks/useLatestResult-test.tsx index a561a82c09..053a5f3126 100644 --- a/test/hooks/useLatestResult-test.tsx +++ b/test/hooks/useLatestResult-test.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { renderHook, RenderHookResult } from "@testing-library/react-hooks/dom"; +import { renderHook, RenderHookResult } from "@testing-library/react"; import { useLatestResult } from "../../src/hooks/useLatestResult"; @@ -28,7 +28,7 @@ beforeEach(() => { }); function simulateRequest( - hookResult: RenderHookResult>["result"], + hookResult: RenderHookResult, typeof useLatestResult>["result"], { id, delayInMs, result }: { id: string; delayInMs: number; result: string }, ) { const [setQuery, setResult] = hookResult.current; diff --git a/test/hooks/useNotificationSettings-test.tsx b/test/hooks/useNotificationSettings-test.tsx index 5b0e490426..48b3472eaa 100644 --- a/test/hooks/useNotificationSettings-test.tsx +++ b/test/hooks/useNotificationSettings-test.tsx @@ -14,8 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { act } from "@testing-library/react"; -import { renderHook } from "@testing-library/react-hooks/dom"; +import { act, renderHook, waitFor } from "@testing-library/react"; import { IPushRules, MatrixClient, PushRuleKind, RuleId } from "matrix-js-sdk/src/matrix"; import { useNotificationSettings } from "../../src/hooks/useNotificationSettings"; @@ -69,10 +68,9 @@ describe("useNotificationSettings", () => { it("correctly parses model", async () => { await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => useNotificationSettings(cli)); + const { result } = renderHook(() => useNotificationSettings(cli)); expect(result.current.model).toEqual(null); - await waitForNextUpdate(); - expect(result.current.model).toEqual(expectedModel); + await waitFor(() => expect(result.current.model).toEqual(expectedModel)); expect(result.current.hasPendingChanges).toBeFalsy(); }); }); @@ -88,14 +86,12 @@ describe("useNotificationSettings", () => { const setPushRuleActions = jest.fn(cli.setPushRuleActions); cli.setPushRuleActions = setPushRuleActions; - const { result, waitForNextUpdate } = renderHook(() => useNotificationSettings(cli)); + const { result } = renderHook(() => useNotificationSettings(cli)); expect(result.current.model).toEqual(null); - await waitForNextUpdate(); - expect(result.current.model).toEqual(expectedModel); + await waitFor(() => expect(result.current.model).toEqual(expectedModel)); expect(result.current.hasPendingChanges).toBeFalsy(); await result.current.reconcile(DefaultNotificationSettings); - await waitForNextUpdate(); - expect(result.current.hasPendingChanges).toBeFalsy(); + await waitFor(() => expect(result.current.hasPendingChanges).toBeFalsy()); expect(addPushRule).toHaveBeenCalledTimes(0); expect(deletePushRule).toHaveBeenCalledTimes(9); expect(deletePushRule).toHaveBeenCalledWith("global", PushRuleKind.ContentSpecific, "justjann3"); diff --git a/test/hooks/useProfileInfo-test.tsx b/test/hooks/useProfileInfo-test.tsx index 63b78f78b1..3a895355e6 100644 --- a/test/hooks/useProfileInfo-test.tsx +++ b/test/hooks/useProfileInfo-test.tsx @@ -14,8 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { waitFor } from "@testing-library/react"; -import { renderHook, act } from "@testing-library/react-hooks/dom"; +import { waitFor, renderHook, act } from "@testing-library/react"; import { MatrixClient } from "matrix-js-sdk/src/matrix"; import { useProfileInfo } from "../../src/hooks/useProfileInfo"; diff --git a/test/hooks/usePublicRoomDirectory-test.tsx b/test/hooks/usePublicRoomDirectory-test.tsx index fe81416208..e729c38cf5 100644 --- a/test/hooks/usePublicRoomDirectory-test.tsx +++ b/test/hooks/usePublicRoomDirectory-test.tsx @@ -14,8 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { waitFor } from "@testing-library/react"; -import { renderHook, act } from "@testing-library/react-hooks/dom"; +import { waitFor, renderHook, act } from "@testing-library/react"; import { IRoomDirectoryOptions, MatrixClient } from "matrix-js-sdk/src/matrix"; import { usePublicRoomDirectory } from "../../src/hooks/usePublicRoomDirectory"; diff --git a/test/hooks/useRoomMembers-test.tsx b/test/hooks/useRoomMembers-test.tsx index 1db551acda..c3709f5428 100644 --- a/test/hooks/useRoomMembers-test.tsx +++ b/test/hooks/useRoomMembers-test.tsx @@ -14,8 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { waitFor } from "@testing-library/react"; -import { renderHook, act } from "@testing-library/react-hooks/dom"; +import { waitFor, renderHook, act } from "@testing-library/react"; import { MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix"; import { KnownMembership } from "matrix-js-sdk/src/types"; diff --git a/test/hooks/useSlidingSyncRoomSearch-test.tsx b/test/hooks/useSlidingSyncRoomSearch-test.tsx index 0b21b58575..108afee3db 100644 --- a/test/hooks/useSlidingSyncRoomSearch-test.tsx +++ b/test/hooks/useSlidingSyncRoomSearch-test.tsx @@ -14,8 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { waitFor } from "@testing-library/react"; -import { renderHook, act } from "@testing-library/react-hooks/dom"; +import { waitFor, renderHook, act } from "@testing-library/react"; import { mocked } from "jest-mock"; import { SlidingSync } from "matrix-js-sdk/src/sliding-sync"; import { Room } from "matrix-js-sdk/src/matrix"; diff --git a/test/hooks/useUnreadNotifications-test.ts b/test/hooks/useUnreadNotifications-test.ts index 5a71bee9a5..570506a28e 100644 --- a/test/hooks/useUnreadNotifications-test.ts +++ b/test/hooks/useUnreadNotifications-test.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { renderHook } from "@testing-library/react-hooks"; +import { renderHook } from "@testing-library/react"; import { EventStatus, NotificationCountType, PendingEventOrdering, Room } from "matrix-js-sdk/src/matrix"; import { KnownMembership } from "matrix-js-sdk/src/types"; diff --git a/test/hooks/useUserDirectory-test.tsx b/test/hooks/useUserDirectory-test.tsx index 7bda5cfe0b..72da549d0f 100644 --- a/test/hooks/useUserDirectory-test.tsx +++ b/test/hooks/useUserDirectory-test.tsx @@ -14,8 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { waitFor } from "@testing-library/react"; -import { renderHook, act } from "@testing-library/react-hooks/dom"; +import { waitFor, renderHook, act } from "@testing-library/react"; import { MatrixClient } from "matrix-js-sdk/src/matrix"; import { useUserDirectory } from "../../src/hooks/useUserDirectory"; diff --git a/test/hooks/useUserOnboardingTasks-test.tsx b/test/hooks/useUserOnboardingTasks-test.tsx index 26a2ba4b75..61b2f465d3 100644 --- a/test/hooks/useUserOnboardingTasks-test.tsx +++ b/test/hooks/useUserOnboardingTasks-test.tsx @@ -15,8 +15,7 @@ limitations under the License. */ import React from "react"; -import { renderHook } from "@testing-library/react-hooks"; -import { waitFor } from "@testing-library/react"; +import { renderHook, waitFor } from "@testing-library/react"; import { useUserOnboardingTasks } from "../../src/hooks/useUserOnboardingTasks"; import { useUserOnboardingContext } from "../../src/hooks/useUserOnboardingContext"; diff --git a/test/hooks/useWindowWidth-test.ts b/test/hooks/useWindowWidth-test.ts index bde91c2acb..2a7f305283 100644 --- a/test/hooks/useWindowWidth-test.ts +++ b/test/hooks/useWindowWidth-test.ts @@ -14,8 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { renderHook } from "@testing-library/react-hooks"; -import { act } from "@testing-library/react"; +import { renderHook, act } from "@testing-library/react"; import UIStore, { UI_EVENTS } from "../../src/stores/UIStore"; import { useWindowWidth } from "../../src/hooks/useWindowWidth"; diff --git a/test/languageHandler-test.tsx b/test/languageHandler-test.tsx index a9ad673a70..aeecaa0e18 100644 --- a/test/languageHandler-test.tsx +++ b/test/languageHandler-test.tsx @@ -32,6 +32,8 @@ import { TranslatedString, UserFriendlyError, TranslationKey, + IVariables, + Tags, } from "../src/languageHandler"; import { stubClient } from "./test-utils"; import { setupLanguageMock } from "./setup/setupLanguage"; @@ -214,13 +216,7 @@ describe("languageHandler JSX", function () { const plurals = "common|and_n_others"; const variableSub = "slash_command|ignore_dialog_description"; - type TestCase = [ - string, - TranslationKey, - Record, - Record | undefined, - TranslatedString, - ]; + type TestCase = [string, TranslationKey, IVariables, Tags | undefined, TranslatedString]; const testCasesEn: TestCase[] = [ // description of the test case, translationString, variables, tags, expected result ["translates a basic string", basicString, {}, undefined, "Rooms"], diff --git a/test/modules/ProxiedModuleApi-test.tsx b/test/modules/ProxiedModuleApi-test.tsx index bec6215232..1e98e69508 100644 --- a/test/modules/ProxiedModuleApi-test.tsx +++ b/test/modules/ProxiedModuleApi-test.tsx @@ -118,6 +118,9 @@ describe("ProxiedApiModule", () => { describe("openDialog", () => { it("should open dialog with a custom title and default options", async () => { class MyDialogContent extends DialogContent { + public constructor(props: DialogProps) { + super(props); + } trySubmit = async () => ({ result: true }); render = () =>

This is my example content.

; } @@ -147,6 +150,9 @@ describe("ProxiedApiModule", () => { it("should open dialog with custom options", async () => { class MyDialogContent extends DialogContent { + public constructor(props: DialogProps) { + super(props); + } trySubmit = async () => ({ result: true }); render = () =>

This is my example content.

; } @@ -178,6 +184,9 @@ describe("ProxiedApiModule", () => { it("should update the options from the opened dialog", async () => { class MyDialogContent extends DialogContent { + public constructor(props: DialogProps) { + super(props); + } trySubmit = async () => ({ result: true }); render = () => { const onClick = () => { @@ -231,6 +240,9 @@ describe("ProxiedApiModule", () => { it("should cancel the dialog from within the dialog", async () => { class MyDialogContent extends DialogContent { + public constructor(props: DialogProps) { + super(props); + } trySubmit = async () => ({ result: true }); render = () => (