Harden Settings using mapped types (#28775)

* Harden Settings using mapped types

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix issues found during hardening

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Remove oidc native flow stale key

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski
2024-12-23 20:25:15 +00:00
committed by GitHub
parent 4e1bd69e4d
commit 1e42f28a69
90 changed files with 576 additions and 274 deletions

View File

@@ -343,7 +343,7 @@ describe("Notifier", () => {
describe("getSoundForRoom", () => {
it("should not explode if given invalid url", () => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string): any => {
return { url: { content_uri: "foobar" } };
});
expect(Notifier.getSoundForRoom("!roomId:server")).toBeNull();

View File

@@ -309,7 +309,7 @@ describe("SlidingSyncManager", () => {
});
it("uses the legacy `feature_sliding_sync_proxy_url` if it was set", async () => {
jest.spyOn(manager, "getProxyFromWellKnown").mockResolvedValue("https://proxy/");
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string): any => {
if (name === "feature_sliding_sync_proxy_url") return "legacy-proxy";
});
await manager.setup(client);

View File

@@ -1493,7 +1493,7 @@ describe("<MatrixChat />", () => {
};
const enabledMobileRegistration = (): void => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName: string) => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName): any => {
if (settingName === "Registration.mobileRegistrationHelper") return true;
if (settingName === UIFeature.Registration) return true;
});

View File

@@ -303,8 +303,8 @@ describe("TimelinePanel", () => {
client.isVersionSupported.mockResolvedValue(true);
client.doesServerSupportUnstableFeature.mockResolvedValue(true);
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting: string) => {
if (setting === "sendReadReceipt") return false;
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting: string): any => {
if (setting === "sendReadReceipts") return false;
return undefined;
});

View File

@@ -14,13 +14,14 @@ import { shouldShowFeedback } from "../../../../../src/utils/Feedback";
import BetaCard from "../../../../../src/components/views/beta/BetaCard";
import SettingsStore from "../../../../../src/settings/SettingsStore";
import { TranslationKey } from "../../../../../src/languageHandler";
import { FeatureSettingKey } from "../../../../../src/settings/Settings.tsx";
jest.mock("../../../../../src/utils/Feedback");
jest.mock("../../../../../src/settings/SettingsStore");
describe("<BetaCard />", () => {
describe("Feedback prompt", () => {
const featureId = "featureId";
const featureId = "featureId" as FeatureSettingKey;
beforeEach(() => {
mocked(SettingsStore).getBetaInfo.mockReturnValue({

View File

@@ -27,6 +27,7 @@ import {
import { UIFeature } from "../../../../../src/settings/UIFeature";
import { SettingLevel } from "../../../../../src/settings/SettingLevel";
import { SdkContextClass } from "../../../../../src/contexts/SDKContext";
import { FeatureSettingKey } from "../../../../../src/settings/Settings.tsx";
mockPlatformPeg({
supportsSpellCheckSettings: jest.fn().mockReturnValue(false),
@@ -111,13 +112,13 @@ describe("<UserSettingsDialog />", () => {
});
it("renders ignored users tab when feature_mjolnir is enabled", () => {
mockSettingsStore.getValue.mockImplementation((settingName): any => settingName === "feature_mjolnir");
mockSettingsStore.getValue.mockImplementation((settingName) => settingName === "feature_mjolnir");
const { getByTestId } = render(getComponent());
expect(getByTestId(`settings-tab-${UserTab.Mjolnir}`)).toBeTruthy();
});
it("renders voip tab when voip is enabled", () => {
mockSettingsStore.getValue.mockImplementation((settingName): any => settingName === UIFeature.Voip);
mockSettingsStore.getValue.mockImplementation((settingName: any): any => settingName === UIFeature.Voip);
const { getByTestId } = render(getComponent());
expect(getByTestId(`settings-tab-${UserTab.Voice}`)).toBeTruthy();
});
@@ -165,7 +166,7 @@ describe("<UserSettingsDialog />", () => {
it("renders with voip tab selected", () => {
useMockMediaDevices();
mockSettingsStore.getValue.mockImplementation((settingName): any => settingName === UIFeature.Voip);
mockSettingsStore.getValue.mockImplementation((settingName: any): any => settingName === UIFeature.Voip);
const { container } = render(getComponent({ initialTabId: UserTab.Voice }));
expect(getActiveTabLabel(container)).toEqual("Voice & Video");
@@ -212,8 +213,11 @@ describe("<UserSettingsDialog />", () => {
});
it("renders labs tab when some feature is in beta", () => {
mockSettingsStore.getFeatureSettingNames.mockReturnValue(["feature_beta_setting", "feature_just_normal_labs"]);
mockSettingsStore.getBetaInfo.mockImplementation((settingName) =>
mockSettingsStore.getFeatureSettingNames.mockReturnValue([
"feature_beta_setting",
"feature_just_normal_labs",
] as unknown[] as FeatureSettingKey[]);
mockSettingsStore.getBetaInfo.mockImplementation((settingName: any) =>
settingName === "feature_beta_setting" ? ({} as any) : undefined,
);
const { getByTestId } = render(getComponent());

View File

@@ -66,11 +66,13 @@ describe("MessageComposer", () => {
// restore settings
act(() => {
[
"MessageComposerInput.showStickersButton",
"MessageComposerInput.showPollsButton",
"feature_wysiwyg_composer",
].forEach((setting: string): void => {
(
[
"MessageComposerInput.showStickersButton",
"MessageComposerInput.showPollsButton",
"feature_wysiwyg_composer",
] as const
).forEach((setting): void => {
SettingsStore.setValue(setting, null, SettingLevel.DEVICE, SettingsStore.getDefaultValue(setting));
});
});
@@ -188,11 +190,11 @@ describe("MessageComposer", () => {
// test button display depending on settings
[
{
setting: "MessageComposerInput.showStickersButton",
setting: "MessageComposerInput.showStickersButton" as const,
buttonLabel: "Sticker",
},
{
setting: "MessageComposerInput.showPollsButton",
setting: "MessageComposerInput.showPollsButton" as const,
buttonLabel: "Poll",
},
].forEach(({ setting, buttonLabel }) => {

View File

@@ -176,7 +176,7 @@ describe("RoomHeader", () => {
});
it("opens the notifications panel", async () => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string): any => {
if (name === "feature_notifications") return true;
});

View File

@@ -44,7 +44,7 @@ describe("RoomPreviewCard", () => {
client.reEmitter.reEmit(room, [RoomStateEvent.Events]);
enabledFeatures = [];
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName) =>
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName): any =>
enabledFeatures.includes(settingName) ? true : undefined,
);
});

View File

@@ -419,7 +419,7 @@ describe("WysiwygComposer", () => {
const onChange = jest.fn();
const onSend = jest.fn();
beforeEach(async () => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string): any => {
if (name === "MessageComposerInput.autoReplaceEmoji") return true;
});
customRender(onChange, onSend);
@@ -455,7 +455,7 @@ describe("WysiwygComposer", () => {
const onChange = jest.fn();
const onSend = jest.fn();
beforeEach(async () => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name): any => {
if (name === "MessageComposerInput.ctrlEnterToSend") return true;
});
customRender(onChange, onSend);

View File

@@ -57,7 +57,7 @@ describe("<LayoutSwitcher />", () => {
act(() => screen.getByRole("radio", { name: "Message bubbles" }).click());
expect(screen.getByRole("radio", { name: "Message bubbles" })).toBeChecked();
await waitFor(() => expect(SettingsStore.getValue<boolean>("layout")).toBe(Layout.Bubble));
await waitFor(() => expect(SettingsStore.getValue("layout")).toBe(Layout.Bubble));
});
});
@@ -77,7 +77,7 @@ describe("<LayoutSwitcher />", () => {
await renderLayoutSwitcher();
act(() => screen.getByRole("checkbox", { name: "Show compact text and messages" }).click());
await waitFor(() => expect(SettingsStore.getValue<boolean>("useCompactLayout")).toBe(true));
await waitFor(() => expect(SettingsStore.getValue("useCompactLayout")).toBe(true));
});
it("should be disabled when the modern layout is not enabled", async () => {

View File

@@ -40,7 +40,7 @@ describe("DiscoverySettings", () => {
const DiscoveryWrapper = (props = {}) => <MatrixClientContext.Provider value={client} {...props} />;
it("is empty if 3pid features are disabled", async () => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((key) => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((key: any): any => {
if (key === UIFeature.ThirdPartyID) return false;
});

View File

@@ -69,7 +69,7 @@ describe("RolesRoomSettingsTab", () => {
describe("Element Call", () => {
const setGroupCallsEnabled = (val: boolean): void => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string): any => {
if (name === "feature_group_calls") return val;
});
};

View File

@@ -17,6 +17,7 @@ import SettingsStore from "../../../../../../../src/settings/SettingsStore";
import { SettingLevel } from "../../../../../../../src/settings/SettingLevel";
import MatrixClientBackedController from "../../../../../../../src/settings/controllers/MatrixClientBackedController";
import PlatformPeg from "../../../../../../../src/PlatformPeg";
import { SettingKey } from "../../../../../../../src/settings/Settings.tsx";
describe("PreferencesUserSettingsTab", () => {
beforeEach(() => {
@@ -121,13 +122,13 @@ describe("PreferencesUserSettingsTab", () => {
const mockGetValue = (val: boolean) => {
const copyOfGetValueAt = SettingsStore.getValueAt;
SettingsStore.getValueAt = <T,>(
SettingsStore.getValueAt = (
level: SettingLevel,
name: string,
name: SettingKey,
roomId?: string,
isExplicit?: boolean,
): T => {
if (name === "sendReadReceipts") return val as T;
) => {
if (name === "sendReadReceipts") return val;
return copyOfGetValueAt(level, name, roomId, isExplicit);
};
};

View File

@@ -19,6 +19,7 @@ import { populateThread } from "../../../../test-utils/threads";
import DMRoomMap from "../../../../../src/utils/DMRoomMap";
import SettingsStore from "../../../../../src/settings/SettingsStore";
import { SettingLevel } from "../../../../../src/settings/SettingLevel";
import { Features } from "../../../../../src/settings/Settings.tsx";
describe("ThreadsActivityCentre", () => {
const getTACButton = () => {
@@ -92,7 +93,7 @@ describe("ThreadsActivityCentre", () => {
});
beforeEach(async () => {
await SettingsStore.setValue("feature_release_announcement", null, SettingLevel.DEVICE, false);
await SettingsStore.setValue(Features.ReleaseAnnouncement, null, SettingLevel.DEVICE, false);
});
it("should render the threads activity centre button", async () => {
@@ -102,7 +103,7 @@ describe("ThreadsActivityCentre", () => {
it("should render the release announcement", async () => {
// Enable release announcement
await SettingsStore.setValue("feature_release_announcement", null, SettingLevel.DEVICE, true);
await SettingsStore.setValue(Features.ReleaseAnnouncement, null, SettingLevel.DEVICE, true);
renderTAC();
expect(document.body).toMatchSnapshot();
@@ -110,7 +111,7 @@ describe("ThreadsActivityCentre", () => {
it("should render not display the tooltip when the release announcement is displayed", async () => {
// Enable release announcement
await SettingsStore.setValue("feature_release_announcement", null, SettingLevel.DEVICE, true);
await SettingsStore.setValue(Features.ReleaseAnnouncement, null, SettingLevel.DEVICE, true);
renderTAC();
@@ -121,7 +122,7 @@ describe("ThreadsActivityCentre", () => {
it("should close the release announcement when the TAC button is clicked", async () => {
// Enable release announcement
await SettingsStore.setValue("feature_release_announcement", null, SettingLevel.DEVICE, true);
await SettingsStore.setValue(Features.ReleaseAnnouncement, null, SettingLevel.DEVICE, true);
renderTAC();
await userEvent.click(getTACButton());

View File

@@ -105,7 +105,7 @@ describe("createRoom", () => {
});
it("correctly sets up MSC3401 power levels", async () => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string): any => {
if (name === "feature_group_calls") return true;
});

View File

@@ -48,6 +48,7 @@ import ActiveWidgetStore, { ActiveWidgetStoreEvent } from "../../../src/stores/A
import { ElementWidgetActions } from "../../../src/stores/widgets/ElementWidgetActions";
import SettingsStore from "../../../src/settings/SettingsStore";
import { PosthogAnalytics } from "../../../src/PosthogAnalytics";
import { SettingKey } from "../../../src/settings/Settings.tsx";
jest.spyOn(MediaDeviceHandler, "getDevices").mockResolvedValue({
[MediaDeviceKindEnum.AudioInput]: [
@@ -63,7 +64,7 @@ jest.spyOn(MediaDeviceHandler, "getVideoInput").mockReturnValue("2");
const enabledSettings = new Set(["feature_group_calls", "feature_video_rooms", "feature_element_call_video_rooms"]);
jest.spyOn(SettingsStore, "getValue").mockImplementation(
(settingName) => enabledSettings.has(settingName) || undefined,
(settingName): any => enabledSettings.has(settingName) || undefined,
);
const setUpClientRoomAndStores = (): {
@@ -709,16 +710,18 @@ describe("ElementCall", () => {
it("passes font settings through widget URL", async () => {
const originalGetValue = SettingsStore.getValue;
SettingsStore.getValue = <T>(name: string, roomId?: string, excludeDefault?: boolean) => {
SettingsStore.getValue = (name: SettingKey, roomId: string | null = null, excludeDefault = false): any => {
switch (name) {
case "fontSizeDelta":
return 4 as T;
return 4;
case "useSystemFont":
return true as T;
return true;
case "systemFont":
return "OpenDyslexic, DejaVu Sans" as T;
return "OpenDyslexic, DejaVu Sans";
default:
return originalGetValue<T>(name, roomId, excludeDefault);
return excludeDefault
? originalGetValue(name, roomId, excludeDefault)
: originalGetValue(name, roomId, excludeDefault);
}
};
document.documentElement.style.fontSize = "12px";
@@ -746,12 +749,14 @@ describe("ElementCall", () => {
// Now test with the preference set to true
const originalGetValue = SettingsStore.getValue;
SettingsStore.getValue = <T>(name: string, roomId?: string, excludeDefault?: boolean) => {
SettingsStore.getValue = (name: SettingKey, roomId: string | null = null, excludeDefault = false): any => {
switch (name) {
case "fallbackICEServerAllowed":
return true as T;
return true;
default:
return originalGetValue<T>(name, roomId, excludeDefault);
return excludeDefault
? originalGetValue(name, roomId, excludeDefault)
: originalGetValue(name, roomId, excludeDefault);
}
};
@@ -803,12 +808,14 @@ describe("ElementCall", () => {
it("passes feature_allow_screen_share_only_mode setting to allowVoipWithNoMedia url param", async () => {
// Now test with the preference set to true
const originalGetValue = SettingsStore.getValue;
SettingsStore.getValue = <T>(name: string, roomId?: string, excludeDefault?: boolean) => {
SettingsStore.getValue = (name: SettingKey, roomId: string | null = null, excludeDefault = false): any => {
switch (name) {
case "feature_allow_screen_share_only_mode":
return true as T;
return true;
default:
return originalGetValue<T>(name, roomId, excludeDefault);
return excludeDefault
? originalGetValue(name, roomId, excludeDefault)
: originalGetValue(name, roomId, excludeDefault);
}
};
await ElementCall.create(room);

View File

@@ -13,10 +13,11 @@ import SdkConfig from "../../../src/SdkConfig";
import { SettingLevel } from "../../../src/settings/SettingLevel";
import SettingsStore from "../../../src/settings/SettingsStore";
import { mkStubRoom, mockPlatformPeg, stubClient } from "../../test-utils";
import { SettingKey } from "../../../src/settings/Settings.tsx";
const TEST_DATA = [
{
name: "Electron.showTrayIcon",
name: "Electron.showTrayIcon" as SettingKey,
level: SettingLevel.PLATFORM,
value: true,
},

View File

@@ -9,6 +9,7 @@ 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";
import { FeatureSettingKey } from "../../../../src/settings/Settings.tsx";
describe("IncompatibleController", () => {
const settingsGetValueSpy = jest.spyOn(SettingsStore, "getValue");
@@ -20,7 +21,7 @@ describe("IncompatibleController", () => {
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 });
const controller = new IncompatibleController("feature_spotlight" as FeatureSettingKey, { key: null });
settingsGetValueSpy.mockReturnValue(true);
// true === true
expect(controller.incompatibleSetting).toBe(true);
@@ -30,7 +31,7 @@ describe("IncompatibleController", () => {
it("returns false when setting value is not true", () => {
// no incompatible value set, defaulted to true
const controller = new IncompatibleController("feature_spotlight", { key: null });
const controller = new IncompatibleController("feature_spotlight" as FeatureSettingKey, { key: null });
settingsGetValueSpy.mockReturnValue("test");
expect(controller.incompatibleSetting).toBe(false);
});
@@ -38,13 +39,21 @@ describe("IncompatibleController", () => {
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");
const controller = new IncompatibleController(
"feature_spotlight" as FeatureSettingKey,
{ 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");
const controller = new IncompatibleController(
"feature_spotlight" as FeatureSettingKey,
{ key: null },
"test",
);
settingsGetValueSpy.mockReturnValue("not test");
expect(controller.incompatibleSetting).toBe(false);
});
@@ -53,7 +62,11 @@ describe("IncompatibleController", () => {
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);
const controller = new IncompatibleController(
"feature_spotlight" as FeatureSettingKey,
{ key: null },
incompatibleValueFn,
);
settingsGetValueSpy.mockReturnValue("test");
expect(controller.incompatibleSetting).toBe(false);
expect(incompatibleValueFn).toHaveBeenCalledWith("test");
@@ -64,7 +77,7 @@ describe("IncompatibleController", () => {
describe("getValueOverride()", () => {
it("returns forced value when setting is incompatible", () => {
settingsGetValueSpy.mockReturnValue(true);
const controller = new IncompatibleController("feature_spotlight", { key: null });
const controller = new IncompatibleController("feature_spotlight" as FeatureSettingKey, { key: null });
expect(
controller.getValueOverride(SettingLevel.ACCOUNT, "$room:server", true, SettingLevel.ACCOUNT),
).toEqual({ key: null });
@@ -72,7 +85,7 @@ describe("IncompatibleController", () => {
it("returns null when setting is not incompatible", () => {
settingsGetValueSpy.mockReturnValue(false);
const controller = new IncompatibleController("feature_spotlight", { key: null });
const controller = new IncompatibleController("feature_spotlight" as FeatureSettingKey, { key: null });
expect(
controller.getValueOverride(SettingLevel.ACCOUNT, "$room:server", true, SettingLevel.ACCOUNT),
).toEqual(null);

View File

@@ -11,7 +11,7 @@ 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 { FeatureSettingKey, LabGroup, SETTINGS } from "../../../../src/settings/Settings";
import { stubClient } from "../../../test-utils";
import { WatchManager } from "../../../../src/settings/WatchManager";
import MatrixClientBackedController from "../../../../src/settings/controllers/MatrixClientBackedController";
@@ -19,7 +19,7 @@ import { TranslationKey } from "../../../../src/languageHandler";
describe("ServerSupportUnstableFeatureController", () => {
const watchers = new WatchManager();
const setting = "setting_name";
const setting = "setting_name" as FeatureSettingKey;
async function prepareSetting(
cli: MatrixClient,

View File

@@ -17,7 +17,7 @@ describe("SystemFontController", () => {
it("dispatches a system font update action on change", () => {
const controller = new SystemFontController();
const getValueSpy = jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName) => {
const getValueSpy = jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName): any => {
if (settingName === "useBundledEmojiFont") return false;
if (settingName === "useSystemFont") return true;
if (settingName === "systemFont") return "Comic Sans MS";

View File

@@ -9,6 +9,7 @@ Please see LICENSE files in the repository root for full details.
import SettingsStore from "../../../../src/settings/SettingsStore";
import ThemeWatcher from "../../../../src/settings/watchers/ThemeWatcher";
import { SettingLevel } from "../../../../src/settings/SettingLevel";
import { SettingKey, Settings } from "../../../../src/settings/Settings.tsx";
function makeMatchMedia(values: any) {
class FakeMediaQueryList {
@@ -33,8 +34,12 @@ function makeMatchMedia(values: any) {
};
}
function makeGetValue(values: any) {
return function getValue<T = any>(settingName: string, _roomId: string | null = null, _excludeDefault = false): T {
function makeGetValue(values: any): any {
return function getValue<S extends SettingKey>(
settingName: S,
_roomId: string | null = null,
_excludeDefault = false,
): Settings[S] {
return values[settingName];
};
}

View File

@@ -21,6 +21,7 @@ import { getMockClientWithEventEmitter, mockClientMethodsCrypto, mockPlatformPeg
import { collectBugReport } from "../../src/rageshake/submit-rageshake";
import SettingsStore from "../../src/settings/SettingsStore";
import { ConsoleLogger } from "../../src/rageshake/rageshake";
import { FeatureSettingKey, SettingKey } from "../../src/settings/Settings.tsx";
describe("Rageshakes", () => {
const RUST_CRYPTO_VERSION = "Rust SDK 0.7.0 (691ec63), Vodozemac 0.5.0";
@@ -376,8 +377,11 @@ describe("Rageshakes", () => {
const mockSettingsStore = mocked(SettingsStore);
it("should collect labs from settings store", async () => {
const someFeatures: string[] = ["feature_video_rooms", "feature_notification_settings2"];
const enabledFeatures: string[] = ["feature_video_rooms"];
const someFeatures = [
"feature_video_rooms",
"feature_notification_settings2",
] as unknown[] as FeatureSettingKey[];
const enabledFeatures: SettingKey[] = ["feature_video_rooms"];
jest.spyOn(mockSettingsStore, "getFeatureSettingNames").mockReturnValue(someFeatures);
jest.spyOn(mockSettingsStore, "getValue").mockImplementation((settingName): any => {
return enabledFeatures.includes(settingName);

View File

@@ -149,7 +149,7 @@ describe("theme", () => {
});
it("should be robust to malformed custom_themes values", () => {
jest.spyOn(SettingsStore, "getValue").mockReturnValue([23]);
jest.spyOn(SettingsStore, "getValue").mockReturnValue([23] as any);
expect(enumerateThemes()).toEqual({
"light": "Light",
"light-high-contrast": "Light high contrast",

View File

@@ -44,7 +44,7 @@ describe("PlainTextExport", () => {
[24, false, "Fri, Apr 16, 2021, 17:20:00 - @alice:example.com: Hello, world!\n"],
[12, true, "Fri, Apr 16, 2021, 5:20:00 PM - @alice:example.com: Hello, world!\n"],
])("should return text with %i hr time format", async (hour: number, setting: boolean, expectedMessage: string) => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName: string) =>
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName: string): any =>
settingName === "showTwelveHourTimestamps" ? setting : undefined,
);
const events: MatrixEvent[] = [