@@ -2639,7 +2628,6 @@ export class RoomView extends React.Component { { private heightUpdateInProgress = false; public divScroll: HTMLDivElement | null = null; - public constructor(props: IProps) { - super(props); + public static contextType = SDKContext; + declare public context: React.ContextType; + + public constructor(props: IProps, context: React.ContextType) { + super(props, context); this.resetScrollState(); } public componentDidMount(): void { this.unmounted = false; - this.props.resizeNotifier?.on("middlePanelResizedNoisy", this.onResize); + this.context?.resizeNotifier?.on("middlePanelResizedNoisy", this.onResize); this.checkScroll(); } @@ -217,14 +216,14 @@ export default class ScrollPanel extends React.Component { // (We could use isMounted(), but facebook have deprecated that.) this.unmounted = true; - this.props.resizeNotifier?.removeListener("middlePanelResizedNoisy", this.onResize); + this.context?.resizeNotifier?.removeListener("middlePanelResizedNoisy", this.onResize); this.divScroll = null; } private onScroll = (ev: Event): void => { // skip scroll events caused by resizing - if (this.props.resizeNotifier && this.props.resizeNotifier.isResizing) return; + if (this.context?.resizeNotifier && this.context.resizeNotifier.isResizing) return; debuglog("onScroll called past resize gate; scroll node top:", this.getScrollNode().scrollTop); this.scrollTimeout?.restart(); this.saveScrollState(); diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index 59ec657b02..c2aa7f2f10 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -763,7 +763,7 @@ export default class SpaceRoomView extends React.PureComponent { return (
- + {this.renderBody()} diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index 8346a0ab31..c112d341b3 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -47,7 +47,6 @@ import shouldHideEvent from "../../shouldHideEvent"; import MessagePanel from "./MessagePanel"; import { type IScrollState } from "./ScrollPanel"; import { type ActionPayload } from "../../dispatcher/payloads"; -import type ResizeNotifier from "../../utils/ResizeNotifier"; import { type RoomPermalinkCreator } from "../../utils/permalinks/Permalinks"; import Spinner from "../views/elements/Spinner"; import type EditorStateTransfer from "../../utils/EditorStateTransfer"; @@ -123,7 +122,6 @@ interface IProps { // whether to always show timestamps for an event alwaysShowTimestamps?: boolean; - resizeNotifier?: ResizeNotifier; editState?: EditorStateTransfer; permalinkCreator?: RoomPermalinkCreator; membersLoaded?: boolean; @@ -1849,7 +1847,6 @@ class TimelinePanel extends React.Component { this.state.alwaysShowTimestamps } className={this.props.className} - resizeNotifier={this.props.resizeNotifier} getRelationsForEvent={this.getRelationsForEvent} editState={this.props.editState} showReactions={this.props.showReactions} diff --git a/src/components/structures/UserView.tsx b/src/components/structures/UserView.tsx index 58aed9932b..ded92b6eb9 100644 --- a/src/components/structures/UserView.tsx +++ b/src/components/structures/UserView.tsx @@ -87,12 +87,7 @@ export default class UserView extends React.Component { /> ); return ( - + ); diff --git a/src/components/structures/WaitingForThirdPartyRoomView.tsx b/src/components/structures/WaitingForThirdPartyRoomView.tsx index 3983b286f1..a02a807c9b 100644 --- a/src/components/structures/WaitingForThirdPartyRoomView.tsx +++ b/src/components/structures/WaitingForThirdPartyRoomView.tsx @@ -41,7 +41,7 @@ export const WaitingForThirdPartyRoomView: React.FC = ({ roomView, resize
- + { membersLoaded={true} editState={this.state.editState} eventId={this.state.initialEventId} - resizeNotifier={this.props.resizeNotifier} highlightedEventId={highlightedEventId} onScroll={this.onScroll} /> diff --git a/src/components/views/rooms/AppsDrawer.tsx b/src/components/views/rooms/AppsDrawer.tsx index ac6328c3bf..1bfef03963 100644 --- a/src/components/views/rooms/AppsDrawer.tsx +++ b/src/components/views/rooms/AppsDrawer.tsx @@ -27,11 +27,11 @@ import UIStore from "../../../stores/UIStore"; import { type ActionPayload } from "../../../dispatcher/payloads"; import Spinner from "../elements/Spinner"; import SdkConfig from "../../../SdkConfig"; +import { SDKContext } from "../../../contexts/SDKContext"; interface IProps { userId: string; room: Room; - resizeNotifier: ResizeNotifier; showApps?: boolean; // Should apps be rendered maxHeight: number; role?: AriaRole; @@ -57,8 +57,11 @@ export default class AppsDrawer extends React.Component { showApps: true, }; - public constructor(props: IProps) { - super(props); + public static contextType = SDKContext; + declare public context: React.ContextType; + + public constructor(props: IProps, context: React.ContextType) { + super(props, context); this.state = { apps: this.getApps(), @@ -73,7 +76,7 @@ export default class AppsDrawer extends React.Component { public componentDidMount(): void { this.unmounted = false; - this.props.resizeNotifier.on("isResizing", this.onIsResizing); + this.context.resizeNotifier.on("isResizing", this.onIsResizing); ScalarMessaging.startListening(); WidgetLayoutStore.instance.on(WidgetLayoutStore.emissionForRoom(this.props.room), this.updateApps); @@ -88,7 +91,7 @@ export default class AppsDrawer extends React.Component { if (this.resizeContainer) { this.resizer.detach(); } - this.props.resizeNotifier.off("isResizing", this.onIsResizing); + this.context.resizeNotifier.off("isResizing", this.onIsResizing); } private onIsResizing = (resizing: boolean): void => { @@ -281,7 +284,7 @@ export default class AppsDrawer extends React.Component { className="mx_AppsDrawer_resizer" handleWrapperClass="mx_AppsDrawer_resizer_container" handleClass="mx_AppsDrawer_resizer_container_handle" - resizeNotifier={this.props.resizeNotifier} + resizeNotifier={this.context.resizeNotifier} > {appContainers} diff --git a/src/components/views/rooms/AuxPanel.tsx b/src/components/views/rooms/AuxPanel.tsx index 9e34a6f40d..f547c29d2e 100644 --- a/src/components/views/rooms/AuxPanel.tsx +++ b/src/components/views/rooms/AuxPanel.tsx @@ -13,7 +13,6 @@ import AppsDrawer from "./AppsDrawer"; import SettingsStore from "../../../settings/SettingsStore"; import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; import { UIFeature } from "../../../settings/UIFeature"; -import type ResizeNotifier from "../../../utils/ResizeNotifier"; import LegacyCallViewForRoom from "../voip/LegacyCallViewForRoom"; import { objectHasDiff } from "../../../utils/objects"; @@ -22,7 +21,6 @@ interface IProps { room: Room; userId: string; showApps: boolean; // Render apps - resizeNotifier: ResizeNotifier; children?: ReactNode; } @@ -36,23 +34,12 @@ export default class AuxPanel extends React.Component { } public render(): React.ReactNode { - const callView = ( - - ); + const callView = ; let appsDrawer; if (SettingsStore.getValue(UIFeature.Widgets)) { appsDrawer = ( - + ); } diff --git a/src/components/views/rooms/PinnedMessageBanner.tsx b/src/components/views/rooms/PinnedMessageBanner.tsx index 200b35a73d..552aa2a4b2 100644 --- a/src/components/views/rooms/PinnedMessageBanner.tsx +++ b/src/components/views/rooms/PinnedMessageBanner.tsx @@ -6,7 +6,7 @@ * Please see LICENSE files in the repository root for full details. */ -import React, { type JSX, useEffect, useId, useRef, useState } from "react"; +import React, { type JSX, useContext, useEffect, useId, useRef, useState } from "react"; import PinIcon from "@vector-im/compound-design-tokens/assets/web/icons/pin-solid"; import { Button } from "@vector-im/compound-web"; import { type MatrixEvent, type Room } from "matrix-js-sdk/src/matrix"; @@ -25,7 +25,7 @@ import { Action } from "../../../dispatcher/actions"; import MessageEvent from "../messages/MessageEvent"; import PosthogTrackers from "../../../PosthogTrackers.ts"; import { EventPreview } from "./EventPreview.tsx"; -import type ResizeNotifier from "../../../utils/ResizeNotifier"; +import { SDKContext } from "../../../contexts/SDKContext.ts"; /** * The props for the {@link PinnedMessageBanner} component. @@ -39,20 +39,12 @@ interface PinnedMessageBannerProps { * The room where the banner is displayed */ room: Room; - /** - * The resize notifier to notify the timeline to resize itself when the banner is displayed or hidden. - */ - resizeNotifier: ResizeNotifier; } /** * A banner that displays the pinned messages in a room. */ -export function PinnedMessageBanner({ - room, - permalinkCreator, - resizeNotifier, -}: PinnedMessageBannerProps): JSX.Element | null { +export function PinnedMessageBanner({ room, permalinkCreator }: PinnedMessageBannerProps): JSX.Element | null { const pinnedEventIds = usePinnedEvents(room); const pinnedEvents = useSortedFetchedPinnedEvents(room, pinnedEventIds); const eventCount = pinnedEvents.length; @@ -67,7 +59,7 @@ export function PinnedMessageBanner({ const isLastMessage = currentEventIndex === eventCount - 1; const pinnedEvent = pinnedEvents[currentEventIndex]; - useNotifyTimeline(pinnedEvent, resizeNotifier); + useNotifyTimeline(pinnedEvent); const id = useId(); @@ -152,9 +144,10 @@ export function PinnedMessageBanner({ /** * When the banner is displayed or hidden, we want to notify the timeline to resize itself. * @param pinnedEvent - * @param resizeNotifier */ -function useNotifyTimeline(pinnedEvent: MatrixEvent | null, resizeNotifier: ResizeNotifier): void { +function useNotifyTimeline(pinnedEvent: MatrixEvent | null): void { + const resizeNotifier = useContext(SDKContext).resizeNotifier; + const previousEvent = useRef(null); useEffect(() => { // If we switch from a pinned message to no pinned message or the opposite, we want to resize the timeline diff --git a/src/components/views/voip/LegacyCallViewForRoom.tsx b/src/components/views/voip/LegacyCallViewForRoom.tsx index f0bc8ffc22..d996fe98d6 100644 --- a/src/components/views/voip/LegacyCallViewForRoom.tsx +++ b/src/components/views/voip/LegacyCallViewForRoom.tsx @@ -12,14 +12,12 @@ import { Resizable } from "re-resizable"; import LegacyCallHandler, { LegacyCallHandlerEvent } from "../../../LegacyCallHandler"; import LegacyCallView from "./LegacyCallView"; -import type ResizeNotifier from "../../../utils/ResizeNotifier"; +import { SDKContext } from "../../../contexts/SDKContext"; interface IProps { // What room we should display the call for roomId: string; - resizeNotifier: ResizeNotifier; - showApps?: boolean; } @@ -33,8 +31,11 @@ interface IState { * or nothing if there is no call in that room. */ export default class LegacyCallViewForRoom extends React.Component { - public constructor(props: IProps) { - super(props); + public static contextType = SDKContext; + declare public context: React.ContextType; + + public constructor(props: IProps, context: React.ContextType) { + super(props, context); const call = this.getCall(); this.state = { call, @@ -73,15 +74,15 @@ export default class LegacyCallViewForRoom extends React.Component { - this.props.resizeNotifier.startResizing(); + this.context.resizeNotifier.startResizing(); }; private onResize = (): void => { - this.props.resizeNotifier.notifyTimelineHeightChanged(); + this.context.resizeNotifier.notifyTimelineHeightChanged(); }; private onResizeStop = (): void => { - this.props.resizeNotifier.stopResizing(); + this.context.resizeNotifier.stopResizing(); }; private setSidebarShown = (sidebarShown: boolean): void => { diff --git a/src/contexts/SDKContext.ts b/src/contexts/SDKContext.ts index 1b8ede3efd..4e7aa9e94f 100644 --- a/src/contexts/SDKContext.ts +++ b/src/contexts/SDKContext.ts @@ -24,6 +24,7 @@ import { WidgetLayoutStore } from "../stores/widgets/WidgetLayoutStore"; import { WidgetPermissionStore } from "../stores/widgets/WidgetPermissionStore"; import { OidcClientStore } from "../stores/oidc/OidcClientStore"; import WidgetStore from "../stores/WidgetStore"; +import ResizeNotifier from "../utils/ResizeNotifier"; // This context is available to components under MatrixChat, // the context must not be used by components outside a SdkContextClass tree. @@ -64,6 +65,7 @@ export class SdkContextClass { protected _TypingStore?: TypingStore; protected _UserProfilesStore?: UserProfilesStore; protected _OidcClientStore?: OidcClientStore; + protected _ResizeNotifier?: ResizeNotifier; /** * Automatically construct stores which need to be created eagerly so they can register with @@ -171,6 +173,16 @@ export class SdkContextClass { return this._OidcClientStore; } + // This is getting increasingly tenuous to have here but we still have class components so it's + // awkward to consume multiple contexts in them. This should be replaced with ResizeObservers + // anyway really. + public get resizeNotifier(): ResizeNotifier { + if (!this._ResizeNotifier) { + this._ResizeNotifier = new ResizeNotifier(); + } + return this._ResizeNotifier; + } + public onLoggedOut(): void { this._UserProfilesStore = undefined; } diff --git a/test/test-utils/wrappers.tsx b/test/test-utils/wrappers.tsx index 7c4fd4b968..99ceae7f94 100644 --- a/test/test-utils/wrappers.tsx +++ b/test/test-utils/wrappers.tsx @@ -62,3 +62,13 @@ export function withClientContextRenderOptions(client: MatrixClient): RenderOpti ), }; } + +export function clientAndSDKContextRenderOptions(client: MatrixClient, sdkContext: SdkContextClass): RenderOptions { + return { + wrapper: ({ children }) => ( + + {children} + + ), + }; +} diff --git a/test/unit-tests/components/structures/FilePanel-test.tsx b/test/unit-tests/components/structures/FilePanel-test.tsx index 0b9b18c38e..eab6725293 100644 --- a/test/unit-tests/components/structures/FilePanel-test.tsx +++ b/test/unit-tests/components/structures/FilePanel-test.tsx @@ -12,7 +12,6 @@ import { screen, render, waitFor } from "jest-matrix-react"; import { mocked } from "jest-mock"; import FilePanel from "../../../../src/components/structures/FilePanel"; -import ResizeNotifier from "../../../../src/utils/ResizeNotifier"; import { mkEvent, stubClient } from "../../../test-utils"; import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; @@ -39,9 +38,7 @@ describe("FilePanel", () => { room.getOrCreateFilteredTimelineSet = jest.fn().mockReturnValue(timelineSet); mocked(cli.getRoom).mockReturnValue(room); - const { asFragment } = render( - , - ); + const { asFragment } = render(); await waitFor(() => { expect(screen.getByText("No files visible in this room")).toBeInTheDocument(); }); @@ -64,7 +61,6 @@ describe("FilePanel", () => { { filePanel = ref; }} diff --git a/test/unit-tests/components/structures/MainSplit-test.tsx b/test/unit-tests/components/structures/MainSplit-test.tsx index 2feb9b22f6..da3c29cd36 100644 --- a/test/unit-tests/components/structures/MainSplit-test.tsx +++ b/test/unit-tests/components/structures/MainSplit-test.tsx @@ -10,30 +10,26 @@ import React from "react"; import { render, fireEvent } from "jest-matrix-react"; import MainSplit from "../../../../src/components/structures/MainSplit"; -import ResizeNotifier from "../../../../src/utils/ResizeNotifier"; import { PosthogAnalytics } from "../../../../src/PosthogAnalytics.ts"; +import { SDKContext, SdkContextClass } from "../../../../src/contexts/SDKContext.ts"; describe("", () => { - const resizeNotifier = new ResizeNotifier(); const children = (
ChildFooBar
); const panel =
Right panel
; + let sdkContext: SdkContextClass; beforeEach(() => { localStorage.clear(); + sdkContext = new SdkContextClass(); }); it("renders", () => { const { asFragment, container } = render( - , + , ); expect(asFragment()).toMatchSnapshot(); // Assert it matches the default width of 320 @@ -42,13 +38,7 @@ describe("", () => { it("respects defaultSize prop", () => { const { asFragment, container } = render( - , + , ); expect(asFragment()).toMatchSnapshot(); // Assert it matches the default width of 350 @@ -59,7 +49,6 @@ describe("", () => { localStorage.setItem("mx_rhs_size_thread", "333"); const { container } = render( ", () => { it("should report to analytics on resize stop", () => { const { container } = render( , + { wrapper: ({ children }) => {children} }, ); const spy = jest.spyOn(PosthogAnalytics.instance, "trackEvent"); const handle = container.querySelector(".mx_ResizeHandle--horizontal")!; + expect(handle).toBeInTheDocument(); fireEvent.mouseDown(handle); fireEvent.resize(handle, { clientX: 0 }); fireEvent.mouseUp(handle); diff --git a/test/unit-tests/components/structures/MatrixChat-test.tsx b/test/unit-tests/components/structures/MatrixChat-test.tsx index 3ebe826b1c..c772f6b743 100644 --- a/test/unit-tests/components/structures/MatrixChat-test.tsx +++ b/test/unit-tests/components/structures/MatrixChat-test.tsx @@ -307,6 +307,30 @@ describe("", () => { }); }); + it("should notify resizenotifier when left panel hidden", async () => { + getComponent(); + + jest.spyOn(SdkContextClass.instance.resizeNotifier, "notifyLeftHandleResized"); + + defaultDispatcher.dispatch({ action: "hide_left_panel" }); + + await waitFor(() => + expect(mocked(SdkContextClass.instance.resizeNotifier.notifyLeftHandleResized)).toHaveBeenCalled(), + ); + }); + + it("should notify resizenotifier when left panel shown", async () => { + getComponent(); + + jest.spyOn(SdkContextClass.instance.resizeNotifier, "notifyLeftHandleResized"); + + defaultDispatcher.dispatch({ action: "show_left_panel" }); + + await waitFor(() => + expect(mocked(SdkContextClass.instance.resizeNotifier.notifyLeftHandleResized)).toHaveBeenCalled(), + ); + }); + describe("when query params have a OIDC params", () => { const issuer = "https://auth.com/"; const homeserverUrl = "https://matrix.org"; diff --git a/test/unit-tests/components/structures/MessagePanel-test.tsx b/test/unit-tests/components/structures/MessagePanel-test.tsx index ae12768c2f..0f3b40e3f0 100644 --- a/test/unit-tests/components/structures/MessagePanel-test.tsx +++ b/test/unit-tests/components/structures/MessagePanel-test.tsx @@ -15,11 +15,11 @@ import { render } from "jest-matrix-react"; import MessagePanel, { shouldFormContinuation } from "../../../../src/components/structures/MessagePanel"; import SettingsStore from "../../../../src/settings/SettingsStore"; -import MatrixClientContext from "../../../../src/contexts/MatrixClientContext"; import RoomContext, { TimelineRenderingType } from "../../../../src/contexts/RoomContext"; import DMRoomMap from "../../../../src/utils/DMRoomMap"; import * as TestUtilsMatrix from "../../../test-utils"; import { + clientAndSDKContextRenderOptions, createTestClient, getMockClientWithEventEmitter, makeBeaconInfoEvent, @@ -32,6 +32,7 @@ import type ResizeNotifier from "../../../../src/utils/ResizeNotifier"; import { type IRoomState } from "../../../../src/components/structures/RoomView"; import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; import { ScopedRoomContextProvider } from "../../../../src/contexts/ScopedRoomContext.tsx"; +import { SdkContextClass } from "../../../../src/contexts/SDKContext.ts"; jest.mock("../../../../src/utils/beacon", () => ({ useBeacon: jest.fn(), @@ -54,6 +55,7 @@ describe("MessagePanel", function () { getClientWellKnown: jest.fn().mockReturnValue({}), supportsThreads: jest.fn().mockReturnValue(true), }); + let sdkContext: SdkContextClass; jest.spyOn(MatrixClientPeg, "get").mockReturnValue(client); const room = new Room(roomId, client, userId); @@ -93,11 +95,9 @@ describe("MessagePanel", function () { } as unknown as IRoomState; const getComponent = (props = {}, roomContext: Partial = {}) => ( - - - - - + + + ); beforeEach(function () { @@ -107,6 +107,8 @@ describe("MessagePanel", function () { return arg === "showDisplaynameChanges"; }); + sdkContext = new SdkContextClass(); + DMRoomMap.makeShared(client); }); @@ -314,7 +316,7 @@ describe("MessagePanel", function () { } it("should show the events", function () { - const { container } = render(getComponent({ events })); + const { container } = render(getComponent({ events }), clientAndSDKContextRenderOptions(client, sdkContext)); // just check we have the right number of tiles for now const tiles = container.getElementsByClassName("mx_EventTile"); @@ -322,7 +324,10 @@ describe("MessagePanel", function () { }); it("should collapse adjacent member events", function () { - const { container } = render(getComponent({ events: mkMelsEvents() })); + const { container } = render( + getComponent({ events: mkMelsEvents() }), + clientAndSDKContextRenderOptions(client, sdkContext), + ); // just check we have the right number of tiles for now const tiles = container.getElementsByClassName("mx_EventTile"); @@ -339,6 +344,7 @@ describe("MessagePanel", function () { readMarkerEventId: events[4].getId(), readMarkerVisible: true, }), + clientAndSDKContextRenderOptions(client, sdkContext), ); const tiles = container.getElementsByClassName("mx_EventTile"); @@ -359,6 +365,7 @@ describe("MessagePanel", function () { readMarkerEventId: melsEvents[4].getId(), readMarkerVisible: true, }), + clientAndSDKContextRenderOptions(client, sdkContext), ); const [summary] = container.getElementsByClassName("mx_GenericEventListSummary"); @@ -381,6 +388,7 @@ describe("MessagePanel", function () { readMarkerEventId: melsEvents[9].getId(), readMarkerVisible: true, }), + clientAndSDKContextRenderOptions(client, sdkContext), ); const [summary] = container.getElementsByClassName("mx_GenericEventListSummary"); @@ -406,6 +414,7 @@ describe("MessagePanel", function () { readMarkerVisible: true, })}
, + clientAndSDKContextRenderOptions(client, sdkContext), ); const tiles = container.getElementsByClassName("mx_EventTile"); @@ -448,7 +457,7 @@ describe("MessagePanel", function () { client.getRoom.mockImplementation((id) => (id === createEvent!.getRoomId() ? room : null)); TestUtilsMatrix.upsertRoomStateEvents(room, events); - const { container } = render(getComponent({ events })); + const { container } = render(getComponent({ events }), clientAndSDKContextRenderOptions(client, sdkContext)); // we expect that // - the room creation event, the room encryption event, and Alice inviting Bob, @@ -476,7 +485,10 @@ describe("MessagePanel", function () { }); const combinedEvents = [...events, beaconInfoEvent]; TestUtilsMatrix.upsertRoomStateEvents(room, combinedEvents); - const { container } = render(getComponent({ events: combinedEvents })); + const { container } = render( + getComponent({ events: combinedEvents }), + clientAndSDKContextRenderOptions(client, sdkContext), + ); const [summaryTile] = container.getElementsByClassName("mx_GenericEventListSummary"); @@ -498,6 +510,7 @@ describe("MessagePanel", function () { readMarkerEventId: events[5].getId(), readMarkerVisible: true, }), + clientAndSDKContextRenderOptions(client, sdkContext), ); // find the
  • which wraps the read marker @@ -514,7 +527,10 @@ describe("MessagePanel", function () { it("should render Date separators for the events", function () { const events = mkOneDayEvents(); - const { queryAllByRole } = render(getComponent({ events })); + const { queryAllByRole } = render( + getComponent({ events }), + clientAndSDKContextRenderOptions(client, sdkContext), + ); const dates = queryAllByRole("separator"); expect(dates.length).toEqual(1); @@ -523,7 +539,10 @@ describe("MessagePanel", function () { it("appends events into summaries during forward pagination without changing key", () => { const events = mkMelsEvents().slice(1, 11); - const { container, rerender } = render(getComponent({ events })); + const { container, rerender } = render( + getComponent({ events }), + clientAndSDKContextRenderOptions(client, sdkContext), + ); let els = container.getElementsByClassName("mx_GenericEventListSummary"); expect(els.length).toEqual(1); expect(els[0].getAttribute("data-testid")).toEqual("eventlistsummary-" + events[0].getId()); @@ -553,7 +572,10 @@ describe("MessagePanel", function () { it("prepends events into summaries during backward pagination without changing key", () => { const events = mkMelsEvents().slice(1, 11); - const { container, rerender } = render(getComponent({ events })); + const { container, rerender } = render( + getComponent({ events }), + clientAndSDKContextRenderOptions(client, sdkContext), + ); let els = container.getElementsByClassName("mx_GenericEventListSummary"); expect(els.length).toEqual(1); expect(els[0].getAttribute("data-testid")).toEqual("eventlistsummary-" + events[0].getId()); @@ -583,7 +605,10 @@ describe("MessagePanel", function () { it("assigns different keys to summaries that get split up", () => { const events = mkMelsEvents().slice(1, 11); - const { container, rerender } = render(getComponent({ events })); + const { container, rerender } = render( + getComponent({ events }), + clientAndSDKContextRenderOptions(client, sdkContext), + ); let els = container.getElementsByClassName("mx_GenericEventListSummary"); expect(els.length).toEqual(1); expect(els[0].getAttribute("data-testid")).toEqual(`eventlistsummary-${events[0].getId()}`); @@ -616,7 +641,7 @@ describe("MessagePanel", function () { it("doesn't lookup showHiddenEventsInTimeline while rendering", () => { // We're only interested in the setting lookups that happen on every render, // rather than those happening on first mount, so let's get those out of the way - const { rerender } = render(getComponent({ events: [] })); + const { rerender } = render(getComponent({ events: [] }), clientAndSDKContextRenderOptions(client, sdkContext)); // Set up our spy and re-render with new events const settingsSpy = jest.spyOn(SettingsStore, "getValue").mockClear(); @@ -654,7 +679,10 @@ describe("MessagePanel", function () { ts: 3, }), ]; - const { container } = render(getComponent({ events }, { showHiddenEvents: true })); + const { container } = render( + getComponent({ events }, { showHiddenEvents: true }), + clientAndSDKContextRenderOptions(client, sdkContext), + ); const els = container.getElementsByClassName("mx_GenericEventListSummary"); expect(els.length).toEqual(1); @@ -678,7 +706,10 @@ describe("MessagePanel", function () { }), ); } - const { asFragment } = render(getComponent({ events }, { showHiddenEvents: false })); + const { asFragment } = render( + getComponent({ events }, { showHiddenEvents: false }), + clientAndSDKContextRenderOptions(client, sdkContext), + ); expect(asFragment()).toMatchSnapshot(); }); @@ -699,7 +730,10 @@ describe("MessagePanel", function () { }), ); } - const { asFragment } = render(getComponent({ events }, { showHiddenEvents: false })); + const { asFragment } = render( + getComponent({ events }, { showHiddenEvents: false }), + clientAndSDKContextRenderOptions(client, sdkContext), + ); expect(asFragment()).toMatchSnapshot(); }); @@ -720,7 +754,10 @@ describe("MessagePanel", function () { }), ); } - const { asFragment } = render(getComponent({ events }, { showHiddenEvents: true })); + const { asFragment } = render( + getComponent({ events }, { showHiddenEvents: true }), + clientAndSDKContextRenderOptions(client, sdkContext), + ); const cpt = asFragment(); // Ignore properties that change every time @@ -751,7 +788,10 @@ describe("MessagePanel", function () { content: { topic: "TOPIC" }, }), ]; - const { container } = render(getComponent({ events, showReadReceipts: true })); + const { container } = render( + getComponent({ events, showReadReceipts: true }), + clientAndSDKContextRenderOptions(client, sdkContext), + ); const tiles = container.getElementsByClassName("mx_EventTile"); expect(tiles.length).toEqual(2); @@ -784,7 +824,10 @@ describe("MessagePanel", function () { }, true, ); - const { container } = render(getComponent({ events, showReadReceipts: true })); + const { container } = render( + getComponent({ events, showReadReceipts: true }), + clientAndSDKContextRenderOptions(client, sdkContext), + ); const tiles = container.getElementsByClassName("mx_EventTile"); expect(tiles.length).toEqual(2); diff --git a/test/unit-tests/components/structures/RoomSearchView-test.tsx b/test/unit-tests/components/structures/RoomSearchView-test.tsx index ab52e8012b..ab939a026b 100644 --- a/test/unit-tests/components/structures/RoomSearchView-test.tsx +++ b/test/unit-tests/components/structures/RoomSearchView-test.tsx @@ -20,11 +20,11 @@ import { } from "matrix-js-sdk/src/matrix"; import { RoomSearchView } from "../../../../src/components/structures/RoomSearchView"; -import ResizeNotifier from "../../../../src/utils/ResizeNotifier"; -import { stubClient } from "../../../test-utils"; +import { clientAndSDKContextRenderOptions, stubClient } from "../../../test-utils"; import MatrixClientContext from "../../../../src/contexts/MatrixClientContext"; import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; import { searchPagination, SearchScope } from "../../../../src/Searching"; +import { SdkContextClass } from "../../../../src/contexts/SDKContext"; jest.mock("../../../../src/Searching", () => ({ searchPagination: jest.fn(), @@ -33,13 +33,14 @@ jest.mock("../../../../src/Searching", () => ({ describe("", () => { const eventMapper = (obj: Partial) => new MatrixEvent(obj); - const resizeNotifier = new ResizeNotifier(); let client: MatrixClient; + let sdkContext: SdkContextClass; let room: Room; beforeEach(async () => { stubClient(); client = MatrixClientPeg.safeGet(); + sdkContext = new SdkContextClass(); client.supportsThreads = jest.fn().mockReturnValue(true); room = new Room("!room:server", client, client.getSafeUserId()); mocked(client.getRoom).mockReturnValue(room); @@ -60,7 +61,6 @@ describe("", () => { term="search term" scope={SearchScope.All} promise={deferred.promise} - resizeNotifier={resizeNotifier} className="someClass" onUpdate={jest.fn()} />, @@ -71,59 +71,57 @@ describe("", () => { it("should render results when the promise resolves", async () => { render( - - ({ - results: [ - SearchResult.fromJson( - { - rank: 1, - result: { - room_id: room.roomId, - event_id: "$2", - sender: client.getSafeUserId(), - origin_server_ts: 1, - content: { body: "Foo Test Bar", msgtype: "m.text" }, - type: EventType.RoomMessage, - }, - context: { - profile_info: {}, - events_before: [ - { - room_id: room.roomId, - event_id: "$1", - sender: client.getSafeUserId(), - origin_server_ts: 1, - content: { body: "Before", msgtype: "m.text" }, - type: EventType.RoomMessage, - }, - ], - events_after: [ - { - room_id: room.roomId, - event_id: "$3", - sender: client.getSafeUserId(), - origin_server_ts: 1, - content: { body: "After", msgtype: "m.text" }, - type: EventType.RoomMessage, - }, - ], - }, + ({ + results: [ + SearchResult.fromJson( + { + rank: 1, + result: { + room_id: room.roomId, + event_id: "$2", + sender: client.getSafeUserId(), + origin_server_ts: 1, + content: { body: "Foo Test Bar", msgtype: "m.text" }, + type: EventType.RoomMessage, }, - eventMapper, - ), - ], - highlights: [], - count: 1, - })} - resizeNotifier={resizeNotifier} - className="someClass" - onUpdate={jest.fn()} - /> - , + context: { + profile_info: {}, + events_before: [ + { + room_id: room.roomId, + event_id: "$1", + sender: client.getSafeUserId(), + origin_server_ts: 1, + content: { body: "Before", msgtype: "m.text" }, + type: EventType.RoomMessage, + }, + ], + events_after: [ + { + room_id: room.roomId, + event_id: "$3", + sender: client.getSafeUserId(), + origin_server_ts: 1, + content: { body: "After", msgtype: "m.text" }, + type: EventType.RoomMessage, + }, + ], + }, + }, + eventMapper, + ), + ], + highlights: [], + count: 1, + })} + className="someClass" + onUpdate={jest.fn()} + />, + clientAndSDKContextRenderOptions(client, sdkContext), ); await screen.findByText("Before"); @@ -133,41 +131,39 @@ describe("", () => { it("should highlight words correctly", async () => { render( - - ({ - results: [ - SearchResult.fromJson( - { - rank: 1, - result: { - room_id: room.roomId, - event_id: "$2", - sender: client.getSafeUserId(), - origin_server_ts: 1, - content: { body: "Foo Test Bar", msgtype: "m.text" }, - type: EventType.RoomMessage, - }, - context: { - profile_info: {}, - events_before: [], - events_after: [], - }, + ({ + results: [ + SearchResult.fromJson( + { + rank: 1, + result: { + room_id: room.roomId, + event_id: "$2", + sender: client.getSafeUserId(), + origin_server_ts: 1, + content: { body: "Foo Test Bar", msgtype: "m.text" }, + type: EventType.RoomMessage, }, - eventMapper, - ), - ], - highlights: ["test"], - count: 1, - })} - resizeNotifier={resizeNotifier} - className="someClass" - onUpdate={jest.fn()} - /> - , + context: { + profile_info: {}, + events_before: [], + events_after: [], + }, + }, + eventMapper, + ), + ], + highlights: ["test"], + count: 1, + })} + className="someClass" + onUpdate={jest.fn()} + />, + clientAndSDKContextRenderOptions(client, sdkContext), ); const text = await screen.findByText("Test"); @@ -231,17 +227,15 @@ describe("", () => { const onUpdate = jest.fn(); const { rerender } = render( - - - , + , + clientAndSDKContextRenderOptions(client, sdkContext), ); await screen.findByRole("progressbar"); @@ -249,17 +243,14 @@ describe("", () => { expect(onUpdate).toHaveBeenCalledWith(false, expect.objectContaining({}), null); rerender( - - - , + , ); expect(screen.queryByRole("progressbar")).toBeFalsy(); @@ -275,7 +266,6 @@ describe("", () => { term="search term" scope={SearchScope.All} promise={deferred.promise} - resizeNotifier={resizeNotifier} className="someClass" onUpdate={jest.fn()} /> @@ -299,7 +289,6 @@ describe("", () => { term="search term" scope={SearchScope.All} promise={deferred.promise} - resizeNotifier={resizeNotifier} className="someClass" onUpdate={jest.fn()} /> @@ -324,7 +313,6 @@ describe("", () => { term="search term" scope={SearchScope.All} promise={deferred.promise} - resizeNotifier={resizeNotifier} className="someClass" onUpdate={onUpdate} /> @@ -424,17 +412,15 @@ describe("", () => { }; render( - - - , + , + clientAndSDKContextRenderOptions(client, sdkContext), ); const beforeNode = await screen.findByText("Before"); @@ -459,98 +445,96 @@ describe("", () => { ); render( - - ({ - results: [ - SearchResult.fromJson( - { - rank: 1, - result: { - room_id: room.roomId, - event_id: "$2", - sender: client.getSafeUserId(), - origin_server_ts: 1, - content: { body: "Room 1", msgtype: "m.text" }, - type: EventType.RoomMessage, - }, - context: { - profile_info: {}, - events_before: [], - events_after: [], - }, + ({ + results: [ + SearchResult.fromJson( + { + rank: 1, + result: { + room_id: room.roomId, + event_id: "$2", + sender: client.getSafeUserId(), + origin_server_ts: 1, + content: { body: "Room 1", msgtype: "m.text" }, + type: EventType.RoomMessage, }, - eventMapper, - ), - SearchResult.fromJson( - { - rank: 2, - result: { - room_id: room2.roomId, - event_id: "$22", - sender: client.getSafeUserId(), - origin_server_ts: 1, - content: { body: "Room 2", msgtype: "m.text" }, - type: EventType.RoomMessage, - }, - context: { - profile_info: {}, - events_before: [], - events_after: [], - }, + context: { + profile_info: {}, + events_before: [], + events_after: [], }, - eventMapper, - ), - SearchResult.fromJson( - { - rank: 2, - result: { - room_id: room2.roomId, - event_id: "$23", - sender: client.getSafeUserId(), - origin_server_ts: 2, - content: { body: "Room 2 message 2", msgtype: "m.text" }, - type: EventType.RoomMessage, - }, - context: { - profile_info: {}, - events_before: [], - events_after: [], - }, + }, + eventMapper, + ), + SearchResult.fromJson( + { + rank: 2, + result: { + room_id: room2.roomId, + event_id: "$22", + sender: client.getSafeUserId(), + origin_server_ts: 1, + content: { body: "Room 2", msgtype: "m.text" }, + type: EventType.RoomMessage, }, - eventMapper, - ), - SearchResult.fromJson( - { - rank: 3, - result: { - room_id: room3.roomId, - event_id: "$32", - sender: client.getSafeUserId(), - origin_server_ts: 1, - content: { body: "Room 3", msgtype: "m.text" }, - type: EventType.RoomMessage, - }, - context: { - profile_info: {}, - events_before: [], - events_after: [], - }, + context: { + profile_info: {}, + events_before: [], + events_after: [], }, - eventMapper, - ), - ], - highlights: [], - count: 1, - })} - resizeNotifier={resizeNotifier} - className="someClass" - onUpdate={jest.fn()} - /> - , + }, + eventMapper, + ), + SearchResult.fromJson( + { + rank: 2, + result: { + room_id: room2.roomId, + event_id: "$23", + sender: client.getSafeUserId(), + origin_server_ts: 2, + content: { body: "Room 2 message 2", msgtype: "m.text" }, + type: EventType.RoomMessage, + }, + context: { + profile_info: {}, + events_before: [], + events_after: [], + }, + }, + eventMapper, + ), + SearchResult.fromJson( + { + rank: 3, + result: { + room_id: room3.roomId, + event_id: "$32", + sender: client.getSafeUserId(), + origin_server_ts: 1, + content: { body: "Room 3", msgtype: "m.text" }, + type: EventType.RoomMessage, + }, + context: { + profile_info: {}, + events_before: [], + events_after: [], + }, + }, + eventMapper, + ), + ], + highlights: [], + count: 1, + })} + className="someClass" + onUpdate={jest.fn()} + />, + clientAndSDKContextRenderOptions(client, sdkContext), ); const event1 = await screen.findByText("Room 1"); diff --git a/test/unit-tests/components/structures/RoomView-test.tsx b/test/unit-tests/components/structures/RoomView-test.tsx index bb722e6f51..b0efc27dda 100644 --- a/test/unit-tests/components/structures/RoomView-test.tsx +++ b/test/unit-tests/components/structures/RoomView-test.tsx @@ -55,7 +55,6 @@ import { Action } from "../../../../src/dispatcher/actions"; import defaultDispatcher from "../../../../src/dispatcher/dispatcher"; import { type ViewRoomPayload } from "../../../../src/dispatcher/payloads/ViewRoomPayload"; import { RoomView } from "../../../../src/components/structures/RoomView"; -import ResizeNotifier from "../../../../src/utils/ResizeNotifier"; import SettingsStore from "../../../../src/settings/SettingsStore"; import { SettingLevel } from "../../../../src/settings/SettingLevel"; import DMRoomMap from "../../../../src/utils/DMRoomMap"; @@ -157,7 +156,6 @@ describe("RoomView", () => { // threepidInvite should be optional on RoomView props // it is treated as optional in RoomView threepidInvite={undefined as any} - resizeNotifier={new ResizeNotifier()} forceTimeline={false} ref={ref} /> @@ -196,7 +194,6 @@ describe("RoomView", () => { // threepidInvite should be optional on RoomView props // it is treated as optional in RoomView threepidInvite={undefined} - resizeNotifier={new ResizeNotifier()} forceTimeline={false} onRegistered={jest.fn()} /> diff --git a/test/unit-tests/components/structures/TimelinePanel-test.tsx b/test/unit-tests/components/structures/TimelinePanel-test.tsx index 354036e282..3602dd8322 100644 --- a/test/unit-tests/components/structures/TimelinePanel-test.tsx +++ b/test/unit-tests/components/structures/TimelinePanel-test.tsx @@ -33,15 +33,14 @@ import { type Mocked, mocked } from "jest-mock"; import { forEachRight } from "lodash"; import TimelinePanel from "../../../../src/components/structures/TimelinePanel"; -import MatrixClientContext from "../../../../src/contexts/MatrixClientContext"; import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; import { + clientAndSDKContextRenderOptions, filterConsole, flushPromises, mkMembership, mkRoom, stubClient, - withClientContextRenderOptions, } from "../../../test-utils"; import { mkThread } from "../../../test-utils/threads"; import { createMessageEventContent } from "../../../test-utils/events"; @@ -51,6 +50,7 @@ import defaultDispatcher from "../../../../src/dispatcher/dispatcher"; import { Action } from "../../../../src/dispatcher/actions"; import { SettingLevel } from "../../../../src/settings/SettingLevel"; import MatrixClientBackedController from "../../../../src/settings/controllers/MatrixClientBackedController"; +import { SdkContextClass } from "../../../../src/contexts/SDKContext"; // ScrollPanel calls this, but jsdom doesn't mock it for us HTMLDivElement.prototype.scrollBy = () => {}; @@ -159,6 +159,7 @@ const setupPagination = ( describe("TimelinePanel", () => { let client: Mocked; + let sdkContext: SdkContextClass; let userId: string; filterConsole("checkForPreJoinUISI: showing all messages, skipping check"); @@ -166,6 +167,7 @@ describe("TimelinePanel", () => { beforeEach(() => { client = mocked(stubClient()); userId = client.getSafeUserId(); + sdkContext = new SdkContextClass(); }); describe("read receipts and markers", () => { @@ -200,7 +202,7 @@ describe("TimelinePanel", () => { timelinePanel = ref; }} />, - withClientContextRenderOptions(MatrixClientPeg.safeGet()), + clientAndSDKContextRenderOptions(client, sdkContext), ); await flushPromises(); await waitFor(() => expect(timelinePanel).toBeTruthy()); @@ -396,7 +398,7 @@ describe("TimelinePanel", () => { await withScrollPanelMountSpy(async (mountSpy) => { const { container } = render( , - withClientContextRenderOptions(MatrixClientPeg.safeGet()), + clientAndSDKContextRenderOptions(client, sdkContext), ); await waitFor(() => expectEvents(container, [events[1]])); @@ -416,7 +418,7 @@ describe("TimelinePanel", () => { await withScrollPanelMountSpy(async (mountSpy) => { const { container } = render( , - withClientContextRenderOptions(MatrixClientPeg.safeGet()), + clientAndSDKContextRenderOptions(client, sdkContext), ); await waitFor(() => expectEvents(container, [events[0], events[1]])); @@ -493,7 +495,7 @@ describe("TimelinePanel", () => { const paginateSpy = jest.spyOn(TimelineWindow.prototype, "paginate").mockClear(); - render(); + render(, clientAndSDKContextRenderOptions(client, sdkContext)); const event = new MatrixEvent({ type: RoomEvent.Timeline, origin_server_ts: 0 }); const data = { timeline: props.timelineSet.getLiveTimeline(), liveEvent: true }; @@ -590,9 +592,8 @@ describe("TimelinePanel", () => { const replyToEvent = jest.spyOn(thread, "replyToEvent", "get"); const dom = render( - - - , + , + clientAndSDKContextRenderOptions(client, sdkContext), ); await dom.findByText("RootEvent"); await dom.findByText("ReplyEvent1"); @@ -645,9 +646,8 @@ describe("TimelinePanel", () => { }; const dom = render( - - - , + , + clientAndSDKContextRenderOptions(client, sdkContext), ); await dom.findByText("RootEvent"); await dom.findByText("ReplyEvent1"); @@ -718,9 +718,8 @@ describe("TimelinePanel", () => { } const { container } = render( - - - , + , + clientAndSDKContextRenderOptions(client, sdkContext), ); await waitFor(() => expect(screen.queryByRole("progressbar")).toBeNull()); @@ -740,7 +739,7 @@ describe("TimelinePanel", () => { await withScrollPanelMountSpy(async () => { const { container } = render( , - withClientContextRenderOptions(MatrixClientPeg.safeGet()), + clientAndSDKContextRenderOptions(client, sdkContext), ); await waitFor(() => expectEvents(container, [events[1]])); diff --git a/test/unit-tests/components/views/dialogs/MessageEditHistoryDialog-test.tsx b/test/unit-tests/components/views/dialogs/MessageEditHistoryDialog-test.tsx index 2f0b0a4974..028c415932 100644 --- a/test/unit-tests/components/views/dialogs/MessageEditHistoryDialog-test.tsx +++ b/test/unit-tests/components/views/dialogs/MessageEditHistoryDialog-test.tsx @@ -13,10 +13,12 @@ import { EventType, MatrixEvent } from "matrix-js-sdk/src/matrix"; import type { MatrixClient } from "matrix-js-sdk/src/matrix"; import { flushPromises, mkMessage, stubClient } from "../../../../test-utils"; import MessageEditHistoryDialog from "../../../../../src/components/views/dialogs/MessageEditHistoryDialog"; +import { SDKContext, SdkContextClass } from "../../../../../src/contexts/SDKContext"; describe("", () => { const roomId = "!aroom:example.com"; let client: jest.Mocked; + let sdkContext: SdkContextClass; let event: MatrixEvent; beforeEach(() => { @@ -27,10 +29,13 @@ describe("", () => { room: "!room:example.com", msg: "My Great Message", }); + sdkContext = new SdkContextClass(); }); async function renderComponent(): Promise { - const result = render(); + const result = render(, { + wrapper: ({ children }) => {children}, + }); await waitForElementToBeRemoved(() => result.queryByRole("progressbar")); await flushPromises(); return result; diff --git a/test/unit-tests/components/views/elements/AppTile-test.tsx b/test/unit-tests/components/views/elements/AppTile-test.tsx index 039cd09631..e62d1adab9 100644 --- a/test/unit-tests/components/views/elements/AppTile-test.tsx +++ b/test/unit-tests/components/views/elements/AppTile-test.tsx @@ -21,7 +21,7 @@ import { import RightPanel from "../../../../../src/components/structures/RightPanel"; import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg"; import ResizeNotifier from "../../../../../src/utils/ResizeNotifier"; -import { stubClient } from "../../../../test-utils"; +import { clientAndSDKContextRenderOptions, stubClient } from "../../../../test-utils"; import { Action } from "../../../../../src/dispatcher/actions"; import dis from "../../../../../src/dispatcher/dispatcher"; import DMRoomMap from "../../../../../src/utils/DMRoomMap"; @@ -39,6 +39,7 @@ import { ElementWidget } from "../../../../../src/stores/widgets/StopGapWidget"; import { WidgetMessagingStore } from "../../../../../src/stores/widgets/WidgetMessagingStore"; import { ModuleRunner } from "../../../../../src/modules/ModuleRunner"; import { RoomPermalinkCreator } from "../../../../../src/utils/permalinks/Permalinks"; +import { SdkContextClass } from "../../../../../src/contexts/SDKContext"; jest.mock("../../../../../src/stores/OwnProfileStore", () => ({ OwnProfileStore: { @@ -53,6 +54,7 @@ jest.mock("../../../../../src/stores/OwnProfileStore", () => ({ describe("AppTile", () => { let cli: MatrixClient; + let sdkContext: SdkContextClass; let r1: Room; let r2: Room; const resizeNotifier = new ResizeNotifier(); @@ -116,6 +118,7 @@ describe("AppTile", () => { }); beforeEach(() => { + sdkContext = new SdkContextClass(); jest.spyOn(SettingsStore, "getValue").mockRestore(); }); @@ -299,9 +302,8 @@ describe("AppTile", () => { // Run initial render with room 1, and also running lifecycle methods const renderResult = render( - - - , + , + clientAndSDKContextRenderOptions(cli, sdkContext), ); expect(renderResult.getByText("Example 1")).toBeInTheDocument(); diff --git a/test/unit-tests/components/views/rooms/AppsDrawer-test.tsx b/test/unit-tests/components/views/rooms/AppsDrawer-test.tsx index 14c8bde3a2..38efbc1eb8 100644 --- a/test/unit-tests/components/views/rooms/AppsDrawer-test.tsx +++ b/test/unit-tests/components/views/rooms/AppsDrawer-test.tsx @@ -13,23 +13,23 @@ import { render } from "jest-matrix-react"; import { stubClient } from "../../../../test-utils"; import AppsDrawer from "../../../../../src/components/views/rooms/AppsDrawer"; import SdkConfig from "../../../../../src/SdkConfig"; -import ResizeNotifier from "../../../../../src/utils/ResizeNotifier"; import { WidgetLayoutStore } from "../../../../../src/stores/widgets/WidgetLayoutStore"; import MatrixClientContext from "../../../../../src/contexts/MatrixClientContext"; +import { SDKContext, SdkContextClass } from "../../../../../src/contexts/SDKContext"; const ROOM_ID = "!room:id"; describe("AppsDrawer", () => { let client: MatrixClient; let room: Room; - let dummyResizeNotifier: ResizeNotifier; + let sdkContext: SdkContextClass; beforeEach(async () => { client = stubClient(); room = new Room(ROOM_ID, client, client.getUserId()!, { pendingEventOrdering: PendingEventOrdering.Detached, }); - dummyResizeNotifier = new ResizeNotifier(); + sdkContext = new SdkContextClass(); }); afterEach(() => { @@ -58,17 +58,13 @@ describe("AppsDrawer", () => { return []; }); - const { container } = render( - , - { - wrapper: ({ ...rest }) => , - }, - ); + const { container } = render(, { + wrapper: ({ ...rest }) => ( + + + + ), + }); const appsDrawerResizer = container.getElementsByClassName("mx_AppsDrawer_resizer")[0] as HTMLElement; expect(appsDrawerResizer.style.height).toBe("500px"); diff --git a/test/unit-tests/components/views/rooms/PinnedMessageBanner-test.tsx b/test/unit-tests/components/views/rooms/PinnedMessageBanner-test.tsx index 68a850affd..da6ba71e90 100644 --- a/test/unit-tests/components/views/rooms/PinnedMessageBanner-test.tsx +++ b/test/unit-tests/components/views/rooms/PinnedMessageBanner-test.tsx @@ -14,13 +14,13 @@ import userEvent from "@testing-library/user-event"; import * as pinnedEventHooks from "../../../../../src/hooks/usePinnedEvents"; import { PinnedMessageBanner } from "../../../../../src/components/views/rooms/PinnedMessageBanner"; import { RoomPermalinkCreator } from "../../../../../src/utils/permalinks/Permalinks"; -import { makePollStartEvent, stubClient, withClientContextRenderOptions } from "../../../../test-utils"; +import { makePollStartEvent, stubClient, clientAndSDKContextRenderOptions } from "../../../../test-utils"; import dis from "../../../../../src/dispatcher/dispatcher"; import RightPanelStore from "../../../../../src/stores/right-panel/RightPanelStore"; import { RightPanelPhases } from "../../../../../src/stores/right-panel/RightPanelStorePhases"; import { UPDATE_EVENT } from "../../../../../src/stores/AsyncStore"; import { Action } from "../../../../../src/dispatcher/actions"; -import ResizeNotifier from "../../../../../src/utils/ResizeNotifier.ts"; +import { SdkContextClass } from "../../../../../src/contexts/SDKContext.ts"; describe("", () => { const userId = "@alice:server.org"; @@ -29,12 +29,12 @@ describe("", () => { let mockClient: MatrixClient; let room: Room; let permalinkCreator: RoomPermalinkCreator; - let resizeNotifier: ResizeNotifier; + let sdkContext: SdkContextClass; beforeEach(() => { mockClient = stubClient(); room = new Room(roomId, mockClient, userId); permalinkCreator = new RoomPermalinkCreator(room); - resizeNotifier = new ResizeNotifier(); + sdkContext = new SdkContextClass(); jest.spyOn(dis, "dispatch").mockReturnValue(undefined); }); @@ -80,8 +80,8 @@ describe("", () => { */ function renderBanner() { return render( - , - withClientContextRenderOptions(mockClient), + , + clientAndSDKContextRenderOptions(mockClient, sdkContext), ); } @@ -153,9 +153,7 @@ describe("", () => { event3.getId()!, ]); jest.spyOn(pinnedEventHooks, "useSortedFetchedPinnedEvents").mockReturnValue([event1, event2, event3]); - rerender( - , - ); + rerender(); await expect(screen.findByText("Third pinned message")).resolves.toBeVisible(); expect(asFragment()).toMatchSnapshot(); }); @@ -226,7 +224,7 @@ describe("", () => { describe("Notify the timeline to resize", () => { beforeEach(() => { - jest.spyOn(resizeNotifier, "notifyTimelineHeightChanged"); + jest.spyOn(sdkContext.resizeNotifier, "notifyTimelineHeightChanged"); jest.spyOn(pinnedEventHooks, "usePinnedEvents").mockReturnValue([event1.getId()!, event2.getId()!]); jest.spyOn(pinnedEventHooks, "useSortedFetchedPinnedEvents").mockReturnValue([event1, event2]); }); @@ -235,7 +233,7 @@ describe("", () => { renderBanner(); await expect(screen.findByText("Second pinned message")).resolves.toBeVisible(); // The banner is displayed, so we need to resize the timeline - expect(resizeNotifier.notifyTimelineHeightChanged).toHaveBeenCalledTimes(1); + expect(sdkContext.resizeNotifier.notifyTimelineHeightChanged).toHaveBeenCalledTimes(1); await userEvent.click( screen.getByRole("button", { @@ -244,23 +242,21 @@ describe("", () => { ); await expect(screen.findByText("First pinned message")).resolves.toBeVisible(); // The banner is already displayed, so we don't need to resize the timeline - expect(resizeNotifier.notifyTimelineHeightChanged).toHaveBeenCalledTimes(1); + expect(sdkContext.resizeNotifier.notifyTimelineHeightChanged).toHaveBeenCalledTimes(1); }); it("should notify the timeline to resize when we hide the banner", async () => { const { rerender } = renderBanner(); await expect(screen.findByText("Second pinned message")).resolves.toBeVisible(); // The banner is displayed, so we need to resize the timeline - expect(resizeNotifier.notifyTimelineHeightChanged).toHaveBeenCalledTimes(1); + expect(sdkContext.resizeNotifier.notifyTimelineHeightChanged).toHaveBeenCalledTimes(1); // The banner has no event to display and is hidden jest.spyOn(pinnedEventHooks, "usePinnedEvents").mockReturnValue([]); jest.spyOn(pinnedEventHooks, "useSortedFetchedPinnedEvents").mockReturnValue([]); - rerender( - , - ); + rerender(); // The timeline should be resized - expect(resizeNotifier.notifyTimelineHeightChanged).toHaveBeenCalledTimes(2); + expect(sdkContext.resizeNotifier.notifyTimelineHeightChanged).toHaveBeenCalledTimes(2); }); }); diff --git a/test/unit-tests/components/views/voip/LegacyCallViewForRoom-test.tsx b/test/unit-tests/components/views/voip/LegacyCallViewForRoom-test.tsx index c3514d1aae..2739c31257 100644 --- a/test/unit-tests/components/views/voip/LegacyCallViewForRoom-test.tsx +++ b/test/unit-tests/components/views/voip/LegacyCallViewForRoom-test.tsx @@ -6,7 +6,7 @@ Please see LICENSE files in the repository root for full details. */ import React from "react"; -import { render } from "jest-matrix-react"; +import { fireEvent, render, waitFor } from "jest-matrix-react"; import { MatrixCall } from "matrix-js-sdk/src/webrtc/call"; import { CallEventHandlerEvent } from "matrix-js-sdk/src/webrtc/callEventHandler"; @@ -15,19 +15,22 @@ import LegacyCallViewForRoom from "../../../../../src/components/views/voip/Lega import { mkStubRoom, stubClient } from "../../../../test-utils"; import DMRoomMap from "../../../../../src/utils/DMRoomMap"; import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg"; -import ResizeNotifier from "../../../../../src/utils/ResizeNotifier"; import LegacyCallHandler from "../../../../../src/LegacyCallHandler"; +import { SDKContext, SdkContextClass } from "../../../../../src/contexts/SDKContext"; jest.mock("../../../../../src/components/views/voip/LegacyCallView", () => jest.fn(() => "LegacyCallView")); describe("LegacyCallViewForRoom", () => { const LegacyCallViewMock = LegacyCallView as unknown as jest.Mock; + let sdkContext: SdkContextClass; + beforeEach(() => { + stubClient(); + sdkContext = new SdkContextClass(); LegacyCallViewMock.mockClear(); }); - it("should remember sidebar state, defaulting to shown", async () => { - stubClient(); + it("should remember sidebar state, defaulting to shown", async () => { const callHandler = new LegacyCallHandler(); callHandler.start(); jest.spyOn(LegacyCallHandler, "instance", "get").mockImplementation(() => callHandler); @@ -45,16 +48,14 @@ describe("LegacyCallViewForRoom", () => { const cli = MatrixClientPeg.safeGet(); cli.emit(CallEventHandlerEvent.Incoming, call); - const { rerender } = render( - , - ); + const { rerender } = render(); let props = LegacyCallViewMock.mock.lastCall![0]; expect(props.sidebarShown).toBeTruthy(); // Sidebar defaults to shown props.setSidebarShown(false); // Hide the sidebar - rerender(); + rerender(); console.log(LegacyCallViewMock.mock); @@ -64,9 +65,47 @@ describe("LegacyCallViewForRoom", () => { rerender(
    ); // Destroy the LegacyCallViewForRoom and LegacyCallView LegacyCallViewMock.mockClear(); // Drop stored LegacyCallView props - rerender(); + rerender(); props = LegacyCallViewMock.mock.lastCall![0]; expect(props.sidebarShown).toBeFalsy(); // Value was remembered }); + + it("should notify on resize start events", async () => { + const call = new MatrixCall({ + client: MatrixClientPeg.safeGet(), + roomId: "test-room", + }); + + const callHandler = { + getCallForRoom: jest.fn().mockReturnValue(call), + isCallSidebarShown: jest.fn().mockReturnValue(true), + addListener: jest.fn(), + removeListener: jest.fn(), + }; + jest.spyOn(LegacyCallHandler, "instance", "get").mockImplementation( + () => callHandler as unknown as LegacyCallHandler, + ); + + jest.spyOn(sdkContext.resizeNotifier, "startResizing"); + jest.spyOn(sdkContext.resizeNotifier, "stopResizing"); + jest.spyOn(sdkContext.resizeNotifier, "notifyTimelineHeightChanged"); + + const { container } = render(, { + wrapper: ({ children }) => {children}, + }); + + const resizer = container.querySelector(".mx_LegacyCallViewForRoom_ResizeHandle"); + await waitFor(() => { + expect(resizer).toBeInTheDocument(); + }); + + fireEvent.mouseDown(resizer!); + fireEvent.mouseMove(resizer!, { clientY: 100 }); + fireEvent.mouseUp(resizer!); + + expect(sdkContext.resizeNotifier.startResizing).toHaveBeenCalled(); + expect(sdkContext.resizeNotifier.stopResizing).toHaveBeenCalled(); + expect(sdkContext.resizeNotifier.notifyTimelineHeightChanged).toHaveBeenCalled(); + }); });