Merge matrix-react-sdk into element-web

Merge remote-tracking branch 'repomerge/t3chguy/repomerge' into t3chguy/repo-merge

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski
2024-10-15 14:57:26 +01:00
3265 changed files with 484599 additions and 699 deletions

View File

@@ -0,0 +1,27 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2024 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import PosthogTrackers from "../../../../src/PosthogTrackers";
import AnalyticsController from "../../../../src/settings/controllers/AnalyticsController";
import { SettingLevel } from "../../../../src/settings/SettingLevel";
describe("AnalyticsController", () => {
afterEach(() => {
jest.restoreAllMocks();
});
it("Tracks a Posthog interaction on change", () => {
const trackInteractionSpy = jest.spyOn(PosthogTrackers, "trackInteraction");
const controller = new AnalyticsController("WebSettingsNotificationsTACOnlyNotificationsToggle");
controller.onChange(SettingLevel.DEVICE, null, false);
expect(trackInteractionSpy).toHaveBeenCalledWith("WebSettingsNotificationsTACOnlyNotificationsToggle");
});
});

View File

@@ -0,0 +1,33 @@
/*
Copyright 2024 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import { AllDevicesIsolationMode, OnlySignedDevicesIsolationMode } from "matrix-js-sdk/src/crypto-api";
import { stubClient } from "../../../test-utils";
import DeviceIsolationModeController from "../../../../src/settings/controllers/DeviceIsolationModeController.ts";
import { SettingLevel } from "../../../../src/settings/SettingLevel";
describe("DeviceIsolationModeController", () => {
afterEach(() => {
jest.resetAllMocks();
});
describe("tracks enabling and disabling", () => {
it("on sets signed device isolation mode", () => {
const cli = stubClient();
const controller = new DeviceIsolationModeController();
controller.onChange(SettingLevel.DEVICE, "", true);
expect(cli.getCrypto()?.setDeviceIsolationMode).toHaveBeenCalledWith(new OnlySignedDevicesIsolationMode());
});
it("off sets all device isolation mode", () => {
const cli = stubClient();
const controller = new DeviceIsolationModeController();
controller.onChange(SettingLevel.DEVICE, "", false);
expect(cli.getCrypto()?.setDeviceIsolationMode).toHaveBeenCalledWith(new AllDevicesIsolationMode(false));
});
});
});

View File

@@ -0,0 +1,57 @@
/*
Copyright 2024 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import fetchMockJest from "fetch-mock-jest";
import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/matrix";
import { SettingLevel } from "../../../../src/settings/SettingLevel";
import FallbackIceServerController from "../../../../src/settings/controllers/FallbackIceServerController.ts";
import MatrixClientBackedController from "../../../../src/settings/controllers/MatrixClientBackedController.ts";
import SettingsStore from "../../../../src/settings/SettingsStore.ts";
describe("FallbackIceServerController", () => {
beforeEach(() => {
fetchMockJest.get("https://matrix.org/_matrix/client/versions", { versions: ["v1.4"] });
});
afterEach(() => {
jest.restoreAllMocks();
});
it("should update MatrixClient's state when the setting is updated", async () => {
const client = new MatrixClient({
baseUrl: "https://matrix.org",
userId: "@alice:matrix.org",
accessToken: "token",
});
MatrixClientBackedController.matrixClient = client;
expect(client.isFallbackICEServerAllowed()).toBeFalsy();
await SettingsStore.setValue("fallbackICEServerAllowed", null, SettingLevel.DEVICE, true);
expect(client.isFallbackICEServerAllowed()).toBeTruthy();
});
it("should force the setting to be disabled if disable_fallback_ice=true", async () => {
const controller = new FallbackIceServerController();
const client = new MatrixClient({
baseUrl: "https://matrix.org",
userId: "@alice:matrix.org",
accessToken: "token",
});
MatrixClientBackedController.matrixClient = client;
expect(controller.settingDisabled).toBeFalsy();
client["clientWellKnown"] = {
"io.element.voip": {
disable_fallback_ice: true,
},
};
client.emit(ClientEvent.ClientWellKnown, client["clientWellKnown"]);
expect(controller.settingDisabled).toBeTruthy();
});
});

View File

@@ -0,0 +1,24 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2022 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import { Action } from "../../../../src/dispatcher/actions";
import dis from "../../../../src/dispatcher/dispatcher";
import FontSizeController from "../../../../src/settings/controllers/FontSizeController";
import { SettingLevel } from "../../../../src/settings/SettingLevel";
const dispatchSpy = jest.spyOn(dis, "fire");
describe("FontSizeController", () => {
it("dispatches a font size action on change", () => {
const controller = new FontSizeController();
controller.onChange(SettingLevel.ACCOUNT, "$room:server", 12);
expect(dispatchSpy).toHaveBeenCalledWith(Action.MigrateBaseFontSize);
});
});

View File

@@ -0,0 +1,81 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2022 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import IncompatibleController from "../../../../src/settings/controllers/IncompatibleController";
import { SettingLevel } from "../../../../src/settings/SettingLevel";
import SettingsStore from "../../../../src/settings/SettingsStore";
describe("IncompatibleController", () => {
const settingsGetValueSpy = jest.spyOn(SettingsStore, "getValue");
beforeEach(() => {
settingsGetValueSpy.mockClear();
});
describe("incompatibleSetting", () => {
describe("when incompatibleValue is not set", () => {
it("returns true when setting value is true", () => {
// no incompatible value set, defaulted to true
const controller = new IncompatibleController("feature_spotlight", { key: null });
settingsGetValueSpy.mockReturnValue(true);
// true === true
expect(controller.incompatibleSetting).toBe(true);
expect(controller.settingDisabled).toEqual(true);
expect(settingsGetValueSpy).toHaveBeenCalledWith("feature_spotlight");
});
it("returns false when setting value is not true", () => {
// no incompatible value set, defaulted to true
const controller = new IncompatibleController("feature_spotlight", { key: null });
settingsGetValueSpy.mockReturnValue("test");
expect(controller.incompatibleSetting).toBe(false);
});
});
describe("when incompatibleValue is set to a value", () => {
it("returns true when setting value matches incompatible value", () => {
const controller = new IncompatibleController("feature_spotlight", { key: null }, "test");
settingsGetValueSpy.mockReturnValue("test");
expect(controller.incompatibleSetting).toBe(true);
});
it("returns false when setting value is not true", () => {
const controller = new IncompatibleController("feature_spotlight", { key: null }, "test");
settingsGetValueSpy.mockReturnValue("not test");
expect(controller.incompatibleSetting).toBe(false);
});
});
describe("when incompatibleValue is set to a function", () => {
it("returns result from incompatibleValue function", () => {
const incompatibleValueFn = jest.fn().mockReturnValue(false);
const controller = new IncompatibleController("feature_spotlight", { key: null }, incompatibleValueFn);
settingsGetValueSpy.mockReturnValue("test");
expect(controller.incompatibleSetting).toBe(false);
expect(incompatibleValueFn).toHaveBeenCalledWith("test");
});
});
});
describe("getValueOverride()", () => {
it("returns forced value when setting is incompatible", () => {
settingsGetValueSpy.mockReturnValue(true);
const controller = new IncompatibleController("feature_spotlight", { key: null });
expect(
controller.getValueOverride(SettingLevel.ACCOUNT, "$room:server", true, SettingLevel.ACCOUNT),
).toEqual({ key: null });
});
it("returns null when setting is not incompatible", () => {
settingsGetValueSpy.mockReturnValue(false);
const controller = new IncompatibleController("feature_spotlight", { key: null });
expect(
controller.getValueOverride(SettingLevel.ACCOUNT, "$room:server", true, SettingLevel.ACCOUNT),
).toEqual(null);
});
});
});

View File

@@ -0,0 +1,141 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2023 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import { defer } from "matrix-js-sdk/src/utils";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import ServerSupportUnstableFeatureController from "../../../../src/settings/controllers/ServerSupportUnstableFeatureController";
import { SettingLevel } from "../../../../src/settings/SettingLevel";
import { LabGroup, SETTINGS } from "../../../../src/settings/Settings";
import { stubClient } from "../../../test-utils";
import { WatchManager } from "../../../../src/settings/WatchManager";
import MatrixClientBackedController from "../../../../src/settings/controllers/MatrixClientBackedController";
import { TranslationKey } from "../../../../src/languageHandler";
describe("ServerSupportUnstableFeatureController", () => {
const watchers = new WatchManager();
const setting = "setting_name";
async function prepareSetting(
cli: MatrixClient,
controller: ServerSupportUnstableFeatureController,
): Promise<void> {
SETTINGS[setting] = {
isFeature: true,
labsGroup: LabGroup.Messaging,
displayName: "name of some kind" as TranslationKey,
supportedLevels: [SettingLevel.DEVICE, SettingLevel.CONFIG],
default: false,
controller,
};
const deferred = defer<any>();
watchers.watchSetting(setting, null, deferred.resolve);
MatrixClientBackedController.matrixClient = cli;
await deferred.promise;
}
describe("getValueOverride()", () => {
it("should return forced value is setting is disabled", async () => {
const cli = stubClient();
cli.doesServerSupportUnstableFeature = jest.fn(async () => false);
const controller = new ServerSupportUnstableFeatureController(
setting,
watchers,
[["feature"]],
undefined,
undefined,
"other_value",
);
await prepareSetting(cli, controller);
expect(controller.getValueOverride(SettingLevel.DEVICE, null, true, SettingLevel.ACCOUNT)).toEqual(
"other_value",
);
});
it("should pass through to the handler if setting is not disabled", async () => {
const cli = stubClient();
cli.doesServerSupportUnstableFeature = jest.fn(async () => true);
const controller = new ServerSupportUnstableFeatureController(
setting,
watchers,
[["feature"]],
"other_value",
);
await prepareSetting(cli, controller);
expect(controller.getValueOverride(SettingLevel.DEVICE, null, true, SettingLevel.ACCOUNT)).toEqual(null);
});
});
describe("settingDisabled()", () => {
it("considered disabled if there is no matrix client", () => {
const controller = new ServerSupportUnstableFeatureController(setting, watchers, [["org.matrix.msc3030"]]);
expect(controller.settingDisabled).toEqual(true);
});
it("considered disabled if not all required features in the only feature group are supported", async () => {
const cli = stubClient();
cli.doesServerSupportUnstableFeature = jest.fn(async (featureName) => {
return featureName === "org.matrix.msc3827.stable";
});
const controller = new ServerSupportUnstableFeatureController(setting, watchers, [
["org.matrix.msc3827.stable", "org.matrix.msc3030"],
]);
await prepareSetting(cli, controller);
expect(controller.settingDisabled).toEqual(true);
});
it("considered enabled if all required features in the only feature group are supported", async () => {
const cli = stubClient();
cli.doesServerSupportUnstableFeature = jest.fn(async (featureName) => {
return featureName === "org.matrix.msc3827.stable" || featureName === "org.matrix.msc3030";
});
const controller = new ServerSupportUnstableFeatureController(setting, watchers, [
["org.matrix.msc3827.stable", "org.matrix.msc3030"],
]);
await prepareSetting(cli, controller);
expect(controller.settingDisabled).toEqual(false);
});
it("considered enabled if all required features in one of the feature groups are supported", async () => {
const cli = stubClient();
cli.doesServerSupportUnstableFeature = jest.fn(async (featureName) => {
return featureName === "org.matrix.msc3827.stable" || featureName === "org.matrix.msc3030";
});
const controller = new ServerSupportUnstableFeatureController(setting, watchers, [
["foo-unsupported", "bar-unsupported"],
["org.matrix.msc3827.stable", "org.matrix.msc3030"],
]);
await prepareSetting(cli, controller);
expect(controller.settingDisabled).toEqual(false);
});
it("considered disabled if not all required features in one of the feature groups are supported", async () => {
const cli = stubClient();
cli.doesServerSupportUnstableFeature = jest.fn(async (featureName) => {
return featureName === "org.matrix.msc3827.stable";
});
const controller = new ServerSupportUnstableFeatureController(setting, watchers, [
["foo-unsupported", "bar-unsupported"],
["org.matrix.msc3827.stable", "org.matrix.msc3030"],
]);
await prepareSetting(cli, controller);
expect(controller.settingDisabled).toEqual(true);
});
});
});

View File

@@ -0,0 +1,36 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2022 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import { Action } from "../../../../src/dispatcher/actions";
import dis from "../../../../src/dispatcher/dispatcher";
import SystemFontController from "../../../../src/settings/controllers/SystemFontController";
import SettingsStore from "../../../../src/settings/SettingsStore";
const dispatchSpy = jest.spyOn(dis, "dispatch");
describe("SystemFontController", () => {
it("dispatches a system font update action on change", () => {
const controller = new SystemFontController();
const getValueSpy = jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName) => {
if (settingName === "useBundledEmojiFont") return false;
if (settingName === "useSystemFont") return true;
if (settingName === "systemFont") return "Comic Sans MS";
});
controller.onChange();
expect(dispatchSpy).toHaveBeenCalledWith({
action: Action.UpdateSystemFont,
useBundledEmojiFont: false,
useSystemFont: true,
font: "Comic Sans MS",
});
expect(getValueSpy).toHaveBeenCalledWith("useSystemFont");
});
});

View File

@@ -0,0 +1,60 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2022 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import ThemeController from "../../../../src/settings/controllers/ThemeController";
import { SettingLevel } from "../../../../src/settings/SettingLevel";
import SettingsStore from "../../../../src/settings/SettingsStore";
import { DEFAULT_THEME } from "../../../../src/theme";
describe("ThemeController", () => {
jest.spyOn(SettingsStore, "getValue").mockReturnValue([]);
afterEach(() => {
// reset
ThemeController.isLogin = false;
});
it("returns null when calculatedValue is falsy", () => {
const controller = new ThemeController();
expect(
controller.getValueOverride(
SettingLevel.ACCOUNT,
"$room:server",
undefined /* calculatedValue */,
SettingLevel.ACCOUNT,
),
).toEqual(null);
});
it("returns light when login flag is set", () => {
const controller = new ThemeController();
ThemeController.isLogin = true;
expect(controller.getValueOverride(SettingLevel.ACCOUNT, "$room:server", "dark", SettingLevel.ACCOUNT)).toEqual(
"light",
);
});
it("returns default theme when value is not a valid theme", () => {
const controller = new ThemeController();
expect(
controller.getValueOverride(SettingLevel.ACCOUNT, "$room:server", "my-test-theme", SettingLevel.ACCOUNT),
).toEqual(DEFAULT_THEME);
});
it("returns null when value is a valid theme", () => {
const controller = new ThemeController();
expect(controller.getValueOverride(SettingLevel.ACCOUNT, "$room:server", "dark", SettingLevel.ACCOUNT)).toEqual(
null,
);
});
});