diff --git a/src/room/GroupCallErrorBoundary.test.tsx b/src/room/GroupCallErrorBoundary.test.tsx
index 86921710..994d1b86 100644
--- a/src/room/GroupCallErrorBoundary.test.tsx
+++ b/src/room/GroupCallErrorBoundary.test.tsx
@@ -16,6 +16,7 @@ import {
} from "react";
import { BrowserRouter } from "react-router-dom";
import userEvent from "@testing-library/user-event";
+import * as Sentry from "@sentry/react";
import {
type CallErrorRecoveryAction,
@@ -25,13 +26,26 @@ import {
ConnectionLostError,
E2EENotSupportedError,
type ElementCallError,
+ FailToGetOpenIdToken,
+ FailToStartLivekitConnection,
InsufficientCapacityError,
MatrixRTCTransportMissingError,
+ NoMatrix2AuthorizationService,
+ SFURoomCreationRestrictedError,
UnknownCallError,
} from "../utils/errors.ts";
import { mockConfig } from "../utils/test.ts";
import { ElementWidgetActions, type WidgetHelpers } from "../widget.ts";
+// Mock Sentry before importing the component
+vi.mock("@sentry/react", async () => {
+ const actual = await vi.importActual("@sentry/react");
+ return {
+ ...actual,
+ captureException: vi.fn(),
+ };
+});
+
test.each([
{
error: new MatrixRTCTransportMissingError("example.com"),
@@ -212,6 +226,44 @@ describe("Rageshake button", () => {
});
});
+test.each([
+ { error: new MatrixRTCTransportMissingError("example.com") },
+ { error: new ConnectionLostError() },
+ { error: new UnknownCallError(new Error("FOO")) },
+ { error: new E2EENotSupportedError() },
+ { error: new InsufficientCapacityError() },
+ { error: new SFURoomCreationRestrictedError() },
+ { error: new FailToStartLivekitConnection() },
+ { error: new NoMatrix2AuthorizationService(new Error("FOO")) },
+ { error: new FailToGetOpenIdToken(new Error("FOO")) },
+])(
+ "should call Sentry.captureException for group call errors $error",
+ ({ error }) => {
+ vi.mocked(Sentry.captureException).mockClear(); // Clear previous calls
+
+ const TestComponent = (): ReactNode => {
+ throw error;
+ };
+
+ render(
+
+
+
+
+ ,
+ );
+
+ // await screen.findByText(/Something went wrong/);
+
+ expect(Sentry.captureException).toHaveBeenCalledWith(error);
+ expect(Sentry.captureException).toHaveBeenCalledOnce();
+ },
+);
+
test("should have a close button in widget mode", async () => {
const error = new MatrixRTCTransportMissingError("example.com");
const TestComponent = (): ReactNode => {
diff --git a/src/room/GroupCallErrorBoundary.tsx b/src/room/GroupCallErrorBoundary.tsx
index ca407ed4..a056b790 100644
--- a/src/room/GroupCallErrorBoundary.tsx
+++ b/src/room/GroupCallErrorBoundary.tsx
@@ -13,7 +13,9 @@ import {
type ReactNode,
type SVGAttributes,
useCallback,
+ useEffect,
} from "react";
+import * as Sentry from "@sentry/react";
import { Trans, useTranslation } from "react-i18next";
import {
ErrorSolidIcon,
@@ -53,6 +55,11 @@ const ErrorPage: FC = ({
recoveryActionHandler,
widget,
}: ErrorPageProps): ReactElement => {
+ // We want to auto capture to sentry
+ useEffect(() => {
+ Sentry.captureException(error);
+ }, [error]);
+
const { t } = useTranslation();
logger.error("Error boundary caught:", error);
let icon: ComponentType>;