Let developers override the whole transport

The developer setting that overrode the LiveKit service URL becomes a
JSON transport, so that a `url`-only or combined transport can be tested
against a homeserver that does not advertise one yet. The settings modal
shows each LiveKit room's role instead of a never-populated isLocal flag.
This commit is contained in:
Robin
2026-10-12 10:33:19 +02:00
committed by Johannes Marbach
parent e336ee5cfa
commit f366e7cbe2
9 changed files with 120 additions and 95 deletions
+51 -32
View File
@@ -7,7 +7,7 @@ Please see LICENSE in the repository root for full details.
import { afterEach, describe, expect, it, type Mock, vi } from "vitest";
import { render, waitFor, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import userEvent, { type UserEvent } from "@testing-library/user-event";
import { TooltipProvider } from "@vector-im/compound-web";
import type { MatrixClient } from "matrix-js-sdk";
@@ -19,12 +19,12 @@ import {
import { outOfCallDeveloperSettingsTabViewModel } from "./DeveloperSettingsTabViewModel";
import { createStaticViewModel } from "../state/ViewModel";
import {
customLivekitUrl as customLivekitUrlSetting,
customTransport as customTransportSetting,
enableExtendedLivekitLogs as enableExtendedLivekitLogsSetting,
matrixRTCMode as matrixRTCModeSetting,
} from "./settings";
import { MatrixRTCMode } from "../config/ConfigOptions";
import { mockConfig } from "../utils/test";
import { exampleTransport, mockConfig } from "../utils/test";
import { getSFUConfig } from "../livekit/auth";
// Mock url params hook to avoid environment-dependent snapshot churn.
@@ -77,6 +77,21 @@ function createMockMatrixClient(): MatrixClient {
} as unknown as MatrixClient;
}
/**
* Types the JSON representation of an object into the given element.
*/
async function typeJson(
user: UserEvent,
element: Element,
object: object,
): Promise<void> {
// `user.type` requires us to escape brackets by doubling them
await user.type(
element,
JSON.stringify(object).replace(/([{[\]])/g, (c) => c + c),
);
}
describe("DeveloperSettingsTab", () => {
it("renders and matches snapshot", async () => {
const client = createMockMatrixClient();
@@ -124,9 +139,9 @@ describe("DeveloperSettingsTab", () => {
expect(container).toMatchSnapshot();
});
describe("custom livekit url", () => {
describe("custom transport", () => {
afterEach(() => {
customLivekitUrlSetting.setValue(null);
customTransportSetting.setValue(null);
});
const client = {
doesServerSupportUnstableFeature: vi.fn().mockResolvedValue(true),
@@ -135,7 +150,7 @@ describe("DeveloperSettingsTab", () => {
getDeviceId: () => "DEVICE",
getDomain: () => "hs",
} as unknown as MatrixClient;
it("will not update custom livekit url without roomId", async () => {
it("will not update custom transport without roomId", async () => {
const user = userEvent.setup();
render(
@@ -148,17 +163,17 @@ describe("DeveloperSettingsTab", () => {
</TooltipProvider>,
);
const input = screen.getByLabelText("Custom Livekit-url");
const input = screen.getByLabelText("Custom transport JSON");
await user.clear(input);
await user.type(input, "wss://example.livekit.invalid");
await typeJson(user, input, exampleTransport);
const saveButton = screen.getByRole("button", { name: "Save" });
await user.click(saveButton);
expect(getSFUConfig).not.toHaveBeenCalled();
expect(customLivekitUrlSetting.getValue()).toBe(null);
expect(customTransportSetting.getValue()).toBe(null);
});
it("will not update custom livekit url without text in input", async () => {
it("will not update custom transport without text in input", async () => {
const user = userEvent.setup();
render(
@@ -172,16 +187,16 @@ describe("DeveloperSettingsTab", () => {
</TooltipProvider>,
);
const input = screen.getByLabelText("Custom Livekit-url");
const input = screen.getByLabelText("Custom transport JSON");
await user.clear(input);
const saveButton = screen.getByRole("button", { name: "Save" });
await user.click(saveButton);
expect(getSFUConfig).not.toHaveBeenCalled();
expect(customLivekitUrlSetting.getValue()).toBe(null);
expect(customTransportSetting.getValue()).toBe(null);
});
it("will not update custom livekit url when pressing cancel", async () => {
it("will not update custom transport when pressing cancel", async () => {
const user = userEvent.setup();
render(
@@ -195,7 +210,7 @@ describe("DeveloperSettingsTab", () => {
</TooltipProvider>,
);
const input = screen.getByLabelText("Custom Livekit-url");
const input = screen.getByLabelText("Custom transport JSON");
await user.clear(input);
await user.type(input, "wss://example.livekit.invalid");
@@ -205,9 +220,9 @@ describe("DeveloperSettingsTab", () => {
await user.click(cancelButton);
expect(getSFUConfig).not.toHaveBeenCalled();
expect(customLivekitUrlSetting.getValue()).toBe(null);
expect(customTransportSetting.getValue()).toBe(null);
});
it("will update custom livekit url", async () => {
it("will update custom transport", async () => {
const user = userEvent.setup();
render(
@@ -221,27 +236,28 @@ describe("DeveloperSettingsTab", () => {
</TooltipProvider>,
);
const input = screen.getByLabelText("Custom Livekit-url");
const input = screen.getByLabelText("Custom transport JSON");
await user.clear(input);
await user.type(input, "wss://example.livekit.valid");
await typeJson(user, input, {
type: "livekit",
url: "wss://example.livekit.valid",
});
const saveButton = screen.getByRole("button", { name: "Save" });
await user.click(saveButton);
expect(getSFUConfig).toHaveBeenCalledWith(
expect.objectContaining({
transport: {
type: "livekit",
livekit_service_url: "wss://example.livekit.valid",
},
transport: { type: "livekit", url: "wss://example.livekit.valid" },
roomId: "#testRoom",
}),
);
expect(customLivekitUrlSetting.getValue()).toBe(
"wss://example.livekit.valid",
);
expect(customTransportSetting.getValue()).toEqual({
type: "livekit",
url: "wss://example.livekit.valid",
});
});
it("will show error on invalid url", async () => {
it("will show error on unreachable transport", async () => {
const user = userEvent.setup();
render(
@@ -255,24 +271,27 @@ describe("DeveloperSettingsTab", () => {
</TooltipProvider>,
);
const input = screen.getByLabelText("Custom Livekit-url");
const input = screen.getByLabelText("Custom transport JSON");
await user.clear(input);
await user.type(input, "wss://example.livekit.valid");
await typeJson(user, input, {
type: "livekit",
url: "wss://example.livekit.valid",
});
const saveButton = screen.getByRole("button", { name: "Save" });
(getSFUConfig as Mock).mockImplementation(() => {
throw new Error("Invalid URL");
throw new Error("Failed to get SFU config");
});
await user.click(saveButton);
expect(
screen.getByText("invalid URL (did not update)"),
screen.getByText("invalid transport (did not update)"),
).toBeInTheDocument();
expect(customLivekitUrlSetting.getValue()).toBe(null);
expect(customTransportSetting.getValue()).toBe(null);
});
});
// Add this test inside the describe("DeveloperSettingsTab", () => { block,
// after the custom livekit url tests:
// after the custom transport tests:
describe("enable extended livekit logs", () => {
afterEach(() => {