mirror of
https://github.com/vector-im/element-web.git
synced 2025-11-29 22:41:44 +01:00
Refactor several unit tests to use SettingsStore directly. (#29744)
* Refactor notifications-test.ts * Refactor other tests to stop mocking SettingsStore
This commit is contained in:
parent
bb23a98bc6
commit
23a42e0d54
@ -7,22 +7,19 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { mocked } from "jest-mock";
|
|
||||||
import { render, screen } from "jest-matrix-react";
|
import { render, screen } from "jest-matrix-react";
|
||||||
import parse from "html-react-parser";
|
import parse from "html-react-parser";
|
||||||
|
|
||||||
import { bodyToHtml, bodyToNode, formatEmojis, topicToHtml } from "../../src/HtmlUtils";
|
import { bodyToHtml, bodyToNode, formatEmojis, topicToHtml } from "../../src/HtmlUtils";
|
||||||
import SettingsStore from "../../src/settings/SettingsStore";
|
import SettingsStore from "../../src/settings/SettingsStore";
|
||||||
|
import { SettingLevel } from "../../src/settings/SettingLevel";
|
||||||
jest.mock("../../src/settings/SettingsStore");
|
import SdkConfig from "../../src/SdkConfig";
|
||||||
|
|
||||||
const enableHtmlTopicFeature = () => {
|
|
||||||
mocked(SettingsStore).getValue.mockImplementation((arg): any => {
|
|
||||||
return arg === "feature_html_topic";
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
describe("topicToHtml", () => {
|
describe("topicToHtml", () => {
|
||||||
|
afterEach(() => {
|
||||||
|
SettingsStore.reset();
|
||||||
|
});
|
||||||
|
|
||||||
function getContent() {
|
function getContent() {
|
||||||
return screen.getByRole("contentinfo").children[0].innerHTML;
|
return screen.getByRole("contentinfo").children[0].innerHTML;
|
||||||
}
|
}
|
||||||
@ -38,19 +35,19 @@ describe("topicToHtml", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("converts literal HTML topic to HTML", async () => {
|
it("converts literal HTML topic to HTML", async () => {
|
||||||
enableHtmlTopicFeature();
|
SettingsStore.setValue("feature_html_topic", null, SettingLevel.DEVICE, true);
|
||||||
render(<div role="contentinfo">{topicToHtml("<b>pizza</b>", undefined, null, false)}</div>);
|
render(<div role="contentinfo">{topicToHtml("<b>pizza</b>", undefined, null, false)}</div>);
|
||||||
expect(getContent()).toEqual("<b>pizza</b>");
|
expect(getContent()).toEqual("<b>pizza</b>");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("converts true HTML topic to HTML", async () => {
|
it("converts true HTML topic to HTML", async () => {
|
||||||
enableHtmlTopicFeature();
|
SettingsStore.setValue("feature_html_topic", null, SettingLevel.DEVICE, true);
|
||||||
render(<div role="contentinfo">{topicToHtml("**pizza**", "<b>pizza</b>", null, false)}</div>);
|
render(<div role="contentinfo">{topicToHtml("**pizza**", "<b>pizza</b>", null, false)}</div>);
|
||||||
expect(getContent()).toEqual("<b>pizza</b>");
|
expect(getContent()).toEqual("<b>pizza</b>");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("converts true HTML topic with emoji to HTML", async () => {
|
it("converts true HTML topic with emoji to HTML", async () => {
|
||||||
enableHtmlTopicFeature();
|
SettingsStore.setValue("feature_html_topic", null, SettingLevel.DEVICE, true);
|
||||||
render(<div role="contentinfo">{topicToHtml("**pizza** 🍕", "<b>pizza</b> 🍕", null, false)}</div>);
|
render(<div role="contentinfo">{topicToHtml("**pizza** 🍕", "<b>pizza</b> 🍕", null, false)}</div>);
|
||||||
expect(getContent()).toEqual('<b>pizza</b> <span class="mx_Emoji" title=":pizza:">🍕</span>');
|
expect(getContent()).toEqual('<b>pizza</b> <span class="mx_Emoji" title=":pizza:">🍕</span>');
|
||||||
});
|
});
|
||||||
@ -107,7 +104,12 @@ describe("bodyToHtml", () => {
|
|||||||
|
|
||||||
describe("feature_latex_maths", () => {
|
describe("feature_latex_maths", () => {
|
||||||
beforeEach(() => {
|
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", () => {
|
it("should render inline katex", () => {
|
||||||
@ -228,4 +230,8 @@ describe("bodyToNode", () => {
|
|||||||
|
|
||||||
expect(asFragment()).toMatchSnapshot();
|
expect(asFragment()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.resetAllMocks();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -484,6 +484,10 @@ describe("<MatrixChat />", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
SettingsStore.reset();
|
||||||
|
});
|
||||||
|
|
||||||
it("should persist login credentials", async () => {
|
it("should persist login credentials", async () => {
|
||||||
getComponent({ realQueryParams });
|
getComponent({ realQueryParams });
|
||||||
|
|
||||||
|
|||||||
@ -50,6 +50,8 @@ import SettingsStore from "../../../../src/settings/SettingsStore";
|
|||||||
import ScrollPanel from "../../../../src/components/structures/ScrollPanel";
|
import ScrollPanel from "../../../../src/components/structures/ScrollPanel";
|
||||||
import defaultDispatcher from "../../../../src/dispatcher/dispatcher";
|
import defaultDispatcher from "../../../../src/dispatcher/dispatcher";
|
||||||
import { Action } from "../../../../src/dispatcher/actions";
|
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
|
// ScrollPanel calls this, but jsdom doesn't mock it for us
|
||||||
HTMLDivElement.prototype.scrollBy = () => {};
|
HTMLDivElement.prototype.scrollBy = () => {};
|
||||||
@ -310,18 +312,14 @@ describe("TimelinePanel", () => {
|
|||||||
|
|
||||||
describe("and sending receipts is disabled", () => {
|
describe("and sending receipts is disabled", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
client.isVersionSupported.mockResolvedValue(true);
|
// Ensure this setting is supported, otherwise it will use the default value.
|
||||||
client.doesServerSupportUnstableFeature.mockResolvedValue(true);
|
client.isVersionSupported.mockImplementation(async (v) => v === "v1.4");
|
||||||
|
MatrixClientBackedController.matrixClient = client;
|
||||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting: string): any => {
|
SettingsStore.setValue("sendReadReceipts", null, SettingLevel.DEVICE, false);
|
||||||
if (setting === "sendReadReceipts") return false;
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
mocked(SettingsStore.getValue).mockReset();
|
SettingsStore.reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should send a fully read marker and a private receipt", async () => {
|
it("should send a fully read marker and a private receipt", async () => {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2024 New Vector Ltd.
|
Copyright 2024, 2025 New Vector Ltd.
|
||||||
Copyright 2023 The Matrix.org Foundation C.I.C.
|
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
|
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 { SdkContextClass } from "../../../../../../src/contexts/SDKContext";
|
||||||
import WidgetStore, { type IApp } from "../../../../../../src/stores/WidgetStore";
|
import WidgetStore, { type IApp } from "../../../../../../src/stores/WidgetStore";
|
||||||
import { UIFeature } from "../../../../../../src/settings/UIFeature";
|
import { UIFeature } from "../../../../../../src/settings/UIFeature";
|
||||||
|
import { SettingLevel } from "../../../../../../src/settings/SettingLevel";
|
||||||
|
|
||||||
jest.mock("../../../../../../src/utils/ShieldUtils");
|
jest.mock("../../../../../../src/utils/ShieldUtils");
|
||||||
jest.mock("../../../../../../src/hooks/right-panel/useCurrentPhase", () => ({
|
jest.mock("../../../../../../src/hooks/right-panel/useCurrentPhase", () => ({
|
||||||
@ -99,6 +100,7 @@ describe("RoomHeader", () => {
|
|||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.restoreAllMocks();
|
jest.restoreAllMocks();
|
||||||
|
SettingsStore.reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders the room header", () => {
|
it("renders the room header", () => {
|
||||||
@ -187,9 +189,7 @@ describe("RoomHeader", () => {
|
|||||||
|
|
||||||
it("opens the notifications panel", async () => {
|
it("opens the notifications panel", async () => {
|
||||||
const user = userEvent.setup();
|
const user = userEvent.setup();
|
||||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string): any => {
|
SettingsStore.setValue("feature_notifications", null, SettingLevel.DEVICE, true);
|
||||||
if (name === "feature_notifications") return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
render(<RoomHeader room={room} />, getWrapper());
|
render(<RoomHeader room={room} />, getWrapper());
|
||||||
|
|
||||||
@ -228,7 +228,15 @@ describe("RoomHeader", () => {
|
|||||||
|
|
||||||
describe("UIFeature.Widgets enabled (default)", () => {
|
describe("UIFeature.Widgets enabled (default)", () => {
|
||||||
beforeEach(() => {
|
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", () => {
|
it("should show call buttons in a room with 2 members", () => {
|
||||||
@ -248,7 +256,15 @@ describe("RoomHeader", () => {
|
|||||||
|
|
||||||
describe("UIFeature.Widgets disabled", () => {
|
describe("UIFeature.Widgets disabled", () => {
|
||||||
beforeEach(() => {
|
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", () => {
|
it("should show call buttons in a room with 2 members", () => {
|
||||||
@ -268,7 +284,15 @@ describe("RoomHeader", () => {
|
|||||||
|
|
||||||
describe("groups call disabled", () => {
|
describe("groups call disabled", () => {
|
||||||
beforeEach(() => {
|
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", () => {
|
it("you can't call if you're alone", () => {
|
||||||
@ -333,15 +357,26 @@ describe("RoomHeader", () => {
|
|||||||
|
|
||||||
describe("group call enabled", () => {
|
describe("group call enabled", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.spyOn(SettingsStore, "getValue").mockImplementation(
|
SdkConfig.put({
|
||||||
(feature) => feature === "feature_group_calls" || feature == UIFeature.Widgets,
|
features: {
|
||||||
);
|
feature_group_calls: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
SdkConfig.reset();
|
||||||
|
jest.restoreAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders only the video call element", async () => {
|
it("renders only the video call element", async () => {
|
||||||
const user = userEvent.setup();
|
const user = userEvent.setup();
|
||||||
mockRoomMembers(room, 3);
|
mockRoomMembers(room, 3);
|
||||||
jest.spyOn(SdkConfig, "get").mockReturnValue({ use_exclusively: true });
|
SdkConfig.add({
|
||||||
|
element_call: {
|
||||||
|
use_exclusively: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
// allow element calls
|
// allow element calls
|
||||||
jest.spyOn(room.currentState, "mayClientSendStateEvent").mockReturnValue(true);
|
jest.spyOn(room.currentState, "mayClientSendStateEvent").mockReturnValue(true);
|
||||||
|
|
||||||
@ -359,7 +394,11 @@ describe("RoomHeader", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("can't call if there's an ongoing (pinned) call", () => {
|
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
|
// allow element calls
|
||||||
jest.spyOn(room.currentState, "mayClientSendStateEvent").mockReturnValue(true);
|
jest.spyOn(room.currentState, "mayClientSendStateEvent").mockReturnValue(true);
|
||||||
jest.spyOn(WidgetLayoutStore.instance, "isInContainer").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 () => {
|
it("clicking on ongoing (unpinned) call re-pins it", async () => {
|
||||||
const user = userEvent.setup();
|
const user = userEvent.setup();
|
||||||
mockRoomMembers(room, 3);
|
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
|
// allow calls
|
||||||
jest.spyOn(room.currentState, "mayClientSendStateEvent").mockReturnValue(true);
|
jest.spyOn(room.currentState, "mayClientSendStateEvent").mockReturnValue(true);
|
||||||
jest.spyOn(WidgetLayoutStore.instance, "isInContainer").mockReturnValue(false);
|
jest.spyOn(WidgetLayoutStore.instance, "isInContainer").mockReturnValue(false);
|
||||||
@ -427,8 +473,10 @@ describe("RoomHeader", () => {
|
|||||||
jest.spyOn(room.currentState, "maySendStateEvent").mockReturnValue(true);
|
jest.spyOn(room.currentState, "maySendStateEvent").mockReturnValue(true);
|
||||||
jest.spyOn(room, "getJoinRule").mockReturnValue(JoinRule.Invite);
|
jest.spyOn(room, "getJoinRule").mockReturnValue(JoinRule.Invite);
|
||||||
jest.spyOn(room, "canInvite").mockReturnValue(false);
|
jest.spyOn(room, "canInvite").mockReturnValue(false);
|
||||||
const guestSpaUrlMock = jest.spyOn(SdkConfig, "get").mockImplementation((key) => {
|
SdkConfig.add({
|
||||||
return { guest_spa_url: "https://guest_spa_url.com", url: "https://spa_url.com" };
|
element_call: {
|
||||||
|
guest_spa_url: "https://guest_spa_url.com",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const { container: containerNoInviteNotPublicCanUpgradeAccess } = render(
|
const { container: containerNoInviteNotPublicCanUpgradeAccess } = render(
|
||||||
<RoomHeader room={room} />,
|
<RoomHeader room={room} />,
|
||||||
@ -442,8 +490,10 @@ describe("RoomHeader", () => {
|
|||||||
jest.spyOn(room.currentState, "maySendStateEvent").mockReturnValue(false);
|
jest.spyOn(room.currentState, "maySendStateEvent").mockReturnValue(false);
|
||||||
jest.spyOn(room, "getJoinRule").mockReturnValue(JoinRule.Invite);
|
jest.spyOn(room, "getJoinRule").mockReturnValue(JoinRule.Invite);
|
||||||
jest.spyOn(room, "canInvite").mockReturnValue(false);
|
jest.spyOn(room, "canInvite").mockReturnValue(false);
|
||||||
jest.spyOn(SdkConfig, "get").mockImplementation((key) => {
|
SdkConfig.add({
|
||||||
return { guest_spa_url: "https://guest_spa_url.com", url: "https://spa_url.com" };
|
element_call: {
|
||||||
|
guest_spa_url: "https://guest_spa_url.com",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const { container: containerNoInviteNotPublic } = render(<RoomHeader room={room} />, getWrapper());
|
const { container: containerNoInviteNotPublic } = render(<RoomHeader room={room} />, getWrapper());
|
||||||
expect(queryAllByLabelText(containerNoInviteNotPublic, "There's no one here to call")).toHaveLength(2);
|
expect(queryAllByLabelText(containerNoInviteNotPublic, "There's no one here to call")).toHaveLength(2);
|
||||||
@ -463,8 +513,9 @@ describe("RoomHeader", () => {
|
|||||||
const { container: containerInvitePublic } = render(<RoomHeader room={room} />, getWrapper());
|
const { container: containerInvitePublic } = render(<RoomHeader room={room} />, getWrapper());
|
||||||
expect(queryAllByLabelText(containerInvitePublic, "There's no one here to call")).toHaveLength(0);
|
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
|
// last we can allow everything but without guest_spa_url nothing will work
|
||||||
guestSpaUrlMock.mockRestore();
|
|
||||||
const { container: containerAllAllowedButNoGuestSpaUrl } = render(<RoomHeader room={room} />, getWrapper());
|
const { container: containerAllAllowedButNoGuestSpaUrl } = render(<RoomHeader room={room} />, getWrapper());
|
||||||
expect(
|
expect(
|
||||||
queryAllByLabelText(containerAllAllowedButNoGuestSpaUrl, "There's no one here to call"),
|
queryAllByLabelText(containerAllAllowedButNoGuestSpaUrl, "There's no one here to call"),
|
||||||
@ -643,6 +694,10 @@ describe("RoomHeader", () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
SdkConfig.reset();
|
||||||
|
});
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
[ShieldUtils.E2EStatus.Verified, "Verified"],
|
[ShieldUtils.E2EStatus.Verified, "Verified"],
|
||||||
[ShieldUtils.E2EStatus.Warning, "Untrusted"],
|
[ShieldUtils.E2EStatus.Warning, "Untrusted"],
|
||||||
@ -655,6 +710,11 @@ describe("RoomHeader", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("does not show the face pile for DMs", () => {
|
it("does not show the face pile for DMs", () => {
|
||||||
|
SdkConfig.put({
|
||||||
|
features: {
|
||||||
|
feature_notifications: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
const { asFragment } = render(<RoomHeader room={room} />, getWrapper());
|
const { asFragment } = render(<RoomHeader room={room} />, getWrapper());
|
||||||
|
|
||||||
expect(asFragment()).toMatchSnapshot();
|
expect(asFragment()).toMatchSnapshot();
|
||||||
@ -751,7 +811,7 @@ describe("RoomHeader", () => {
|
|||||||
|
|
||||||
describe("ask to join enabled", () => {
|
describe("ask to join enabled", () => {
|
||||||
it("does render the RoomKnocksBar", () => {
|
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, "canInvite").mockReturnValue(true);
|
||||||
jest.spyOn(room, "getJoinRule").mockReturnValue(JoinRule.Knock);
|
jest.spyOn(room, "getJoinRule").mockReturnValue(JoinRule.Knock);
|
||||||
jest.spyOn(room, "getMembersWithMembership").mockReturnValue([new RoomMember(room.roomId, "@foo")]);
|
jest.spyOn(room, "getMembersWithMembership").mockReturnValue([new RoomMember(room.roomId, "@foo")]);
|
||||||
|
|||||||
@ -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);"
|
style="--cpd-icon-button-size: 100%; --cpd-color-icon-tertiary: var(--cpd-color-icon-disabled);"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
aria-labelledby=":r15i:"
|
aria-labelledby=":r1c8:"
|
||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
height="1em"
|
height="1em"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@ -71,7 +71,7 @@ exports[`RoomHeader dm does not show the face pile for DMs 1`] = `
|
|||||||
<button
|
<button
|
||||||
aria-disabled="true"
|
aria-disabled="true"
|
||||||
aria-label="There's no one here to call"
|
aria-label="There's no one here to call"
|
||||||
aria-labelledby=":r15n:"
|
aria-labelledby=":r1cd:"
|
||||||
class="_icon-button_m2erp_8"
|
class="_icon-button_m2erp_8"
|
||||||
role="button"
|
role="button"
|
||||||
style="--cpd-icon-button-size: 32px;"
|
style="--cpd-icon-button-size: 32px;"
|
||||||
@ -96,7 +96,7 @@ exports[`RoomHeader dm does not show the face pile for DMs 1`] = `
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
aria-label="Threads"
|
aria-label="Threads"
|
||||||
aria-labelledby=":r15s:"
|
aria-labelledby=":r1ci:"
|
||||||
class="_icon-button_m2erp_8"
|
class="_icon-button_m2erp_8"
|
||||||
role="button"
|
role="button"
|
||||||
style="--cpd-icon-button-size: 32px;"
|
style="--cpd-icon-button-size: 32px;"
|
||||||
@ -122,7 +122,7 @@ exports[`RoomHeader dm does not show the face pile for DMs 1`] = `
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
aria-label="Room info"
|
aria-label="Room info"
|
||||||
aria-labelledby=":r161:"
|
aria-labelledby=":r1cn:"
|
||||||
class="_icon-button_m2erp_8"
|
class="_icon-button_m2erp_8"
|
||||||
role="button"
|
role="button"
|
||||||
style="--cpd-icon-button-size: 32px;"
|
style="--cpd-icon-button-size: 32px;"
|
||||||
|
|||||||
@ -37,6 +37,10 @@ describe("NotificatinSettingsTab", () => {
|
|||||||
NotificationSettingsTab.contextType = React.createContext<MatrixClient>(cli);
|
NotificationSettingsTab.contextType = React.createContext<MatrixClient>(cli);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
SettingsStore.reset();
|
||||||
|
});
|
||||||
|
|
||||||
it("should prevent »Settings« link click from bubbling up to radio buttons", async () => {
|
it("should prevent »Settings« link click from bubbling up to radio buttons", async () => {
|
||||||
const tab = renderTab();
|
const tab = renderTab();
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2024 New Vector Ltd.
|
Copyright 2024, 2025 New Vector Ltd.
|
||||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
@ -28,13 +28,13 @@ import {
|
|||||||
getMarkedUnreadState,
|
getMarkedUnreadState,
|
||||||
setMarkedUnreadState,
|
setMarkedUnreadState,
|
||||||
} from "../../../src/utils/notifications";
|
} from "../../../src/utils/notifications";
|
||||||
import SettingsStore from "../../../src/settings/SettingsStore";
|
import { getMockClientWithEventEmitter, mockClientMethodsServer } from "../../test-utils/client";
|
||||||
import { getMockClientWithEventEmitter } from "../../test-utils/client";
|
|
||||||
import { mkMessage, stubClient } from "../../test-utils/test-utils";
|
import { mkMessage, stubClient } from "../../test-utils/test-utils";
|
||||||
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
|
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
|
||||||
import { NotificationLevel } from "../../../src/stores/notifications/NotificationLevel";
|
import { NotificationLevel } from "../../../src/stores/notifications/NotificationLevel";
|
||||||
|
import { SettingLevel } from "../../../src/settings/SettingLevel";
|
||||||
jest.mock("../../../src/settings/SettingsStore");
|
import MatrixClientBackedController from "../../../src/settings/controllers/MatrixClientBackedController";
|
||||||
|
import SettingsStore from "../../../src/settings/SettingsStore";
|
||||||
|
|
||||||
describe("notifications", () => {
|
describe("notifications", () => {
|
||||||
let accountDataStore: Record<string, MatrixEvent> = {};
|
let accountDataStore: Record<string, MatrixEvent> = {};
|
||||||
@ -44,6 +44,7 @@ describe("notifications", () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
mockClient = getMockClientWithEventEmitter({
|
mockClient = getMockClientWithEventEmitter({
|
||||||
|
...mockClientMethodsServer(),
|
||||||
isGuest: jest.fn().mockReturnValue(false),
|
isGuest: jest.fn().mockReturnValue(false),
|
||||||
getAccountData: jest.fn().mockImplementation((eventType) => accountDataStore[eventType]),
|
getAccountData: jest.fn().mockImplementation((eventType) => accountDataStore[eventType]),
|
||||||
setAccountData: jest.fn().mockImplementation((eventType, content) => {
|
setAccountData: jest.fn().mockImplementation((eventType, content) => {
|
||||||
@ -52,10 +53,20 @@ describe("notifications", () => {
|
|||||||
content,
|
content,
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
isVersionSupported: jest.fn().mockImplementation(async (v) => v === "v1.4"),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Ensure unstable settings are supported, otherwise it will use the default value.
|
||||||
|
MatrixClientBackedController.matrixClient = mockClient;
|
||||||
accountDataStore = {};
|
accountDataStore = {};
|
||||||
accountDataEventKey = getLocalNotificationAccountDataEventType(mockClient.deviceId!);
|
accountDataEventKey = getLocalNotificationAccountDataEventType(mockClient.deviceId!);
|
||||||
mocked(SettingsStore).getValue.mockReturnValue(false);
|
// Disable all notifications
|
||||||
|
deviceNotificationSettingsKeys.forEach((k) => SettingsStore.setValue(k, null, SettingLevel.DEVICE, false));
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.restoreAllMocks();
|
||||||
|
SettingsStore.reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("createLocalNotification", () => {
|
describe("createLocalNotification", () => {
|
||||||
@ -75,10 +86,15 @@ describe("notifications", () => {
|
|||||||
it.each(deviceNotificationSettingsKeys)(
|
it.each(deviceNotificationSettingsKeys)(
|
||||||
"unsilenced for existing sessions when %s setting is truthy",
|
"unsilenced for existing sessions when %s setting is truthy",
|
||||||
async (settingKey) => {
|
async (settingKey) => {
|
||||||
mocked(SettingsStore).getValue.mockImplementation((key): any => {
|
// We need to spy `getValue` because setting these keys requires mocking
|
||||||
return key === settingKey;
|
// the platform to support notifications, which is out of scope for this test.
|
||||||
|
const origFn = SettingsStore.getValue;
|
||||||
|
jest.spyOn(SettingsStore, "getValue").mockImplementation((name, ...args) => {
|
||||||
|
if (name === settingKey) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return origFn(name, ...args);
|
||||||
});
|
});
|
||||||
|
|
||||||
await createLocalNotificationSettingsIfNeeded(mockClient);
|
await createLocalNotificationSettingsIfNeeded(mockClient);
|
||||||
const event = mockClient.getAccountData(accountDataEventKey);
|
const event = mockClient.getAccountData(accountDataEventKey);
|
||||||
expect(event?.getContent().is_silenced).toBe(false);
|
expect(event?.getContent().is_silenced).toBe(false);
|
||||||
@ -116,7 +132,6 @@ describe("notifications", () => {
|
|||||||
const ROOM_ID = "123";
|
const ROOM_ID = "123";
|
||||||
const USER_ID = "@bob:example.org";
|
const USER_ID = "@bob:example.org";
|
||||||
let message: MatrixEvent;
|
let message: MatrixEvent;
|
||||||
let sendReceiptsSetting = true;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
stubClient();
|
stubClient();
|
||||||
@ -131,9 +146,7 @@ describe("notifications", () => {
|
|||||||
room.addLiveEvents([message], { addToState: true });
|
room.addLiveEvents([message], { addToState: true });
|
||||||
sendReadReceiptSpy = jest.spyOn(client, "sendReadReceipt").mockResolvedValue({});
|
sendReadReceiptSpy = jest.spyOn(client, "sendReadReceipt").mockResolvedValue({});
|
||||||
jest.spyOn(client, "getRooms").mockReturnValue([room]);
|
jest.spyOn(client, "getRooms").mockReturnValue([room]);
|
||||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((name) => {
|
SettingsStore.setValue("sendReadReceipts", null, SettingLevel.DEVICE, true);
|
||||||
return name === "sendReadReceipts" && sendReceiptsSetting;
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("sends a request even if everything has been read", async () => {
|
it("sends a request even if everything has been read", async () => {
|
||||||
@ -152,11 +165,8 @@ describe("notifications", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("when sendReadReceipts setting is disabled", () => {
|
describe("when sendReadReceipts setting is disabled", () => {
|
||||||
beforeEach(() => {
|
|
||||||
sendReceiptsSetting = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should send a private read receipt", async () => {
|
it("should send a private read receipt", async () => {
|
||||||
|
SettingsStore.setValue("sendReadReceipts", null, SettingLevel.DEVICE, false);
|
||||||
await clearRoomNotification(room, client);
|
await clearRoomNotification(room, client);
|
||||||
expect(sendReadReceiptSpy).toHaveBeenCalledWith(message, ReceiptType.ReadPrivate, true);
|
expect(sendReadReceiptSpy).toHaveBeenCalledWith(message, ReceiptType.ReadPrivate, true);
|
||||||
});
|
});
|
||||||
@ -177,9 +187,7 @@ describe("notifications", () => {
|
|||||||
room = new Room(ROOM_ID, client, USER_ID);
|
room = new Room(ROOM_ID, client, USER_ID);
|
||||||
sendReadReceiptSpy = jest.spyOn(client, "sendReadReceipt").mockResolvedValue({});
|
sendReadReceiptSpy = jest.spyOn(client, "sendReadReceipt").mockResolvedValue({});
|
||||||
jest.spyOn(client, "getRooms").mockReturnValue([room]);
|
jest.spyOn(client, "getRooms").mockReturnValue([room]);
|
||||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((name) => {
|
SettingsStore.setValue("sendReadReceipts", null, SettingLevel.DEVICE, true);
|
||||||
return name === "sendReadReceipts";
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not send any requests if everything has been read", () => {
|
it("does not send any requests if everything has been read", () => {
|
||||||
@ -212,7 +220,7 @@ describe("notifications", () => {
|
|||||||
room.addLiveEvents([message], { addToState: true });
|
room.addLiveEvents([message], { addToState: true });
|
||||||
room.setUnreadNotificationCount(NotificationCountType.Total, 1);
|
room.setUnreadNotificationCount(NotificationCountType.Total, 1);
|
||||||
|
|
||||||
jest.spyOn(SettingsStore, "getValue").mockReset().mockReturnValue(false);
|
SettingsStore.setValue("sendReadReceipts", null, SettingLevel.DEVICE, false);
|
||||||
|
|
||||||
await clearAllNotifications(client);
|
await clearAllNotifications(client);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user