GYU: Account Notification Settings (#11008)
* Implement new notification settings UI * Sort new keywords at the front * Make ts-strict happier * Make ts-strict happier * chore: fixed lint issues * update beta card * Fix issue with the user settings test * chore: fixed lint issues * Add tests for notification settings * chore: fixed lint issues * fix: spurious text failures * improve tests further * make ts-strict happier * improve tests further * Reduce uncovered conditions * Correct snapshot * even more test coverage * Fix an issue with inverted rules * Update res/css/views/settings/tabs/_SettingsIndent.pcss Co-authored-by: Šimon Brandner <simon.bra.ag@gmail.com> * Fix license headers * Improve i18n * make linters happier * Improve beta labels * improve i18n * chore: fixed lint issues * fix: more lint issues * Update snapshots to match changed text * Update text as requested * Remove labs image * Update snapshots * Correct an issue with one of the tests * fix: keyword reconcilation code * Determine mute status more accurately * Address review comments * Prevent duplicate updates * Fix missing license header * slight change to avoid ts-strict complaining * fix test issue caused by previous merge --------- Co-authored-by: Šimon Brandner <simon.bra.ag@gmail.com>
This commit is contained in:
parent
95283d21bb
commit
f62fe2626c
25 changed files with 3797 additions and 33 deletions
|
@ -0,0 +1,762 @@
|
|||
/*
|
||||
Copyright 2022-2023 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { act, findByRole, getByRole, queryByRole, render, waitFor } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { ThreepidMedium } from "matrix-js-sdk/src/@types/threepids";
|
||||
import { IPushRules, MatrixClient, NotificationCountType, PushRuleKind, Room, RuleId } from "matrix-js-sdk/src/matrix";
|
||||
import React from "react";
|
||||
|
||||
import NotificationSettings2 from "../../../../../src/components/views/settings/notifications/NotificationSettings2";
|
||||
import MatrixClientContext from "../../../../../src/contexts/MatrixClientContext";
|
||||
import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg";
|
||||
import { StandardActions } from "../../../../../src/notifications/StandardActions";
|
||||
import { PredictableRandom } from "../../../../predictableRandom";
|
||||
import { mkMessage, stubClient } from "../../../../test-utils";
|
||||
import Mock = jest.Mock;
|
||||
|
||||
const mockRandom = new PredictableRandom();
|
||||
|
||||
// Fake random strings to give a predictable snapshot for IDs
|
||||
jest.mock("matrix-js-sdk/src/randomstring", () => ({
|
||||
randomString: jest.fn((len): string => {
|
||||
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
let ret = "";
|
||||
|
||||
for (let i = 0; i < len; ++i) {
|
||||
ret += chars.charAt(Math.floor(mockRandom.get() * chars.length));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}),
|
||||
}));
|
||||
|
||||
const waitForUpdate = (): Promise<void> => new Promise((resolve) => setTimeout(resolve));
|
||||
|
||||
const labelGlobalMute = "Enable notifications for this account";
|
||||
const labelLevelAllMessage = "All messages";
|
||||
const labelLevelMentionsOnly = "Mentions and Keywords only";
|
||||
const labelSoundPeople = "People";
|
||||
const labelSoundMentions = "Mentions and Keywords";
|
||||
const labelSoundCalls = "Audio and Video calls";
|
||||
const labelActivityInvites = "Invited to a room";
|
||||
const labelActivityStatus = "New room activity, upgrades and status messages occur";
|
||||
const labelActivityBots = "Messages sent by bots";
|
||||
const labelMentionUser = "Notify when someone mentions using @displayname or @mxid";
|
||||
const labelMentionRoom = "Notify when someone mentions using @room";
|
||||
const labelMentionKeyword =
|
||||
"Notify when someone uses a keyword" + "Enter keywords here, or use for spelling variations or nicknames";
|
||||
const labelResetDefault = "Reset to default settings";
|
||||
|
||||
const keywords = ["justjann3", "justj4nn3", "justj4nne", "Janne", "J4nne", "Jann3", "jann3", "j4nne", "janne"];
|
||||
|
||||
describe("<Notifications />", () => {
|
||||
let cli: MatrixClient;
|
||||
let pushRules: IPushRules;
|
||||
|
||||
beforeAll(async () => {
|
||||
pushRules = (await import("../../../../models/notificationsettings/pushrules_sample.json")) as IPushRules;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
stubClient();
|
||||
cli = MatrixClientPeg.safeGet();
|
||||
cli.getPushRules = jest.fn(cli.getPushRules).mockResolvedValue(pushRules);
|
||||
cli.supportsIntentionalMentions = jest.fn(cli.supportsIntentionalMentions).mockReturnValue(false);
|
||||
cli.setPushRuleEnabled = jest.fn(cli.setPushRuleEnabled);
|
||||
cli.setPushRuleActions = jest.fn(cli.setPushRuleActions);
|
||||
cli.addPushRule = jest.fn(cli.addPushRule).mockResolvedValue({});
|
||||
cli.deletePushRule = jest.fn(cli.deletePushRule).mockResolvedValue({});
|
||||
cli.removePusher = jest.fn(cli.removePusher).mockResolvedValue({});
|
||||
cli.setPusher = jest.fn(cli.setPusher).mockResolvedValue({});
|
||||
|
||||
mockRandom.reset();
|
||||
});
|
||||
|
||||
it("matches the snapshot", async () => {
|
||||
cli.getPushers = jest.fn(cli.getPushers).mockResolvedValue({
|
||||
pushers: [
|
||||
{
|
||||
app_display_name: "Element",
|
||||
app_id: "im.vector.app",
|
||||
data: {},
|
||||
device_display_name: "My EyeFon",
|
||||
kind: "http",
|
||||
lang: "en",
|
||||
pushkey: "",
|
||||
enabled: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
cli.getThreePids = jest.fn(cli.getThreePids).mockResolvedValue({
|
||||
threepids: [
|
||||
{
|
||||
medium: ThreepidMedium.Email,
|
||||
address: "test@example.tld",
|
||||
validated_at: 1656633600,
|
||||
added_at: 1656633600,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const screen = render(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<NotificationSettings2 />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await act(waitForUpdate);
|
||||
expect(screen.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("correctly handles the loading/disabled state", async () => {
|
||||
(cli.getPushRules as Mock).mockReturnValue(new Promise<IPushRules>(() => {}));
|
||||
|
||||
const user = userEvent.setup();
|
||||
const screen = render(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<NotificationSettings2 />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await act(async () => {
|
||||
await waitForUpdate();
|
||||
expect(screen.container).toMatchSnapshot();
|
||||
|
||||
const globalMute = screen.getByLabelText(labelGlobalMute);
|
||||
expect(globalMute).toHaveAttribute("aria-disabled", "true");
|
||||
|
||||
const levelAllMessages = screen.getByLabelText(labelLevelAllMessage);
|
||||
expect(levelAllMessages).toBeDisabled();
|
||||
|
||||
const soundPeople = screen.getByLabelText(labelSoundPeople);
|
||||
expect(soundPeople).toBeDisabled();
|
||||
const soundMentions = screen.getByLabelText(labelSoundMentions);
|
||||
expect(soundMentions).toBeDisabled();
|
||||
const soundCalls = screen.getByLabelText(labelSoundCalls);
|
||||
expect(soundCalls).toBeDisabled();
|
||||
|
||||
const activityInvites = screen.getByLabelText(labelActivityInvites);
|
||||
expect(activityInvites).toBeDisabled();
|
||||
const activityStatus = screen.getByLabelText(labelActivityStatus);
|
||||
expect(activityStatus).toBeDisabled();
|
||||
const activityBots = screen.getByLabelText(labelActivityBots);
|
||||
expect(activityBots).toBeDisabled();
|
||||
|
||||
const mentionUser = screen.getByLabelText(labelMentionUser.replace("@mxid", cli.getUserId()!));
|
||||
expect(mentionUser).toBeDisabled();
|
||||
const mentionRoom = screen.getByLabelText(labelMentionRoom);
|
||||
expect(mentionRoom).toBeDisabled();
|
||||
const mentionKeyword = screen.getByLabelText(labelMentionKeyword);
|
||||
expect(mentionKeyword).toBeDisabled();
|
||||
await Promise.all([
|
||||
user.click(globalMute),
|
||||
user.click(levelAllMessages),
|
||||
user.click(soundPeople),
|
||||
user.click(soundMentions),
|
||||
user.click(soundCalls),
|
||||
user.click(activityInvites),
|
||||
user.click(activityStatus),
|
||||
user.click(activityBots),
|
||||
user.click(mentionUser),
|
||||
user.click(mentionRoom),
|
||||
user.click(mentionKeyword),
|
||||
]);
|
||||
});
|
||||
|
||||
expect(cli.setPushRuleActions).not.toHaveBeenCalled();
|
||||
expect(cli.setPushRuleEnabled).not.toHaveBeenCalled();
|
||||
expect(cli.addPushRule).not.toHaveBeenCalled();
|
||||
expect(cli.deletePushRule).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("form elements actually toggle the model value", () => {
|
||||
it("global mute", async () => {
|
||||
const label = labelGlobalMute;
|
||||
|
||||
const user = userEvent.setup();
|
||||
const screen = render(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<NotificationSettings2 />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await act(waitForUpdate);
|
||||
expect(screen.getByLabelText(label)).not.toBeDisabled();
|
||||
await act(async () => {
|
||||
await user.click(screen.getByLabelText(label));
|
||||
await waitForUpdate();
|
||||
});
|
||||
expect(cli.setPushRuleEnabled).toHaveBeenCalledWith("global", PushRuleKind.Override, RuleId.Master, true);
|
||||
});
|
||||
|
||||
it("notification level", async () => {
|
||||
const user = userEvent.setup();
|
||||
const screen = render(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<NotificationSettings2 />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await act(waitForUpdate);
|
||||
expect(screen.getByLabelText(labelLevelAllMessage)).not.toBeDisabled();
|
||||
await act(async () => {
|
||||
await user.click(screen.getByLabelText(labelLevelAllMessage));
|
||||
await waitForUpdate();
|
||||
});
|
||||
expect(cli.setPushRuleEnabled).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Underride,
|
||||
RuleId.EncryptedMessage,
|
||||
true,
|
||||
);
|
||||
expect(cli.setPushRuleEnabled).toHaveBeenCalledWith("global", PushRuleKind.Underride, RuleId.Message, true);
|
||||
(cli.setPushRuleEnabled as Mock).mockClear();
|
||||
expect(screen.getByLabelText(labelLevelMentionsOnly)).not.toBeDisabled();
|
||||
await act(async () => {
|
||||
await user.click(screen.getByLabelText(labelLevelMentionsOnly));
|
||||
await waitForUpdate();
|
||||
});
|
||||
expect(cli.setPushRuleEnabled).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Underride,
|
||||
RuleId.EncryptedDM,
|
||||
true,
|
||||
);
|
||||
expect(cli.setPushRuleEnabled).toHaveBeenCalledWith("global", PushRuleKind.Underride, RuleId.DM, true);
|
||||
});
|
||||
|
||||
describe("play a sound for", () => {
|
||||
it("people", async () => {
|
||||
const label = labelSoundPeople;
|
||||
|
||||
const user = userEvent.setup();
|
||||
const screen = render(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<NotificationSettings2 />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await act(waitForUpdate);
|
||||
expect(screen.getByLabelText(label)).not.toBeDisabled();
|
||||
await act(async () => {
|
||||
await user.click(screen.getByLabelText(label));
|
||||
await waitForUpdate();
|
||||
});
|
||||
expect(cli.setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Underride,
|
||||
RuleId.EncryptedDM,
|
||||
StandardActions.ACTION_NOTIFY_DEFAULT_SOUND,
|
||||
);
|
||||
expect(cli.setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Underride,
|
||||
RuleId.DM,
|
||||
StandardActions.ACTION_NOTIFY_DEFAULT_SOUND,
|
||||
);
|
||||
expect(cli.setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Override,
|
||||
RuleId.InviteToSelf,
|
||||
StandardActions.ACTION_NOTIFY_DEFAULT_SOUND,
|
||||
);
|
||||
});
|
||||
|
||||
it("mentions", async () => {
|
||||
const label = labelSoundMentions;
|
||||
|
||||
const user = userEvent.setup();
|
||||
const screen = render(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<NotificationSettings2 />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await act(waitForUpdate);
|
||||
expect(screen.getByLabelText(label)).not.toBeDisabled();
|
||||
await act(async () => {
|
||||
await user.click(screen.getByLabelText(label));
|
||||
await waitForUpdate();
|
||||
});
|
||||
expect(cli.setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Override,
|
||||
RuleId.ContainsDisplayName,
|
||||
StandardActions.ACTION_HIGHLIGHT,
|
||||
);
|
||||
expect(cli.setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.ContentSpecific,
|
||||
RuleId.ContainsUserName,
|
||||
StandardActions.ACTION_HIGHLIGHT,
|
||||
);
|
||||
});
|
||||
|
||||
it("calls", async () => {
|
||||
const label = labelSoundCalls;
|
||||
|
||||
const user = userEvent.setup();
|
||||
const screen = render(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<NotificationSettings2 />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await act(waitForUpdate);
|
||||
expect(screen.getByLabelText(label)).not.toBeDisabled();
|
||||
await act(async () => {
|
||||
await user.click(screen.getByLabelText(label));
|
||||
await waitForUpdate();
|
||||
});
|
||||
expect(cli.setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Underride,
|
||||
RuleId.IncomingCall,
|
||||
StandardActions.ACTION_NOTIFY,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("activity", () => {
|
||||
it("invite", async () => {
|
||||
const label = labelActivityInvites;
|
||||
|
||||
const user = userEvent.setup();
|
||||
const screen = render(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<NotificationSettings2 />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await act(waitForUpdate);
|
||||
expect(screen.getByLabelText(label)).not.toBeDisabled();
|
||||
await act(async () => {
|
||||
await user.click(screen.getByLabelText(label));
|
||||
await waitForUpdate();
|
||||
});
|
||||
expect(cli.setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Override,
|
||||
RuleId.InviteToSelf,
|
||||
StandardActions.ACTION_NOTIFY,
|
||||
);
|
||||
});
|
||||
it("status messages", async () => {
|
||||
const label = labelActivityStatus;
|
||||
|
||||
const user = userEvent.setup();
|
||||
const screen = render(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<NotificationSettings2 />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await act(waitForUpdate);
|
||||
expect(screen.getByLabelText(label)).not.toBeDisabled();
|
||||
await act(async () => {
|
||||
await user.click(screen.getByLabelText(label));
|
||||
await waitForUpdate();
|
||||
});
|
||||
expect(cli.setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Override,
|
||||
RuleId.MemberEvent,
|
||||
StandardActions.ACTION_NOTIFY,
|
||||
);
|
||||
expect(cli.setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Override,
|
||||
RuleId.Tombstone,
|
||||
StandardActions.ACTION_HIGHLIGHT,
|
||||
);
|
||||
});
|
||||
it("notices", async () => {
|
||||
const label = labelActivityBots;
|
||||
|
||||
const user = userEvent.setup();
|
||||
const screen = render(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<NotificationSettings2 />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await act(waitForUpdate);
|
||||
expect(screen.getByLabelText(label)).not.toBeDisabled();
|
||||
await act(async () => {
|
||||
await user.click(screen.getByLabelText(label));
|
||||
await waitForUpdate();
|
||||
});
|
||||
expect(cli.setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Override,
|
||||
RuleId.SuppressNotices,
|
||||
StandardActions.ACTION_DONT_NOTIFY,
|
||||
);
|
||||
});
|
||||
});
|
||||
describe("mentions", () => {
|
||||
it("room mentions", async () => {
|
||||
const label = labelMentionRoom;
|
||||
|
||||
const user = userEvent.setup();
|
||||
const screen = render(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<NotificationSettings2 />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await act(waitForUpdate);
|
||||
expect(screen.getByLabelText(label)).not.toBeDisabled();
|
||||
await act(async () => {
|
||||
await user.click(screen.getByLabelText(label));
|
||||
await waitForUpdate();
|
||||
});
|
||||
expect(cli.setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Override,
|
||||
RuleId.AtRoomNotification,
|
||||
StandardActions.ACTION_DONT_NOTIFY,
|
||||
);
|
||||
});
|
||||
it("user mentions", async () => {
|
||||
const label = labelMentionUser.replace("@mxid", cli.getUserId()!);
|
||||
|
||||
const user = userEvent.setup();
|
||||
const screen = render(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<NotificationSettings2 />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await act(waitForUpdate);
|
||||
expect(screen.getByLabelText(label)).not.toBeDisabled();
|
||||
await act(async () => {
|
||||
await user.click(screen.getByLabelText(label));
|
||||
await waitForUpdate();
|
||||
});
|
||||
expect(cli.setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Override,
|
||||
RuleId.ContainsDisplayName,
|
||||
StandardActions.ACTION_DONT_NOTIFY,
|
||||
);
|
||||
expect(cli.setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.ContentSpecific,
|
||||
RuleId.ContainsUserName,
|
||||
StandardActions.ACTION_DONT_NOTIFY,
|
||||
);
|
||||
});
|
||||
it("keywords", async () => {
|
||||
const label = labelMentionKeyword;
|
||||
|
||||
const user = userEvent.setup();
|
||||
const screen = render(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<NotificationSettings2 />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await act(waitForUpdate);
|
||||
expect(screen.getByLabelText(label)).not.toBeDisabled();
|
||||
await act(async () => {
|
||||
await user.click(screen.getByLabelText(label));
|
||||
await waitForUpdate();
|
||||
});
|
||||
for (const pattern of keywords) {
|
||||
expect(cli.setPushRuleEnabled).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.ContentSpecific,
|
||||
pattern,
|
||||
false,
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
describe("keywords", () => {
|
||||
it("allows adding keywords", async () => {
|
||||
const user = userEvent.setup();
|
||||
const screen = render(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<NotificationSettings2 />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await act(waitForUpdate);
|
||||
const inputField = screen.getByRole("textbox", { name: "Keyword" });
|
||||
const addButton = screen.getByRole("button", { name: "Add" });
|
||||
expect(inputField).not.toBeDisabled();
|
||||
expect(addButton).not.toBeDisabled();
|
||||
await act(async () => {
|
||||
await user.type(inputField, "testkeyword");
|
||||
await user.click(addButton);
|
||||
await waitForUpdate();
|
||||
});
|
||||
expect(cli.addPushRule).toHaveBeenCalledWith("global", PushRuleKind.ContentSpecific, "testkeyword", {
|
||||
kind: PushRuleKind.ContentSpecific,
|
||||
rule_id: "testkeyword",
|
||||
enabled: true,
|
||||
default: false,
|
||||
actions: StandardActions.ACTION_HIGHLIGHT_DEFAULT_SOUND,
|
||||
pattern: "testkeyword",
|
||||
});
|
||||
});
|
||||
|
||||
it("allows deleting keywords", async () => {
|
||||
const user = userEvent.setup();
|
||||
const screen = render(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<NotificationSettings2 />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await act(waitForUpdate);
|
||||
const tag = screen.getByText("justj4nn3");
|
||||
const deleteButton = getByRole(tag, "button", { name: "Remove" });
|
||||
expect(deleteButton).not.toBeDisabled();
|
||||
await act(async () => {
|
||||
await user.click(deleteButton);
|
||||
await waitForUpdate();
|
||||
});
|
||||
expect(cli.deletePushRule).toHaveBeenCalledWith("global", PushRuleKind.ContentSpecific, "justj4nn3");
|
||||
});
|
||||
});
|
||||
|
||||
it("resets the model correctly", async () => {
|
||||
const user = userEvent.setup();
|
||||
const screen = render(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<NotificationSettings2 />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await act(waitForUpdate);
|
||||
const button = screen.getByText(labelResetDefault);
|
||||
expect(button).not.toBeDisabled();
|
||||
await act(async () => {
|
||||
await user.click(button);
|
||||
await waitForUpdate();
|
||||
});
|
||||
expect(cli.setPushRuleEnabled).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Underride,
|
||||
RuleId.EncryptedMessage,
|
||||
true,
|
||||
);
|
||||
expect(cli.setPushRuleEnabled).toHaveBeenCalledWith("global", PushRuleKind.Underride, RuleId.Message, true);
|
||||
expect(cli.setPushRuleEnabled).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Underride,
|
||||
RuleId.EncryptedDM,
|
||||
true,
|
||||
);
|
||||
expect(cli.setPushRuleEnabled).toHaveBeenCalledWith("global", PushRuleKind.Underride, RuleId.DM, true);
|
||||
expect(cli.setPushRuleEnabled).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Override,
|
||||
RuleId.SuppressNotices,
|
||||
false,
|
||||
);
|
||||
expect(cli.setPushRuleEnabled).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Override,
|
||||
RuleId.InviteToSelf,
|
||||
true,
|
||||
);
|
||||
|
||||
expect(cli.setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Underride,
|
||||
RuleId.EncryptedMessage,
|
||||
StandardActions.ACTION_NOTIFY,
|
||||
);
|
||||
expect(cli.setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Underride,
|
||||
RuleId.Message,
|
||||
StandardActions.ACTION_NOTIFY,
|
||||
);
|
||||
expect(cli.setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Underride,
|
||||
RuleId.EncryptedDM,
|
||||
StandardActions.ACTION_NOTIFY_DEFAULT_SOUND,
|
||||
);
|
||||
expect(cli.setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Underride,
|
||||
RuleId.DM,
|
||||
StandardActions.ACTION_NOTIFY_DEFAULT_SOUND,
|
||||
);
|
||||
expect(cli.setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Override,
|
||||
RuleId.SuppressNotices,
|
||||
StandardActions.ACTION_DONT_NOTIFY,
|
||||
);
|
||||
expect(cli.setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Override,
|
||||
RuleId.InviteToSelf,
|
||||
StandardActions.ACTION_NOTIFY_DEFAULT_SOUND,
|
||||
);
|
||||
|
||||
for (const pattern of keywords) {
|
||||
expect(cli.deletePushRule).toHaveBeenCalledWith("global", PushRuleKind.ContentSpecific, pattern);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("pusher settings", () => {
|
||||
it("can create email pushers", async () => {
|
||||
cli.getPushers = jest.fn(cli.getPushers).mockResolvedValue({
|
||||
pushers: [
|
||||
{
|
||||
app_display_name: "Element",
|
||||
app_id: "im.vector.app",
|
||||
data: {},
|
||||
device_display_name: "My EyeFon",
|
||||
kind: "http",
|
||||
lang: "en",
|
||||
pushkey: "",
|
||||
enabled: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
cli.getThreePids = jest.fn(cli.getThreePids).mockResolvedValue({
|
||||
threepids: [
|
||||
{
|
||||
medium: ThreepidMedium.Email,
|
||||
address: "test@example.tld",
|
||||
validated_at: 1656633600,
|
||||
added_at: 1656633600,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const label = "test@example.tld";
|
||||
const user = userEvent.setup();
|
||||
const screen = render(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<NotificationSettings2 />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await act(waitForUpdate);
|
||||
expect(screen.getByLabelText(label)).not.toBeDisabled();
|
||||
await act(async () => {
|
||||
await user.click(screen.getByLabelText(label));
|
||||
await waitForUpdate();
|
||||
});
|
||||
expect(cli.setPusher).toHaveBeenCalledWith({
|
||||
app_display_name: "Email Notifications",
|
||||
app_id: "m.email",
|
||||
append: true,
|
||||
data: { brand: "Element" },
|
||||
device_display_name: "test@example.tld",
|
||||
kind: "email",
|
||||
lang: "en-US",
|
||||
pushkey: "test@example.tld",
|
||||
});
|
||||
});
|
||||
|
||||
it("can remove email pushers", async () => {
|
||||
cli.getPushers = jest.fn(cli.getPushers).mockResolvedValue({
|
||||
pushers: [
|
||||
{
|
||||
app_display_name: "Element",
|
||||
app_id: "im.vector.app",
|
||||
data: {},
|
||||
device_display_name: "My EyeFon",
|
||||
kind: "http",
|
||||
lang: "en",
|
||||
pushkey: "abctest",
|
||||
},
|
||||
{
|
||||
app_display_name: "Email Notifications",
|
||||
app_id: "m.email",
|
||||
data: { brand: "Element" },
|
||||
device_display_name: "test@example.tld",
|
||||
kind: "email",
|
||||
lang: "en-US",
|
||||
pushkey: "test@example.tld",
|
||||
},
|
||||
],
|
||||
});
|
||||
cli.getThreePids = jest.fn(cli.getThreePids).mockResolvedValue({
|
||||
threepids: [
|
||||
{
|
||||
medium: ThreepidMedium.Email,
|
||||
address: "test@example.tld",
|
||||
validated_at: 1656633600,
|
||||
added_at: 1656633600,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const label = "test@example.tld";
|
||||
const user = userEvent.setup();
|
||||
const screen = render(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<NotificationSettings2 />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await act(waitForUpdate);
|
||||
expect(screen.getByLabelText(label)).not.toBeDisabled();
|
||||
await act(async () => {
|
||||
await user.click(screen.getByLabelText(label));
|
||||
await waitForUpdate();
|
||||
});
|
||||
expect(cli.removePusher).toHaveBeenCalledWith("test@example.tld", "m.email");
|
||||
});
|
||||
});
|
||||
|
||||
describe("clear all notifications", () => {
|
||||
it("is hidden when no notifications exist", async () => {
|
||||
const room = new Room("room123", cli, "@alice:example.org");
|
||||
cli.getRooms = jest.fn(cli.getRooms).mockReturnValue([room]);
|
||||
|
||||
const { container } = render(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<NotificationSettings2 />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await waitForUpdate();
|
||||
expect(
|
||||
queryByRole(container, "button", {
|
||||
name: "Mark all messages as read",
|
||||
}),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("clears all notifications", async () => {
|
||||
const room = new Room("room123", cli, "@alice:example.org");
|
||||
cli.getRooms = jest.fn(cli.getRooms).mockReturnValue([room]);
|
||||
|
||||
const message = mkMessage({
|
||||
event: true,
|
||||
room: "room123",
|
||||
user: "@alice:example.org",
|
||||
ts: 1,
|
||||
});
|
||||
room.addLiveEvents([message]);
|
||||
room.setUnreadNotificationCount(NotificationCountType.Total, 1);
|
||||
|
||||
const user = userEvent.setup();
|
||||
const { container } = render(
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<NotificationSettings2 />
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
await waitForUpdate();
|
||||
const clearNotificationEl = await findByRole(container, "button", {
|
||||
name: "Mark all messages as read",
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
await user.click(clearNotificationEl);
|
||||
await waitForUpdate();
|
||||
});
|
||||
expect(cli.sendReadReceipt).toHaveBeenCalled();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(clearNotificationEl).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
File diff suppressed because it is too large
Load diff
|
@ -79,6 +79,56 @@ exports[`<LabsUserSettingsTab /> renders settings marked as beta as beta cards 1
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_BetaCard"
|
||||
>
|
||||
<div
|
||||
class="mx_BetaCard_columns"
|
||||
>
|
||||
<div
|
||||
class="mx_BetaCard_columns_description"
|
||||
>
|
||||
<h3
|
||||
class="mx_BetaCard_title"
|
||||
>
|
||||
<span>
|
||||
Notification Settings
|
||||
</span>
|
||||
<span
|
||||
class="mx_BetaCard_betaPill"
|
||||
>
|
||||
Beta
|
||||
</span>
|
||||
</h3>
|
||||
<div
|
||||
class="mx_BetaCard_caption"
|
||||
>
|
||||
<p>
|
||||
Introducing a simpler way to change your notification settings. Customize your , just the way you like.
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="mx_BetaCard_buttons"
|
||||
>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Join the beta
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_BetaCard_columns_image_wrapper"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
class="mx_BetaCard_columns_image"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue