Merge matrix-react-sdk into element-web
Merge remote-tracking branch 'repomerge/t3chguy/repomerge' into t3chguy/repo-merge Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
commit
f0ee7f7905
3265 changed files with 484599 additions and 699 deletions
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2024 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { renderHook } from "@testing-library/react-hooks/dom";
|
||||
import { MatrixClient, NotificationCountType, Room } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { useRoomThreadNotifications } from "../../../../src/hooks/room/useRoomThreadNotifications";
|
||||
import { stubClient } from "../../../test-utils";
|
||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||
import { NotificationLevel } from "../../../../src/stores/notifications/NotificationLevel";
|
||||
import { populateThread } from "../../../test-utils/threads";
|
||||
|
||||
function render(room: Room) {
|
||||
return renderHook(() => useRoomThreadNotifications(room));
|
||||
}
|
||||
|
||||
describe("useRoomThreadNotifications", () => {
|
||||
let cli: MatrixClient;
|
||||
let room: Room;
|
||||
|
||||
beforeEach(() => {
|
||||
stubClient();
|
||||
cli = MatrixClientPeg.safeGet();
|
||||
cli.supportsThreads = () => true;
|
||||
room = new Room("!room:server", cli, cli.getSafeUserId());
|
||||
});
|
||||
|
||||
it("returns none if no thread in the room has notifications", async () => {
|
||||
const { result } = render(room);
|
||||
|
||||
expect(result.current).toBe(NotificationLevel.None);
|
||||
});
|
||||
|
||||
it("returns none if the thread hasn't a notification anymore", async () => {
|
||||
room.setThreadUnreadNotificationCount("flooble", NotificationCountType.Highlight, 0);
|
||||
const { result } = render(room);
|
||||
|
||||
expect(result.current).toBe(NotificationLevel.None);
|
||||
});
|
||||
|
||||
it("returns red if a thread in the room has a highlight notification", async () => {
|
||||
room.setThreadUnreadNotificationCount("flooble", NotificationCountType.Highlight, 1);
|
||||
const { result } = render(room);
|
||||
|
||||
expect(result.current).toBe(NotificationLevel.Highlight);
|
||||
});
|
||||
|
||||
it("returns grey if a thread in the room has a normal notification", async () => {
|
||||
room.setThreadUnreadNotificationCount("flooble", NotificationCountType.Total, 1);
|
||||
const { result } = render(room);
|
||||
|
||||
expect(result.current).toBe(NotificationLevel.Notification);
|
||||
});
|
||||
|
||||
it("returns activity if a thread in the room unread messages", async () => {
|
||||
await populateThread({
|
||||
room,
|
||||
client: cli,
|
||||
authorId: cli.getSafeUserId(),
|
||||
participantUserIds: ["@alice:server.org"],
|
||||
});
|
||||
|
||||
const { result } = render(room);
|
||||
|
||||
expect(result.current).toBe(NotificationLevel.Activity);
|
||||
});
|
||||
});
|
186
test/unit-tests/hooks/useDebouncedCallback-test.tsx
Normal file
186
test/unit-tests/hooks/useDebouncedCallback-test.tsx
Normal file
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { renderHook } from "@testing-library/react-hooks";
|
||||
|
||||
import { useDebouncedCallback } from "../../../src/hooks/spotlight/useDebouncedCallback";
|
||||
|
||||
describe("useDebouncedCallback", () => {
|
||||
beforeAll(() => jest.useFakeTimers());
|
||||
afterAll(() => jest.useRealTimers());
|
||||
|
||||
function render(enabled: boolean, callback: (...params: any[]) => void, params: any[]) {
|
||||
return renderHook(({ enabled, callback, params }) => useDebouncedCallback(enabled, callback, params), {
|
||||
initialProps: {
|
||||
enabled,
|
||||
callback,
|
||||
params,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
it("should be able to handle empty parameters", async () => {
|
||||
// When
|
||||
const params: any[] = [];
|
||||
const callback = jest.fn();
|
||||
render(true, callback, params);
|
||||
jest.advanceTimersByTime(1);
|
||||
|
||||
// Then
|
||||
expect(callback).toHaveBeenCalledTimes(0);
|
||||
|
||||
// When
|
||||
jest.advanceTimersByTime(500);
|
||||
|
||||
// Then
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should call the callback with the parameters", async () => {
|
||||
// When
|
||||
const params = ["USER NAME"];
|
||||
const callback = jest.fn();
|
||||
render(true, callback, params);
|
||||
jest.advanceTimersByTime(500);
|
||||
|
||||
// Then
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
expect(callback).toHaveBeenCalledWith(...params);
|
||||
});
|
||||
|
||||
it("should call the callback with the parameters when parameters change during the timeout", async () => {
|
||||
// When
|
||||
const params = ["USER NAME"];
|
||||
const callback = jest.fn();
|
||||
const { rerender } = render(true, callback, []);
|
||||
|
||||
jest.advanceTimersByTime(1);
|
||||
rerender({ enabled: true, callback, params });
|
||||
jest.advanceTimersByTime(500);
|
||||
|
||||
// Then
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
expect(callback).toHaveBeenCalledWith(...params);
|
||||
});
|
||||
|
||||
it("should handle multiple parameters", async () => {
|
||||
// When
|
||||
const params = [4, 8, 15, 16, 23, 42];
|
||||
const callback = jest.fn();
|
||||
const { rerender } = render(true, callback, []);
|
||||
|
||||
jest.advanceTimersByTime(1);
|
||||
rerender({ enabled: true, callback, params });
|
||||
jest.advanceTimersByTime(500);
|
||||
|
||||
// Then
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
expect(callback).toHaveBeenCalledWith(...params);
|
||||
});
|
||||
|
||||
it("should debounce quick changes", async () => {
|
||||
// When
|
||||
const queries = [
|
||||
"U",
|
||||
"US",
|
||||
"USE",
|
||||
"USER",
|
||||
"USER ",
|
||||
"USER N",
|
||||
"USER NM",
|
||||
"USER NMA",
|
||||
"USER NM",
|
||||
"USER N",
|
||||
"USER NA",
|
||||
"USER NAM",
|
||||
"USER NAME",
|
||||
];
|
||||
const callback = jest.fn();
|
||||
|
||||
const { rerender } = render(true, callback, []);
|
||||
jest.advanceTimersByTime(1);
|
||||
|
||||
for (const query of queries) {
|
||||
rerender({ enabled: true, callback, params: [query] });
|
||||
jest.advanceTimersByTime(50);
|
||||
}
|
||||
|
||||
jest.advanceTimersByTime(500);
|
||||
|
||||
// Then
|
||||
const query = queries[queries.length - 1];
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
expect(callback).toHaveBeenCalledWith(query);
|
||||
});
|
||||
|
||||
it("should not debounce slow changes", async () => {
|
||||
// When
|
||||
const queries = [
|
||||
"U",
|
||||
"US",
|
||||
"USE",
|
||||
"USER",
|
||||
"USER ",
|
||||
"USER N",
|
||||
"USER NM",
|
||||
"USER NMA",
|
||||
"USER NM",
|
||||
"USER N",
|
||||
"USER NA",
|
||||
"USER NAM",
|
||||
"USER NAME",
|
||||
];
|
||||
const callback = jest.fn();
|
||||
|
||||
const { rerender } = render(true, callback, []);
|
||||
jest.advanceTimersByTime(1);
|
||||
for (const query of queries) {
|
||||
rerender({ enabled: true, callback, params: [query] });
|
||||
jest.advanceTimersByTime(200);
|
||||
}
|
||||
|
||||
jest.advanceTimersByTime(500);
|
||||
|
||||
// Then
|
||||
const query = queries[queries.length - 1];
|
||||
expect(callback).toHaveBeenCalledTimes(queries.length);
|
||||
expect(callback).toHaveBeenCalledWith(query);
|
||||
});
|
||||
|
||||
it("should not call the callback if it’s disabled", async () => {
|
||||
// When
|
||||
const queries = [
|
||||
"U",
|
||||
"US",
|
||||
"USE",
|
||||
"USER",
|
||||
"USER ",
|
||||
"USER N",
|
||||
"USER NM",
|
||||
"USER NMA",
|
||||
"USER NM",
|
||||
"USER N",
|
||||
"USER NA",
|
||||
"USER NAM",
|
||||
"USER NAME",
|
||||
];
|
||||
const callback = jest.fn();
|
||||
|
||||
const { rerender } = render(false, callback, []);
|
||||
jest.advanceTimersByTime(1);
|
||||
for (const query of queries) {
|
||||
rerender({ enabled: false, callback, params: [query] });
|
||||
jest.advanceTimersByTime(200);
|
||||
}
|
||||
|
||||
jest.advanceTimersByTime(500);
|
||||
|
||||
// Then
|
||||
expect(callback).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
});
|
128
test/unit-tests/hooks/useLatestResult-test.tsx
Normal file
128
test/unit-tests/hooks/useLatestResult-test.tsx
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { renderHook, RenderHookResult } from "@testing-library/react-hooks/dom";
|
||||
|
||||
import { useLatestResult } from "../../../src/hooks/useLatestResult";
|
||||
|
||||
// All tests use fake timers throughout, comments will show the elapsed time in ms
|
||||
jest.useFakeTimers();
|
||||
|
||||
const mockSetter = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
mockSetter.mockClear();
|
||||
});
|
||||
|
||||
function simulateRequest(
|
||||
hookResult: RenderHookResult<typeof useLatestResult, ReturnType<typeof useLatestResult>>["result"],
|
||||
{ id, delayInMs, result }: { id: string; delayInMs: number; result: string },
|
||||
) {
|
||||
const [setQuery, setResult] = hookResult.current;
|
||||
setQuery(id);
|
||||
setTimeout(() => setResult(id, result), delayInMs);
|
||||
}
|
||||
|
||||
describe("renderhook tests", () => {
|
||||
it("should return a result", () => {
|
||||
const { result: hookResult } = renderHook(() => useLatestResult(mockSetter));
|
||||
|
||||
const query = { id: "query1", delayInMs: 100, result: "result1" };
|
||||
simulateRequest(hookResult, query);
|
||||
|
||||
// check we have made no calls to the setter
|
||||
expect(mockSetter).not.toHaveBeenCalled();
|
||||
|
||||
// advance timer until the timeout elapses, check we have called the setter
|
||||
jest.advanceTimersToNextTimer();
|
||||
expect(mockSetter).toHaveBeenCalledTimes(1);
|
||||
expect(mockSetter).toHaveBeenLastCalledWith(query.result);
|
||||
});
|
||||
|
||||
it("should not let a slower response to an earlier query overwrite the result of a later query", () => {
|
||||
const { result: hookResult } = renderHook(() => useLatestResult(mockSetter));
|
||||
|
||||
const slowQuery = { id: "slowQuery", delayInMs: 500, result: "slowResult" };
|
||||
const fastQuery = { id: "fastQuery", delayInMs: 100, result: "fastResult" };
|
||||
|
||||
simulateRequest(hookResult, slowQuery);
|
||||
simulateRequest(hookResult, fastQuery);
|
||||
|
||||
// advance to fastQuery response, check the setter call
|
||||
jest.advanceTimersToNextTimer();
|
||||
expect(mockSetter).toHaveBeenCalledTimes(1);
|
||||
expect(mockSetter).toHaveBeenLastCalledWith(fastQuery.result);
|
||||
|
||||
// advance time to slowQuery response, check the setter has _not_ been
|
||||
// called again and that the result is still from the fast query
|
||||
jest.advanceTimersToNextTimer();
|
||||
expect(mockSetter).toHaveBeenCalledTimes(1);
|
||||
expect(mockSetter).toHaveBeenLastCalledWith(fastQuery.result);
|
||||
});
|
||||
|
||||
it("should return expected results when all response times similar", () => {
|
||||
const { result: hookResult } = renderHook(() => useLatestResult(mockSetter));
|
||||
|
||||
const commonDelayInMs = 180;
|
||||
const query1 = { id: "q1", delayInMs: commonDelayInMs, result: "r1" };
|
||||
const query2 = { id: "q2", delayInMs: commonDelayInMs, result: "r2" };
|
||||
const query3 = { id: "q3", delayInMs: commonDelayInMs, result: "r3" };
|
||||
|
||||
// ELAPSED: 0ms, no queries sent
|
||||
simulateRequest(hookResult, query1);
|
||||
jest.advanceTimersByTime(100);
|
||||
|
||||
// ELAPSED: 100ms, query1 sent, no responses
|
||||
expect(mockSetter).not.toHaveBeenCalled();
|
||||
simulateRequest(hookResult, query2);
|
||||
jest.advanceTimersByTime(70);
|
||||
|
||||
// ELAPSED: 170ms, query1 and query2 sent, no responses
|
||||
expect(mockSetter).not.toHaveBeenCalled();
|
||||
simulateRequest(hookResult, query3);
|
||||
jest.advanceTimersByTime(70);
|
||||
|
||||
// ELAPSED: 240ms, all queries sent, responses for query1 and query2
|
||||
expect(mockSetter).not.toHaveBeenCalled();
|
||||
|
||||
// ELAPSED: 360ms, all queries sent, all queries have responses
|
||||
jest.advanceTimersByTime(120);
|
||||
expect(mockSetter).toHaveBeenLastCalledWith(query3.result);
|
||||
});
|
||||
|
||||
it("should prevent out of order results", () => {
|
||||
const { result: hookResult } = renderHook(() => useLatestResult(mockSetter));
|
||||
|
||||
const query1 = { id: "q1", delayInMs: 0, result: "r1" };
|
||||
const query2 = { id: "q2", delayInMs: 50, result: "r2" };
|
||||
const query3 = { id: "q3", delayInMs: 1, result: "r3" };
|
||||
|
||||
// ELAPSED: 0ms, no queries sent
|
||||
simulateRequest(hookResult, query1);
|
||||
jest.advanceTimersByTime(5);
|
||||
|
||||
// ELAPSED: 5ms, query1 sent, response from query1
|
||||
expect(mockSetter).toHaveBeenCalledTimes(1);
|
||||
expect(mockSetter).toHaveBeenLastCalledWith(query1.result);
|
||||
simulateRequest(hookResult, query2);
|
||||
jest.advanceTimersByTime(5);
|
||||
|
||||
// ELAPSED: 10ms, query1 and query2 sent, response from query1
|
||||
simulateRequest(hookResult, query3);
|
||||
jest.advanceTimersByTime(5);
|
||||
|
||||
// ELAPSED: 15ms, all queries sent, responses from query1 and query3
|
||||
expect(mockSetter).toHaveBeenCalledTimes(2);
|
||||
expect(mockSetter).toHaveBeenLastCalledWith(query3.result);
|
||||
|
||||
// ELAPSED: 65ms, all queries sent, all queries have responses
|
||||
// so check that the result is still from query3, not query2
|
||||
jest.advanceTimersByTime(50);
|
||||
expect(mockSetter).toHaveBeenLastCalledWith(query3.result);
|
||||
});
|
||||
});
|
146
test/unit-tests/hooks/useNotificationSettings-test.tsx
Normal file
146
test/unit-tests/hooks/useNotificationSettings-test.tsx
Normal file
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { renderHook } from "@testing-library/react-hooks/dom";
|
||||
import { waitFor } from "jest-matrix-react";
|
||||
import { IPushRules, MatrixClient, PushRuleKind, RuleId } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { useNotificationSettings } from "../../../src/hooks/useNotificationSettings";
|
||||
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
|
||||
import {
|
||||
DefaultNotificationSettings,
|
||||
NotificationSettings,
|
||||
} from "../../../src/models/notificationsettings/NotificationSettings";
|
||||
import { StandardActions } from "../../../src/notifications/StandardActions";
|
||||
import { RoomNotifState } from "../../../src/RoomNotifs";
|
||||
import { stubClient } from "../../test-utils";
|
||||
|
||||
const expectedModel: NotificationSettings = {
|
||||
globalMute: false,
|
||||
defaultLevels: {
|
||||
dm: RoomNotifState.AllMessages,
|
||||
room: RoomNotifState.MentionsOnly,
|
||||
},
|
||||
sound: {
|
||||
calls: "ring",
|
||||
mentions: "default",
|
||||
people: undefined,
|
||||
},
|
||||
activity: {
|
||||
bot_notices: false,
|
||||
invite: true,
|
||||
status_event: false,
|
||||
},
|
||||
mentions: {
|
||||
user: true,
|
||||
room: true,
|
||||
keywords: true,
|
||||
},
|
||||
keywords: ["justjann3", "justj4nn3", "justj4nne", "Janne", "J4nne", "Jann3", "jann3", "j4nne", "janne"],
|
||||
};
|
||||
|
||||
describe("useNotificationSettings", () => {
|
||||
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);
|
||||
});
|
||||
|
||||
it("correctly parses model", async () => {
|
||||
const { result } = renderHook(() => useNotificationSettings(cli));
|
||||
expect(result.current.model).toEqual(null);
|
||||
await waitFor(() => expect(result.current.model).toEqual(expectedModel));
|
||||
expect(result.current.hasPendingChanges).toBeFalsy();
|
||||
});
|
||||
|
||||
it("correctly generates change calls", async () => {
|
||||
const addPushRule = jest.fn(cli.addPushRule);
|
||||
cli.addPushRule = addPushRule;
|
||||
const deletePushRule = jest.fn(cli.deletePushRule);
|
||||
cli.deletePushRule = deletePushRule;
|
||||
const setPushRuleEnabled = jest.fn(cli.setPushRuleEnabled);
|
||||
cli.setPushRuleEnabled = setPushRuleEnabled;
|
||||
const setPushRuleActions = jest.fn(cli.setPushRuleActions);
|
||||
cli.setPushRuleActions = setPushRuleActions;
|
||||
|
||||
const { result } = renderHook(() => useNotificationSettings(cli));
|
||||
expect(result.current.model).toEqual(null);
|
||||
await waitFor(() => expect(result.current.model).toEqual(expectedModel));
|
||||
expect(result.current.hasPendingChanges).toBeFalsy();
|
||||
await result.current.reconcile(DefaultNotificationSettings);
|
||||
await waitFor(() => expect(result.current.hasPendingChanges).toBeFalsy());
|
||||
expect(addPushRule).toHaveBeenCalledTimes(0);
|
||||
expect(deletePushRule).toHaveBeenCalledTimes(9);
|
||||
expect(deletePushRule).toHaveBeenCalledWith("global", PushRuleKind.ContentSpecific, "justjann3");
|
||||
expect(deletePushRule).toHaveBeenCalledWith("global", PushRuleKind.ContentSpecific, "justj4nn3");
|
||||
expect(deletePushRule).toHaveBeenCalledWith("global", PushRuleKind.ContentSpecific, "justj4nne");
|
||||
expect(deletePushRule).toHaveBeenCalledWith("global", PushRuleKind.ContentSpecific, "Janne");
|
||||
expect(deletePushRule).toHaveBeenCalledWith("global", PushRuleKind.ContentSpecific, "J4nne");
|
||||
expect(deletePushRule).toHaveBeenCalledWith("global", PushRuleKind.ContentSpecific, "Jann3");
|
||||
expect(deletePushRule).toHaveBeenCalledWith("global", PushRuleKind.ContentSpecific, "jann3");
|
||||
expect(deletePushRule).toHaveBeenCalledWith("global", PushRuleKind.ContentSpecific, "j4nne");
|
||||
expect(deletePushRule).toHaveBeenCalledWith("global", PushRuleKind.ContentSpecific, "janne");
|
||||
expect(setPushRuleEnabled).toHaveBeenCalledTimes(6);
|
||||
expect(setPushRuleEnabled).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Underride,
|
||||
RuleId.EncryptedMessage,
|
||||
true,
|
||||
);
|
||||
expect(setPushRuleEnabled).toHaveBeenCalledWith("global", PushRuleKind.Underride, RuleId.Message, true);
|
||||
expect(setPushRuleEnabled).toHaveBeenCalledWith("global", PushRuleKind.Underride, RuleId.EncryptedDM, true);
|
||||
expect(setPushRuleEnabled).toHaveBeenCalledWith("global", PushRuleKind.Underride, RuleId.DM, true);
|
||||
expect(setPushRuleEnabled).toHaveBeenCalledWith("global", PushRuleKind.Override, RuleId.SuppressNotices, false);
|
||||
expect(setPushRuleEnabled).toHaveBeenCalledWith("global", PushRuleKind.Override, RuleId.InviteToSelf, true);
|
||||
expect(setPushRuleActions).toHaveBeenCalledTimes(6);
|
||||
expect(setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Underride,
|
||||
RuleId.EncryptedMessage,
|
||||
StandardActions.ACTION_NOTIFY,
|
||||
);
|
||||
expect(setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Underride,
|
||||
RuleId.Message,
|
||||
StandardActions.ACTION_NOTIFY,
|
||||
);
|
||||
expect(setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Underride,
|
||||
RuleId.EncryptedDM,
|
||||
StandardActions.ACTION_NOTIFY_DEFAULT_SOUND,
|
||||
);
|
||||
expect(setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Underride,
|
||||
RuleId.DM,
|
||||
StandardActions.ACTION_NOTIFY_DEFAULT_SOUND,
|
||||
);
|
||||
expect(setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Override,
|
||||
RuleId.SuppressNotices,
|
||||
StandardActions.ACTION_DONT_NOTIFY,
|
||||
);
|
||||
expect(setPushRuleActions).toHaveBeenCalledWith(
|
||||
"global",
|
||||
PushRuleKind.Override,
|
||||
RuleId.InviteToSelf,
|
||||
StandardActions.ACTION_NOTIFY_DEFAULT_SOUND,
|
||||
);
|
||||
});
|
||||
});
|
110
test/unit-tests/hooks/useProfileInfo-test.tsx
Normal file
110
test/unit-tests/hooks/useProfileInfo-test.tsx
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { waitFor } from "jest-matrix-react";
|
||||
import { renderHook, act } from "@testing-library/react-hooks/dom";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { useProfileInfo } from "../../../src/hooks/useProfileInfo";
|
||||
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
|
||||
import { stubClient } from "../../test-utils/test-utils";
|
||||
|
||||
function render() {
|
||||
return renderHook(() => useProfileInfo());
|
||||
}
|
||||
|
||||
describe("useProfileInfo", () => {
|
||||
let cli: MatrixClient;
|
||||
|
||||
beforeEach(() => {
|
||||
stubClient();
|
||||
cli = MatrixClientPeg.safeGet();
|
||||
cli.getProfileInfo = (query) => {
|
||||
return Promise.resolve({
|
||||
avatar_url: undefined,
|
||||
displayname: query,
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
it("should display user profile when searching", async () => {
|
||||
const query = "@user:home.server";
|
||||
|
||||
const { result } = render();
|
||||
|
||||
act(() => {
|
||||
result.current.search({ query });
|
||||
});
|
||||
|
||||
await waitFor(() => expect(result.current.ready).toBe(true));
|
||||
|
||||
expect(result.current.profile?.display_name).toBe(query);
|
||||
});
|
||||
|
||||
it("should work with empty queries", async () => {
|
||||
const query = "";
|
||||
|
||||
const { result } = render();
|
||||
|
||||
act(() => {
|
||||
result.current.search({ query });
|
||||
});
|
||||
|
||||
await waitFor(() => expect(result.current.ready).toBe(true));
|
||||
|
||||
expect(result.current.profile).toBeNull();
|
||||
});
|
||||
|
||||
it("should treat invalid mxids as empty queries", async () => {
|
||||
const queries = ["@user", "user@home.server"];
|
||||
|
||||
for (const query of queries) {
|
||||
const { result } = render();
|
||||
|
||||
act(() => {
|
||||
result.current.search({ query });
|
||||
});
|
||||
|
||||
await waitFor(() => expect(result.current.ready).toBe(true));
|
||||
|
||||
expect(result.current.profile).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it("should recover from a server exception", async () => {
|
||||
cli.getProfileInfo = () => {
|
||||
throw new Error("Oops");
|
||||
};
|
||||
const query = "@user:home.server";
|
||||
|
||||
const { result } = render();
|
||||
|
||||
act(() => {
|
||||
result.current.search({ query });
|
||||
});
|
||||
|
||||
await waitFor(() => expect(result.current.ready).toBe(true));
|
||||
|
||||
expect(result.current.profile).toBeNull();
|
||||
});
|
||||
|
||||
it("should be able to handle an empty result", async () => {
|
||||
cli.getProfileInfo = () => null as unknown as Promise<{}>;
|
||||
const query = "@user:home.server";
|
||||
|
||||
const { result } = render();
|
||||
|
||||
act(() => {
|
||||
result.current.search({ query });
|
||||
});
|
||||
|
||||
await waitFor(() => expect(result.current.ready).toBe(true));
|
||||
|
||||
expect(result.current.profile?.display_name).toBeUndefined();
|
||||
});
|
||||
});
|
109
test/unit-tests/hooks/usePublicRoomDirectory-test.tsx
Normal file
109
test/unit-tests/hooks/usePublicRoomDirectory-test.tsx
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { waitFor } from "jest-matrix-react";
|
||||
import { renderHook, act } from "@testing-library/react-hooks/dom";
|
||||
import { IRoomDirectoryOptions, MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { usePublicRoomDirectory } from "../../../src/hooks/usePublicRoomDirectory";
|
||||
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
|
||||
import { stubClient } from "../../test-utils/test-utils";
|
||||
|
||||
function render() {
|
||||
return renderHook(() => usePublicRoomDirectory());
|
||||
}
|
||||
|
||||
describe("usePublicRoomDirectory", () => {
|
||||
let cli: MatrixClient;
|
||||
|
||||
beforeEach(() => {
|
||||
stubClient();
|
||||
cli = MatrixClientPeg.safeGet();
|
||||
|
||||
cli.getDomain = () => "matrix.org";
|
||||
cli.getThirdpartyProtocols = () => Promise.resolve({});
|
||||
cli.publicRooms = ({ filter }: IRoomDirectoryOptions) => {
|
||||
const chunk = filter?.generic_search_term
|
||||
? [
|
||||
{
|
||||
room_id: "hello world!",
|
||||
name: filter.generic_search_term,
|
||||
world_readable: true,
|
||||
guest_can_join: true,
|
||||
num_joined_members: 1,
|
||||
},
|
||||
]
|
||||
: [];
|
||||
return Promise.resolve({
|
||||
chunk,
|
||||
total_room_count_estimate: 1,
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
it("should display public rooms when searching", async () => {
|
||||
const query = "ROOM NAME";
|
||||
const { result } = render();
|
||||
|
||||
expect(result.current.ready).toBe(false);
|
||||
expect(result.current.loading).toBe(false);
|
||||
|
||||
act(() => {
|
||||
result.current.search({
|
||||
limit: 1,
|
||||
query,
|
||||
});
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.ready).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.publicRooms[0].name).toBe(query);
|
||||
});
|
||||
|
||||
it("should work with empty queries", async () => {
|
||||
const query = "ROOM NAME";
|
||||
const { result } = render();
|
||||
|
||||
act(() => {
|
||||
result.current.search({
|
||||
limit: 1,
|
||||
query,
|
||||
});
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.ready).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.publicRooms[0].name).toEqual(query);
|
||||
});
|
||||
|
||||
it("should recover from a server exception", async () => {
|
||||
cli.publicRooms = () => {
|
||||
throw new Error("Oops");
|
||||
};
|
||||
const query = "ROOM NAME";
|
||||
|
||||
const { result } = render();
|
||||
|
||||
act(() => {
|
||||
result.current.search({
|
||||
limit: 1,
|
||||
query,
|
||||
});
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.ready).toBe(true);
|
||||
});
|
||||
|
||||
expect(result.current.publicRooms).toEqual([]);
|
||||
});
|
||||
});
|
115
test/unit-tests/hooks/useRoomMembers-test.tsx
Normal file
115
test/unit-tests/hooks/useRoomMembers-test.tsx
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { waitFor } from "jest-matrix-react";
|
||||
import { renderHook, act } from "@testing-library/react-hooks/dom";
|
||||
import { MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
|
||||
import { KnownMembership } from "matrix-js-sdk/src/types";
|
||||
|
||||
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
|
||||
import { stubClient } from "../../test-utils";
|
||||
import { useMyRoomMembership, useRoomMemberCount, useRoomMembers } from "../../../src/hooks/useRoomMembers";
|
||||
|
||||
describe("useRoomMembers", () => {
|
||||
function render(room: Room) {
|
||||
return renderHook(() => useRoomMembers(room));
|
||||
}
|
||||
|
||||
let cli: MatrixClient;
|
||||
let room: Room;
|
||||
|
||||
beforeEach(() => {
|
||||
stubClient();
|
||||
cli = MatrixClientPeg.safeGet();
|
||||
room = new Room("!room:server", cli, cli.getSafeUserId());
|
||||
});
|
||||
|
||||
it("should update on RoomState.Members events", async () => {
|
||||
const { result } = render(room);
|
||||
|
||||
expect(result.current).toHaveLength(0);
|
||||
|
||||
act(() => {
|
||||
room.currentState.markOutOfBandMembersStarted();
|
||||
room.currentState.setOutOfBandMembers([
|
||||
new MatrixEvent({
|
||||
type: "m.room.member",
|
||||
state_key: "!user:server",
|
||||
room_id: room.roomId,
|
||||
content: {
|
||||
membership: KnownMembership.Join,
|
||||
},
|
||||
}),
|
||||
]);
|
||||
});
|
||||
await waitFor(() => expect(result.current).toHaveLength(1));
|
||||
});
|
||||
});
|
||||
|
||||
describe("useRoomMemberCount", () => {
|
||||
function render(room: Room) {
|
||||
return renderHook(() => useRoomMemberCount(room));
|
||||
}
|
||||
|
||||
let cli: MatrixClient;
|
||||
let room: Room;
|
||||
|
||||
beforeEach(() => {
|
||||
stubClient();
|
||||
cli = MatrixClientPeg.safeGet();
|
||||
room = new Room("!room:server", cli, cli.getSafeUserId());
|
||||
});
|
||||
|
||||
it("should update on RoomState.Members events", async () => {
|
||||
const { result } = render(room);
|
||||
|
||||
expect(result.current).toBe(0);
|
||||
|
||||
act(() => {
|
||||
room.currentState.markOutOfBandMembersStarted();
|
||||
room.currentState.setOutOfBandMembers([
|
||||
new MatrixEvent({
|
||||
type: "m.room.member",
|
||||
state_key: "!user:server",
|
||||
room_id: room.roomId,
|
||||
content: {
|
||||
membership: KnownMembership.Join,
|
||||
},
|
||||
}),
|
||||
]);
|
||||
});
|
||||
await waitFor(() => expect(result.current).toBe(1));
|
||||
});
|
||||
});
|
||||
|
||||
describe("useMyRoomMembership", () => {
|
||||
function render(room: Room) {
|
||||
return renderHook(() => useMyRoomMembership(room));
|
||||
}
|
||||
|
||||
let cli: MatrixClient;
|
||||
let room: Room;
|
||||
|
||||
beforeEach(() => {
|
||||
stubClient();
|
||||
cli = MatrixClientPeg.safeGet();
|
||||
room = new Room("!room:server", cli, cli.getSafeUserId());
|
||||
});
|
||||
|
||||
it("should update on RoomState.Members events", async () => {
|
||||
room.updateMyMembership(KnownMembership.Join);
|
||||
const { result } = render(room);
|
||||
|
||||
expect(result.current).toBe(KnownMembership.Join);
|
||||
|
||||
act(() => {
|
||||
room.updateMyMembership(KnownMembership.Leave);
|
||||
});
|
||||
await waitFor(() => expect(result.current).toBe(KnownMembership.Leave));
|
||||
});
|
||||
});
|
85
test/unit-tests/hooks/useSlidingSyncRoomSearch-test.tsx
Normal file
85
test/unit-tests/hooks/useSlidingSyncRoomSearch-test.tsx
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { waitFor } from "jest-matrix-react";
|
||||
import { renderHook, act } from "@testing-library/react-hooks/dom";
|
||||
import { mocked } from "jest-mock";
|
||||
import { SlidingSync } from "matrix-js-sdk/src/sliding-sync";
|
||||
import { Room } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { useSlidingSyncRoomSearch } from "../../../src/hooks/useSlidingSyncRoomSearch";
|
||||
import { MockEventEmitter, stubClient } from "../../test-utils";
|
||||
import { SlidingSyncManager } from "../../../src/SlidingSyncManager";
|
||||
|
||||
describe("useSlidingSyncRoomSearch", () => {
|
||||
afterAll(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("should display rooms when searching", async () => {
|
||||
const client = stubClient();
|
||||
const roomA = new Room("!a:localhost", client, client.getUserId()!);
|
||||
const roomB = new Room("!b:localhost", client, client.getUserId()!);
|
||||
const slidingSync = mocked(
|
||||
new MockEventEmitter({
|
||||
getListData: jest.fn(),
|
||||
}) as unknown as SlidingSync,
|
||||
);
|
||||
jest.spyOn(SlidingSyncManager.instance, "ensureListRegistered").mockResolvedValue({
|
||||
ranges: [[0, 9]],
|
||||
});
|
||||
SlidingSyncManager.instance.slidingSync = slidingSync;
|
||||
mocked(slidingSync.getListData).mockReturnValue({
|
||||
joinedCount: 2,
|
||||
roomIndexToRoomId: {
|
||||
0: roomA.roomId,
|
||||
1: roomB.roomId,
|
||||
},
|
||||
});
|
||||
mocked(client.getRoom).mockImplementation((roomId) => {
|
||||
switch (roomId) {
|
||||
case roomA.roomId:
|
||||
return roomA;
|
||||
case roomB.roomId:
|
||||
return roomB;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// first check that everything is empty
|
||||
const { result } = renderHook(() => useSlidingSyncRoomSearch());
|
||||
const query = {
|
||||
limit: 10,
|
||||
query: "foo",
|
||||
};
|
||||
expect(result.current.loading).toBe(false);
|
||||
expect(result.current.rooms).toEqual([]);
|
||||
|
||||
// run the query
|
||||
act(() => {
|
||||
result.current.search(query);
|
||||
});
|
||||
|
||||
// wait for loading to finish
|
||||
await waitFor(() => {
|
||||
expect(result.current.loading).toBe(false);
|
||||
});
|
||||
|
||||
// now we expect there to be rooms
|
||||
expect(result.current.rooms).toEqual([roomA, roomB]);
|
||||
|
||||
// run the query again
|
||||
act(() => {
|
||||
result.current.search(query);
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(result.current.loading).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
102
test/unit-tests/hooks/useUnreadNotifications-test.ts
Normal file
102
test/unit-tests/hooks/useUnreadNotifications-test.ts
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { renderHook } from "@testing-library/react-hooks";
|
||||
import { EventStatus, NotificationCountType, PendingEventOrdering, Room } from "matrix-js-sdk/src/matrix";
|
||||
import { KnownMembership } from "matrix-js-sdk/src/types";
|
||||
|
||||
import type { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import { useUnreadNotifications } from "../../../src/hooks/useUnreadNotifications";
|
||||
import { NotificationLevel } from "../../../src/stores/notifications/NotificationLevel";
|
||||
import { mkEvent, muteRoom, stubClient } from "../../test-utils";
|
||||
|
||||
describe("useUnreadNotifications", () => {
|
||||
let client: MatrixClient;
|
||||
let room: Room;
|
||||
|
||||
beforeEach(() => {
|
||||
client = stubClient();
|
||||
room = new Room("!room:example.org", client, "@user:example.org", {
|
||||
pendingEventOrdering: PendingEventOrdering.Detached,
|
||||
});
|
||||
});
|
||||
|
||||
function setUnreads(greys: number, reds: number): void {
|
||||
room.setUnreadNotificationCount(NotificationCountType.Highlight, reds);
|
||||
room.setUnreadNotificationCount(NotificationCountType.Total, greys);
|
||||
}
|
||||
|
||||
it("shows nothing by default", async () => {
|
||||
const { result } = renderHook(() => useUnreadNotifications(room));
|
||||
const { level, symbol, count } = result.current;
|
||||
|
||||
expect(symbol).toBe(null);
|
||||
expect(level).toBe(NotificationLevel.None);
|
||||
expect(count).toBe(0);
|
||||
});
|
||||
|
||||
it("indicates if there are unsent messages", async () => {
|
||||
const event = mkEvent({
|
||||
event: true,
|
||||
type: "m.message",
|
||||
user: "@user:example.org",
|
||||
content: {},
|
||||
});
|
||||
event.status = EventStatus.NOT_SENT;
|
||||
room.addPendingEvent(event, "txn");
|
||||
|
||||
const { result } = renderHook(() => useUnreadNotifications(room));
|
||||
const { level, symbol, count } = result.current;
|
||||
|
||||
expect(symbol).toBe("!");
|
||||
expect(level).toBe(NotificationLevel.Unsent);
|
||||
expect(count).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("indicates the user has been invited to a channel", async () => {
|
||||
room.updateMyMembership(KnownMembership.Invite);
|
||||
|
||||
const { result } = renderHook(() => useUnreadNotifications(room));
|
||||
const { level, symbol, count } = result.current;
|
||||
|
||||
expect(symbol).toBe("!");
|
||||
expect(level).toBe(NotificationLevel.Highlight);
|
||||
expect(count).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("shows nothing for muted channels", async () => {
|
||||
setUnreads(999, 999);
|
||||
muteRoom(room);
|
||||
|
||||
const { result } = renderHook(() => useUnreadNotifications(room));
|
||||
const { level, count } = result.current;
|
||||
|
||||
expect(level).toBe(NotificationLevel.None);
|
||||
expect(count).toBe(0);
|
||||
});
|
||||
|
||||
it("uses the correct number of unreads", async () => {
|
||||
setUnreads(999, 0);
|
||||
|
||||
const { result } = renderHook(() => useUnreadNotifications(room));
|
||||
const { level, count } = result.current;
|
||||
|
||||
expect(level).toBe(NotificationLevel.Notification);
|
||||
expect(count).toBe(999);
|
||||
});
|
||||
|
||||
it("uses the correct number of highlights", async () => {
|
||||
setUnreads(0, 888);
|
||||
|
||||
const { result } = renderHook(() => useUnreadNotifications(room));
|
||||
const { level, count } = result.current;
|
||||
|
||||
expect(level).toBe(NotificationLevel.Highlight);
|
||||
expect(count).toBe(888);
|
||||
});
|
||||
});
|
84
test/unit-tests/hooks/useUserDirectory-test.tsx
Normal file
84
test/unit-tests/hooks/useUserDirectory-test.tsx
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { waitFor } from "jest-matrix-react";
|
||||
import { renderHook, act } from "@testing-library/react-hooks/dom";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { useUserDirectory } from "../../../src/hooks/useUserDirectory";
|
||||
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
|
||||
import { stubClient } from "../../test-utils";
|
||||
|
||||
function render() {
|
||||
return renderHook(() => useUserDirectory());
|
||||
}
|
||||
|
||||
describe("useUserDirectory", () => {
|
||||
let cli: MatrixClient;
|
||||
|
||||
beforeEach(() => {
|
||||
stubClient();
|
||||
cli = MatrixClientPeg.safeGet();
|
||||
|
||||
cli.getDomain = () => "matrix.org";
|
||||
cli.getThirdpartyProtocols = () => Promise.resolve({});
|
||||
cli.searchUserDirectory = ({ term: query }) =>
|
||||
Promise.resolve({
|
||||
results: [
|
||||
{
|
||||
user_id: "@bob:matrix.org",
|
||||
display_name: query,
|
||||
},
|
||||
],
|
||||
limited: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("search for users in the identity server", async () => {
|
||||
const query = "Bob";
|
||||
const { result } = render();
|
||||
|
||||
act(() => {
|
||||
result.current.search({ limit: 1, query });
|
||||
});
|
||||
await waitFor(() => expect(result.current.ready).toBe(true));
|
||||
|
||||
expect(result.current.loading).toBe(false);
|
||||
expect(result.current.users[0].name).toBe(query);
|
||||
});
|
||||
|
||||
it("should work with empty queries", async () => {
|
||||
const query = "";
|
||||
const { result } = render();
|
||||
|
||||
act(() => {
|
||||
result.current.search({ limit: 1, query });
|
||||
});
|
||||
await waitFor(() => expect(result.current.ready).toBe(true));
|
||||
|
||||
expect(result.current.loading).toBe(false);
|
||||
expect(result.current.users).toEqual([]);
|
||||
});
|
||||
|
||||
it("should recover from a server exception", async () => {
|
||||
cli.searchUserDirectory = () => {
|
||||
throw new Error("Oops");
|
||||
};
|
||||
const query = "Bob";
|
||||
|
||||
const { result } = render();
|
||||
|
||||
act(() => {
|
||||
result.current.search({ limit: 1, query });
|
||||
});
|
||||
await waitFor(() => expect(result.current.ready).toBe(true));
|
||||
|
||||
expect(result.current.loading).toBe(false);
|
||||
expect(result.current.users).toEqual([]);
|
||||
});
|
||||
});
|
83
test/unit-tests/hooks/useUserOnboardingTasks-test.tsx
Normal file
83
test/unit-tests/hooks/useUserOnboardingTasks-test.tsx
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { renderHook } from "@testing-library/react-hooks";
|
||||
import { waitFor } from "jest-matrix-react";
|
||||
|
||||
import { useUserOnboardingTasks } from "../../../src/hooks/useUserOnboardingTasks";
|
||||
import { useUserOnboardingContext } from "../../../src/hooks/useUserOnboardingContext";
|
||||
import { stubClient } from "../../test-utils";
|
||||
import MatrixClientContext from "../../../src/contexts/MatrixClientContext";
|
||||
import DMRoomMap from "../../../src/utils/DMRoomMap";
|
||||
import PlatformPeg from "../../../src/PlatformPeg";
|
||||
|
||||
describe("useUserOnboardingTasks", () => {
|
||||
it.each([
|
||||
{
|
||||
context: {
|
||||
hasAvatar: false,
|
||||
hasDevices: false,
|
||||
hasDmRooms: false,
|
||||
showNotificationsPrompt: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
context: {
|
||||
hasAvatar: true,
|
||||
hasDevices: false,
|
||||
hasDmRooms: false,
|
||||
showNotificationsPrompt: true,
|
||||
},
|
||||
},
|
||||
])("sequence should stay static", async ({ context }) => {
|
||||
const { result } = renderHook(() => useUserOnboardingTasks(context));
|
||||
|
||||
expect(result.current).toHaveLength(5);
|
||||
expect(result.current[0].id).toBe("create-account");
|
||||
expect(result.current[1].id).toBe("find-friends");
|
||||
expect(result.current[2].id).toBe("download-apps");
|
||||
expect(result.current[3].id).toBe("setup-profile");
|
||||
expect(result.current[4].id).toBe("permission-notifications");
|
||||
});
|
||||
|
||||
it("should mark desktop notifications task completed on click", async () => {
|
||||
jest.spyOn(PlatformPeg, "get").mockReturnValue({
|
||||
supportsNotifications: jest.fn().mockReturnValue(true),
|
||||
maySendNotifications: jest.fn().mockReturnValue(false),
|
||||
} as any);
|
||||
|
||||
const cli = stubClient();
|
||||
cli.pushRules = {
|
||||
global: {
|
||||
override: [
|
||||
{
|
||||
rule_id: ".m.rule.master",
|
||||
enabled: false,
|
||||
actions: [],
|
||||
default: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
DMRoomMap.makeShared(cli);
|
||||
const context = renderHook(() => useUserOnboardingContext(), {
|
||||
wrapper: (props) => {
|
||||
return <MatrixClientContext.Provider value={cli}>{props.children}</MatrixClientContext.Provider>;
|
||||
},
|
||||
});
|
||||
const { result, rerender } = renderHook(() => useUserOnboardingTasks(context.result.current));
|
||||
expect(result.current[4].id).toBe("permission-notifications");
|
||||
expect(result.current[4].completed).toBe(false);
|
||||
result.current[4].action!.onClick!({ type: "click" } as any);
|
||||
await waitFor(() => {
|
||||
rerender();
|
||||
expect(result.current[4].completed).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
36
test/unit-tests/hooks/useWindowWidth-test.ts
Normal file
36
test/unit-tests/hooks/useWindowWidth-test.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2024 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { renderHook } from "@testing-library/react-hooks";
|
||||
import { act } from "jest-matrix-react";
|
||||
|
||||
import UIStore, { UI_EVENTS } from "../../../src/stores/UIStore";
|
||||
import { useWindowWidth } from "../../../src/hooks/useWindowWidth";
|
||||
|
||||
describe("useWindowWidth", () => {
|
||||
beforeEach(() => {
|
||||
UIStore.instance.windowWidth = 768;
|
||||
});
|
||||
|
||||
it("should return the current width of window, according to UIStore", () => {
|
||||
const { result } = renderHook(() => useWindowWidth());
|
||||
|
||||
expect(result.current).toBe(768);
|
||||
});
|
||||
|
||||
it("should update the value when UIStore's value changes", () => {
|
||||
const { result } = renderHook(() => useWindowWidth());
|
||||
|
||||
act(() => {
|
||||
UIStore.instance.windowWidth = 1024;
|
||||
UIStore.instance.emit(UI_EVENTS.Resize);
|
||||
});
|
||||
|
||||
expect(result.current).toBe(1024);
|
||||
});
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue