diff --git a/test/unit-tests/HtmlUtils-test.tsx b/test/unit-tests/HtmlUtils-test.tsx
index 0650db1890..16546e69dc 100644
--- a/test/unit-tests/HtmlUtils-test.tsx
+++ b/test/unit-tests/HtmlUtils-test.tsx
@@ -7,22 +7,19 @@ Please see LICENSE files in the repository root for full details.
*/
import React from "react";
-import { mocked } from "jest-mock";
import { render, screen } from "jest-matrix-react";
import parse from "html-react-parser";
import { bodyToHtml, bodyToNode, formatEmojis, topicToHtml } from "../../src/HtmlUtils";
import SettingsStore from "../../src/settings/SettingsStore";
-
-jest.mock("../../src/settings/SettingsStore");
-
-const enableHtmlTopicFeature = () => {
- mocked(SettingsStore).getValue.mockImplementation((arg): any => {
- return arg === "feature_html_topic";
- });
-};
+import { SettingLevel } from "../../src/settings/SettingLevel";
+import SdkConfig from "../../src/SdkConfig";
describe("topicToHtml", () => {
+ afterEach(() => {
+ SettingsStore.reset();
+ });
+
function getContent() {
return screen.getByRole("contentinfo").children[0].innerHTML;
}
@@ -38,19 +35,19 @@ describe("topicToHtml", () => {
});
it("converts literal HTML topic to HTML", async () => {
- enableHtmlTopicFeature();
+ SettingsStore.setValue("feature_html_topic", null, SettingLevel.DEVICE, true);
render(
{topicToHtml("pizza", undefined, null, false)}
);
expect(getContent()).toEqual("<b>pizza</b>");
});
it("converts true HTML topic to HTML", async () => {
- enableHtmlTopicFeature();
+ SettingsStore.setValue("feature_html_topic", null, SettingLevel.DEVICE, true);
render({topicToHtml("**pizza**", "pizza", null, false)}
);
expect(getContent()).toEqual("pizza");
});
it("converts true HTML topic with emoji to HTML", async () => {
- enableHtmlTopicFeature();
+ SettingsStore.setValue("feature_html_topic", null, SettingLevel.DEVICE, true);
render({topicToHtml("**pizza** 🍕", "pizza 🍕", null, false)}
);
expect(getContent()).toEqual('pizza 🍕');
});
@@ -107,7 +104,12 @@ describe("bodyToHtml", () => {
describe("feature_latex_maths", () => {
beforeEach(() => {
- jest.spyOn(SettingsStore, "getValue").mockImplementation((feature) => feature === "feature_latex_maths");
+ SettingsStore.setValue("feature_latex_maths", null, SettingLevel.DEVICE, true);
+ });
+
+ afterEach(() => {
+ SettingsStore.reset();
+ SdkConfig.reset();
});
it("should render inline katex", () => {
@@ -228,4 +230,8 @@ describe("bodyToNode", () => {
expect(asFragment()).toMatchSnapshot();
});
+
+ afterEach(() => {
+ jest.resetAllMocks();
+ });
});
diff --git a/test/unit-tests/components/structures/MatrixChat-test.tsx b/test/unit-tests/components/structures/MatrixChat-test.tsx
index d6db2ce941..8633b3cfcf 100644
--- a/test/unit-tests/components/structures/MatrixChat-test.tsx
+++ b/test/unit-tests/components/structures/MatrixChat-test.tsx
@@ -484,6 +484,10 @@ describe("", () => {
);
});
+ afterEach(() => {
+ SettingsStore.reset();
+ });
+
it("should persist login credentials", async () => {
getComponent({ realQueryParams });
diff --git a/test/unit-tests/components/structures/TimelinePanel-test.tsx b/test/unit-tests/components/structures/TimelinePanel-test.tsx
index 886fe777e4..87c788d9f9 100644
--- a/test/unit-tests/components/structures/TimelinePanel-test.tsx
+++ b/test/unit-tests/components/structures/TimelinePanel-test.tsx
@@ -50,6 +50,8 @@ import SettingsStore from "../../../../src/settings/SettingsStore";
import ScrollPanel from "../../../../src/components/structures/ScrollPanel";
import defaultDispatcher from "../../../../src/dispatcher/dispatcher";
import { Action } from "../../../../src/dispatcher/actions";
+import { SettingLevel } from "../../../../src/settings/SettingLevel";
+import MatrixClientBackedController from "../../../../src/settings/controllers/MatrixClientBackedController";
// ScrollPanel calls this, but jsdom doesn't mock it for us
HTMLDivElement.prototype.scrollBy = () => {};
@@ -310,18 +312,14 @@ describe("TimelinePanel", () => {
describe("and sending receipts is disabled", () => {
beforeEach(async () => {
- client.isVersionSupported.mockResolvedValue(true);
- client.doesServerSupportUnstableFeature.mockResolvedValue(true);
-
- jest.spyOn(SettingsStore, "getValue").mockImplementation((setting: string): any => {
- if (setting === "sendReadReceipts") return false;
-
- return undefined;
- });
+ // Ensure this setting is supported, otherwise it will use the default value.
+ client.isVersionSupported.mockImplementation(async (v) => v === "v1.4");
+ MatrixClientBackedController.matrixClient = client;
+ SettingsStore.setValue("sendReadReceipts", null, SettingLevel.DEVICE, false);
});
afterEach(() => {
- mocked(SettingsStore.getValue).mockReset();
+ SettingsStore.reset();
});
it("should send a fully read marker and a private receipt", async () => {
diff --git a/test/unit-tests/components/views/rooms/RoomHeader/RoomHeader-test.tsx b/test/unit-tests/components/views/rooms/RoomHeader/RoomHeader-test.tsx
index 846adc8ab4..17d1a048c2 100644
--- a/test/unit-tests/components/views/rooms/RoomHeader/RoomHeader-test.tsx
+++ b/test/unit-tests/components/views/rooms/RoomHeader/RoomHeader-test.tsx
@@ -1,5 +1,5 @@
/*
-Copyright 2024 New Vector Ltd.
+Copyright 2024, 2025 New Vector Ltd.
Copyright 2023 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
@@ -57,6 +57,7 @@ import * as UseCall from "../../../../../../src/hooks/useCall";
import { SdkContextClass } from "../../../../../../src/contexts/SDKContext";
import WidgetStore, { type IApp } from "../../../../../../src/stores/WidgetStore";
import { UIFeature } from "../../../../../../src/settings/UIFeature";
+import { SettingLevel } from "../../../../../../src/settings/SettingLevel";
jest.mock("../../../../../../src/utils/ShieldUtils");
jest.mock("../../../../../../src/hooks/right-panel/useCurrentPhase", () => ({
@@ -99,6 +100,7 @@ describe("RoomHeader", () => {
afterEach(() => {
jest.restoreAllMocks();
+ SettingsStore.reset();
});
it("renders the room header", () => {
@@ -187,9 +189,7 @@ describe("RoomHeader", () => {
it("opens the notifications panel", async () => {
const user = userEvent.setup();
- jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string): any => {
- if (name === "feature_notifications") return true;
- });
+ SettingsStore.setValue("feature_notifications", null, SettingLevel.DEVICE, true);
render(, getWrapper());
@@ -228,7 +228,15 @@ describe("RoomHeader", () => {
describe("UIFeature.Widgets enabled (default)", () => {
beforeEach(() => {
- jest.spyOn(SettingsStore, "getValue").mockImplementation((feature) => feature == UIFeature.Widgets);
+ SdkConfig.put({
+ setting_defaults: {
+ [UIFeature.Widgets]: true,
+ },
+ });
+ });
+
+ afterEach(() => {
+ SdkConfig.reset();
});
it("should show call buttons in a room with 2 members", () => {
@@ -248,7 +256,15 @@ describe("RoomHeader", () => {
describe("UIFeature.Widgets disabled", () => {
beforeEach(() => {
- jest.spyOn(SettingsStore, "getValue").mockImplementation((feature) => false);
+ SdkConfig.put({
+ setting_defaults: {
+ [UIFeature.Widgets]: false,
+ },
+ });
+ });
+
+ afterEach(() => {
+ SdkConfig.reset();
});
it("should show call buttons in a room with 2 members", () => {
@@ -268,7 +284,15 @@ describe("RoomHeader", () => {
describe("groups call disabled", () => {
beforeEach(() => {
- jest.spyOn(SettingsStore, "getValue").mockImplementation((feature) => feature == UIFeature.Widgets);
+ SdkConfig.put({
+ setting_defaults: {
+ [UIFeature.Widgets]: true,
+ },
+ });
+ });
+
+ afterEach(() => {
+ SdkConfig.reset();
});
it("you can't call if you're alone", () => {
@@ -333,15 +357,26 @@ describe("RoomHeader", () => {
describe("group call enabled", () => {
beforeEach(() => {
- jest.spyOn(SettingsStore, "getValue").mockImplementation(
- (feature) => feature === "feature_group_calls" || feature == UIFeature.Widgets,
- );
+ SdkConfig.put({
+ features: {
+ feature_group_calls: true,
+ },
+ });
+ });
+
+ afterEach(() => {
+ SdkConfig.reset();
+ jest.restoreAllMocks();
});
it("renders only the video call element", async () => {
const user = userEvent.setup();
mockRoomMembers(room, 3);
- jest.spyOn(SdkConfig, "get").mockReturnValue({ use_exclusively: true });
+ SdkConfig.add({
+ element_call: {
+ use_exclusively: true,
+ },
+ });
// allow element calls
jest.spyOn(room.currentState, "mayClientSendStateEvent").mockReturnValue(true);
@@ -359,7 +394,11 @@ describe("RoomHeader", () => {
});
it("can't call if there's an ongoing (pinned) call", () => {
- jest.spyOn(SdkConfig, "get").mockReturnValue({ use_exclusively: true });
+ SdkConfig.add({
+ element_call: {
+ use_exclusively: true,
+ },
+ });
// allow element calls
jest.spyOn(room.currentState, "mayClientSendStateEvent").mockReturnValue(true);
jest.spyOn(WidgetLayoutStore.instance, "isInContainer").mockReturnValue(true);
@@ -377,7 +416,14 @@ describe("RoomHeader", () => {
it("clicking on ongoing (unpinned) call re-pins it", async () => {
const user = userEvent.setup();
mockRoomMembers(room, 3);
- jest.spyOn(SettingsStore, "getValue").mockImplementation((feature) => feature == UIFeature.Widgets);
+ SdkConfig.add({
+ setting_defaults: {
+ [UIFeature.Widgets]: true,
+ },
+ features: {
+ feature_group_calls: false,
+ },
+ });
// allow calls
jest.spyOn(room.currentState, "mayClientSendStateEvent").mockReturnValue(true);
jest.spyOn(WidgetLayoutStore.instance, "isInContainer").mockReturnValue(false);
@@ -427,8 +473,10 @@ describe("RoomHeader", () => {
jest.spyOn(room.currentState, "maySendStateEvent").mockReturnValue(true);
jest.spyOn(room, "getJoinRule").mockReturnValue(JoinRule.Invite);
jest.spyOn(room, "canInvite").mockReturnValue(false);
- const guestSpaUrlMock = jest.spyOn(SdkConfig, "get").mockImplementation((key) => {
- return { guest_spa_url: "https://guest_spa_url.com", url: "https://spa_url.com" };
+ SdkConfig.add({
+ element_call: {
+ guest_spa_url: "https://guest_spa_url.com",
+ },
});
const { container: containerNoInviteNotPublicCanUpgradeAccess } = render(
,
@@ -442,8 +490,10 @@ describe("RoomHeader", () => {
jest.spyOn(room.currentState, "maySendStateEvent").mockReturnValue(false);
jest.spyOn(room, "getJoinRule").mockReturnValue(JoinRule.Invite);
jest.spyOn(room, "canInvite").mockReturnValue(false);
- jest.spyOn(SdkConfig, "get").mockImplementation((key) => {
- return { guest_spa_url: "https://guest_spa_url.com", url: "https://spa_url.com" };
+ SdkConfig.add({
+ element_call: {
+ guest_spa_url: "https://guest_spa_url.com",
+ },
});
const { container: containerNoInviteNotPublic } = render(, getWrapper());
expect(queryAllByLabelText(containerNoInviteNotPublic, "There's no one here to call")).toHaveLength(2);
@@ -463,8 +513,9 @@ describe("RoomHeader", () => {
const { container: containerInvitePublic } = render(, getWrapper());
expect(queryAllByLabelText(containerInvitePublic, "There's no one here to call")).toHaveLength(0);
+ // Clear guest_spa_url
+ SdkConfig.reset();
// last we can allow everything but without guest_spa_url nothing will work
- guestSpaUrlMock.mockRestore();
const { container: containerAllAllowedButNoGuestSpaUrl } = render(, getWrapper());
expect(
queryAllByLabelText(containerAllAllowedButNoGuestSpaUrl, "There's no one here to call"),
@@ -643,6 +694,10 @@ describe("RoomHeader", () => {
]);
});
+ afterEach(() => {
+ SdkConfig.reset();
+ });
+
it.each([
[ShieldUtils.E2EStatus.Verified, "Verified"],
[ShieldUtils.E2EStatus.Warning, "Untrusted"],
@@ -655,6 +710,11 @@ describe("RoomHeader", () => {
});
it("does not show the face pile for DMs", () => {
+ SdkConfig.put({
+ features: {
+ feature_notifications: false,
+ },
+ });
const { asFragment } = render(, getWrapper());
expect(asFragment()).toMatchSnapshot();
@@ -751,7 +811,7 @@ describe("RoomHeader", () => {
describe("ask to join enabled", () => {
it("does render the RoomKnocksBar", () => {
- jest.spyOn(SettingsStore, "getValue").mockImplementation((feature) => feature === "feature_ask_to_join");
+ SettingsStore.setValue("feature_ask_to_join", null, SettingLevel.DEVICE, true);
jest.spyOn(room, "canInvite").mockReturnValue(true);
jest.spyOn(room, "getJoinRule").mockReturnValue(JoinRule.Knock);
jest.spyOn(room, "getMembersWithMembership").mockReturnValue([new RoomMember(room.roomId, "@foo")]);
diff --git a/test/unit-tests/components/views/rooms/RoomHeader/__snapshots__/RoomHeader-test.tsx.snap b/test/unit-tests/components/views/rooms/RoomHeader/__snapshots__/RoomHeader-test.tsx.snap
index b0505fac0b..bbcf4cfb4b 100644
--- a/test/unit-tests/components/views/rooms/RoomHeader/__snapshots__/RoomHeader-test.tsx.snap
+++ b/test/unit-tests/components/views/rooms/RoomHeader/__snapshots__/RoomHeader-test.tsx.snap
@@ -55,7 +55,7 @@ exports[`RoomHeader dm does not show the face pile for DMs 1`] = `
style="--cpd-icon-button-size: 100%; --cpd-color-icon-tertiary: var(--cpd-color-icon-disabled);"
>