Merge pull request #3479 from robintown/fix-reconnect

Fix the reconnect button
This commit is contained in:
Robin
2025-09-12 15:05:47 +02:00
committed by GitHub
4 changed files with 32 additions and 9 deletions

View File

@@ -132,9 +132,10 @@ test("ConnectionLostError: Action handling should reset error state", async () =
const WrapComponent = (): ReactNode => { const WrapComponent = (): ReactNode => {
const [failState, setFailState] = useState(true); const [failState, setFailState] = useState(true);
const reconnectCallback = useCallback( const reconnectCallback = useCallback(
(action: CallErrorRecoveryAction) => { async (action: CallErrorRecoveryAction) => {
reconnectCallbackSpy(action); reconnectCallbackSpy(action);
setFailState(false); setFailState(false);
return Promise.resolve();
}, },
[setFailState], [setFailState],
); );

View File

@@ -36,7 +36,9 @@ import { type WidgetHelpers } from "../widget.ts";
export type CallErrorRecoveryAction = "reconnect"; // | "retry" ; export type CallErrorRecoveryAction = "reconnect"; // | "retry" ;
export type RecoveryActionHandler = (action: CallErrorRecoveryAction) => void; export type RecoveryActionHandler = (
action: CallErrorRecoveryAction,
) => Promise<void>;
interface ErrorPageProps { interface ErrorPageProps {
error: ElementCallError; error: ElementCallError;
@@ -71,7 +73,7 @@ const ErrorPage: FC<ErrorPageProps> = ({
if (error instanceof ConnectionLostError) { if (error instanceof ConnectionLostError) {
actions.push({ actions.push({
label: t("call_ended_view.reconnect_button"), label: t("call_ended_view.reconnect_button"),
onClick: () => recoveryActionHandler("reconnect"), onClick: () => void recoveryActionHandler("reconnect"),
}); });
} }
@@ -131,9 +133,9 @@ export const GroupCallErrorBoundary = ({
widget={widget ?? null} widget={widget ?? null}
error={callError} error={callError}
resetError={resetError} resetError={resetError}
recoveryActionHandler={(action: CallErrorRecoveryAction) => { recoveryActionHandler={async (action: CallErrorRecoveryAction) => {
await recoveryActionHandler(action);
resetError(); resetError();
recoveryActionHandler(action);
}} }}
/> />
); );

View File

@@ -13,9 +13,12 @@ import {
test, test,
vi, vi,
} from "vitest"; } from "vitest";
import { render, waitFor, screen } from "@testing-library/react"; import { render, waitFor, screen, act } from "@testing-library/react";
import { type MatrixClient, JoinRule, type RoomState } from "matrix-js-sdk"; import { type MatrixClient, JoinRule, type RoomState } from "matrix-js-sdk";
import { type MatrixRTCSession } from "matrix-js-sdk/lib/matrixrtc"; import {
MatrixRTCSessionEvent,
type MatrixRTCSession,
} from "matrix-js-sdk/lib/matrixrtc";
import { BrowserRouter } from "react-router-dom"; import { BrowserRouter } from "react-router-dom";
import userEvent from "@testing-library/user-event"; import userEvent from "@testing-library/user-event";
import { type RelationsContainer } from "matrix-js-sdk/lib/models/relations-container"; import { type RelationsContainer } from "matrix-js-sdk/lib/models/relations-container";
@@ -258,3 +261,19 @@ test("GroupCallView shows errors that occur during joining", async () => {
await user.click(screen.getByRole("button", { name: "Join call" })); await user.click(screen.getByRole("button", { name: "Join call" }));
screen.getByText("Call is not supported"); screen.getByText("Call is not supported");
}); });
test("user can reconnect after a membership manager error", async () => {
const user = userEvent.setup();
const { rtcSession } = createGroupCallView(null, true);
await act(() =>
rtcSession.emit(MatrixRTCSessionEvent.MembershipManagerError, undefined),
);
// XXX: Wrapping the following click in act() shouldn't be necessary (the
// async state update should be processed automatically by the waitFor call),
// and yet here we are.
await act(async () =>
user.click(screen.getByRole("button", { name: "Reconnect" })),
);
// In-call controls should be visible again
await waitFor(() => screen.getByRole("button", { name: "Leave" }));
});

View File

@@ -497,10 +497,11 @@ export const GroupCallView: FC<Props> = ({
return ( return (
<GroupCallErrorBoundary <GroupCallErrorBoundary
widget={widget} widget={widget}
recoveryActionHandler={(action) => { recoveryActionHandler={async (action) => {
setExternalError(null);
if (action == "reconnect") { if (action == "reconnect") {
setLeft(false); setLeft(false);
enterRTCSessionOrError(rtcSession).catch((e) => { await enterRTCSessionOrError(rtcSession).catch((e) => {
logger.error("Error re-entering RTC session", e); logger.error("Error re-entering RTC session", e);
}); });
} }