Merge branch 'develop' into johannes/find-myself

This commit is contained in:
Johannes Marbach 2023-02-13 20:16:04 +01:00 committed by GitHub
commit d0e9331f07
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
612 changed files with 3608 additions and 2769 deletions

View file

@ -83,7 +83,7 @@ describe("avatarUrlForRoom", () => {
it("should return null if there is no other member in the room", () => {
mocked(dmRoomMap).getUserIdForRoomId.mockReturnValue("@user:example.com");
mocked(room.getAvatarFallbackMember).mockReturnValue(null);
mocked(room.getAvatarFallbackMember).mockReturnValue(undefined);
expect(avatarUrlForRoom(room, 128, 128)).toBeNull();
});

View file

@ -238,7 +238,7 @@ describe("LegacyCallHandler", () => {
return [];
}
},
} as DMRoomMap;
} as unknown as DMRoomMap;
DMRoomMap.setShared(dmRoomMap);
pstnLookup = null;

View file

@ -266,7 +266,7 @@ describe("Notifier", () => {
});
});
describe("_displayPopupNotification", () => {
describe("displayPopupNotification", () => {
const testCases: { event: IContent | undefined; count: number }[] = [
{ event: { is_silenced: true }, count: 0 },
{ event: { is_silenced: false }, count: 1 },
@ -274,13 +274,13 @@ describe("Notifier", () => {
];
it.each(testCases)("does not dispatch when notifications are silenced", ({ event, count }) => {
mockClient.setAccountData(accountDataEventKey, event!);
Notifier._displayPopupNotification(testEvent, testRoom);
Notifier.displayPopupNotification(testEvent, testRoom);
expect(MockPlatform.displayNotification).toHaveBeenCalledTimes(count);
});
it("should display a notification for a voice message", () => {
const audioEvent = mkAudioEvent();
Notifier._displayPopupNotification(audioEvent, testRoom);
Notifier.displayPopupNotification(audioEvent, testRoom);
expect(MockPlatform.displayNotification).toHaveBeenCalledWith(
"@user:example.com (!room1:server)",
"@user:example.com: test audio message",
@ -292,7 +292,7 @@ describe("Notifier", () => {
it("should display the expected notification for a broadcast chunk with sequence = 1", () => {
const audioEvent = mkAudioEvent({ sequence: 1 });
Notifier._displayPopupNotification(audioEvent, testRoom);
Notifier.displayPopupNotification(audioEvent, testRoom);
expect(MockPlatform.displayNotification).toHaveBeenCalledWith(
"@user:example.com (!room1:server)",
"@user:example.com started a voice broadcast",
@ -304,7 +304,7 @@ describe("Notifier", () => {
it("should display the expected notification for a broadcast chunk with sequence = 1", () => {
const audioEvent = mkAudioEvent({ sequence: 2 });
Notifier._displayPopupNotification(audioEvent, testRoom);
Notifier.displayPopupNotification(audioEvent, testRoom);
expect(MockPlatform.displayNotification).not.toHaveBeenCalled();
});
});
@ -330,7 +330,7 @@ describe("Notifier", () => {
Notifier.getSoundForRoom = jest.fn();
mockClient.setAccountData(accountDataEventKey, event!);
Notifier._playAudioNotification(testEvent, testRoom);
Notifier.playAudioNotification(testEvent, testRoom);
expect(Notifier.getSoundForRoom).toHaveBeenCalledTimes(count);
});
});
@ -445,7 +445,7 @@ describe("Notifier", () => {
});
});
describe("_evaluateEvent", () => {
describe("evaluateEvent", () => {
beforeEach(() => {
jest.spyOn(SdkContextClass.instance.roomViewStore, "getRoomId").mockReturnValue(testRoom.roomId);
@ -453,7 +453,7 @@ describe("Notifier", () => {
jest.spyOn(Modal, "hasDialogs").mockReturnValue(false);
jest.spyOn(Notifier, "_displayPopupNotification").mockReset();
jest.spyOn(Notifier, "displayPopupNotification").mockReset();
jest.spyOn(Notifier, "isEnabled").mockReturnValue(true);
mockClient.getPushActionsForEvent.mockReturnValue({
@ -465,9 +465,9 @@ describe("Notifier", () => {
});
it("should show a pop-up", () => {
expect(Notifier._displayPopupNotification).toHaveBeenCalledTimes(0);
Notifier._evaluateEvent(testEvent);
expect(Notifier._displayPopupNotification).toHaveBeenCalledTimes(0);
expect(Notifier.displayPopupNotification).toHaveBeenCalledTimes(0);
Notifier.evaluateEvent(testEvent);
expect(Notifier.displayPopupNotification).toHaveBeenCalledTimes(0);
const eventFromOtherRoom = mkEvent({
event: true,
@ -477,8 +477,8 @@ describe("Notifier", () => {
content: {},
});
Notifier._evaluateEvent(eventFromOtherRoom);
expect(Notifier._displayPopupNotification).toHaveBeenCalledTimes(1);
Notifier.evaluateEvent(eventFromOtherRoom);
expect(Notifier.displayPopupNotification).toHaveBeenCalledTimes(1);
});
it("should a pop-up for thread event", async () => {
@ -489,13 +489,13 @@ describe("Notifier", () => {
participantUserIds: ["@bob:example.org"],
});
expect(Notifier._displayPopupNotification).toHaveBeenCalledTimes(0);
expect(Notifier.displayPopupNotification).toHaveBeenCalledTimes(0);
Notifier._evaluateEvent(rootEvent);
expect(Notifier._displayPopupNotification).toHaveBeenCalledTimes(0);
Notifier.evaluateEvent(rootEvent);
expect(Notifier.displayPopupNotification).toHaveBeenCalledTimes(0);
Notifier._evaluateEvent(events[1]);
expect(Notifier._displayPopupNotification).toHaveBeenCalledTimes(1);
Notifier.evaluateEvent(events[1]);
expect(Notifier.displayPopupNotification).toHaveBeenCalledTimes(1);
dis.dispatch<ThreadPayload>({
action: Action.ViewThread,
@ -504,13 +504,13 @@ describe("Notifier", () => {
await waitFor(() => expect(SdkContextClass.instance.roomViewStore.getThreadId()).toBe(rootEvent.getId()));
Notifier._evaluateEvent(events[1]);
expect(Notifier._displayPopupNotification).toHaveBeenCalledTimes(1);
Notifier.evaluateEvent(events[1]);
expect(Notifier.displayPopupNotification).toHaveBeenCalledTimes(1);
});
it("should show a pop-up for an audio message", () => {
Notifier._evaluateEvent(mkAudioEvent());
expect(Notifier._displayPopupNotification).toHaveBeenCalledTimes(1);
Notifier.evaluateEvent(mkAudioEvent());
expect(Notifier.displayPopupNotification).toHaveBeenCalledTimes(1);
});
it("should not show a notification for broadcast info events in any case", () => {
@ -527,8 +527,8 @@ describe("Notifier", () => {
"ABC123",
);
Notifier._evaluateEvent(broadcastStartedEvent);
expect(Notifier._displayPopupNotification).not.toHaveBeenCalled();
Notifier.evaluateEvent(broadcastStartedEvent);
expect(Notifier.displayPopupNotification).not.toHaveBeenCalled();
});
});

View file

@ -42,7 +42,7 @@ export interface ITestEvent extends IPosthogEvent {
describe("PosthogAnalytics", () => {
let fakePosthog: PostHog;
const shaHashes = {
const shaHashes: Record<string, string> = {
"42": "73475cb40a568e8da8a045ced110137e159f890ac4da883b6b17dc651b3a8049",
"some": "a6b46dd0d1ae5e86cbc8f37e75ceeb6760230c1ca4ffbcb0c97b96dd7d9c464b",
"pii": "bd75b3e080945674c0351f75e0db33d1e90986fa07b318ea7edf776f5eef38d4",
@ -54,7 +54,7 @@ describe("PosthogAnalytics", () => {
window.crypto = {
subtle: {
digest: async (_, encodedMessage) => {
digest: async (_: AlgorithmIdentifier, encodedMessage: BufferSource) => {
const message = new TextDecoder().decode(encodedMessage);
const hexHash = shaHashes[message];
const bytes = [];

View file

@ -16,6 +16,7 @@ limitations under the License.
import { mocked } from "jest-mock";
import fetchMock from "fetch-mock-jest";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import ScalarAuthClient from "../src/ScalarAuthClient";
import { stubClient } from "./test-utils";
@ -32,7 +33,7 @@ describe("ScalarAuthClient", function () {
expires_in: 999,
};
let client;
let client: MatrixClient;
beforeEach(function () {
jest.clearAllMocks();
client = stubClient();

View file

@ -17,7 +17,7 @@ limitations under the License.
import { EventType, MatrixClient, MatrixEvent, Room, RoomMember } from "matrix-js-sdk/src/matrix";
import TestRenderer from "react-test-renderer";
import { ReactElement } from "react";
import { mocked } from "jest-mock";
import { Mocked, mocked } from "jest-mock";
import { textForEvent } from "../src/TextForEvent";
import SettingsStore from "../src/settings/SettingsStore";
@ -49,8 +49,14 @@ function mockPinnedEvent(pinnedMessageIds?: string[], prevPinnedMessageIds?: str
// Helper function that renders a component to a plain text string.
// Once snapshots are introduced in tests, this function will no longer be necessary,
// and should be replaced with snapshots.
function renderComponent(component): string {
const serializeObject = (object): string => {
function renderComponent(component: TestRenderer.ReactTestRenderer): string {
const serializeObject = (
object:
| TestRenderer.ReactTestRendererJSON
| TestRenderer.ReactTestRendererJSON[]
| TestRenderer.ReactTestRendererNode
| TestRenderer.ReactTestRendererNode[],
): string => {
if (typeof object === "string") {
return object === " " ? "" : object;
}
@ -59,8 +65,8 @@ function renderComponent(component): string {
return object[0];
}
if (object["type"] !== undefined && typeof object["children"] !== undefined) {
return serializeObject(object.children);
if (!Array.isArray(object) && object["type"] !== undefined && typeof object["children"] !== undefined) {
return serializeObject(object.children!);
}
if (!Array.isArray(object)) {
@ -74,7 +80,7 @@ function renderComponent(component): string {
.join("");
};
return serializeObject(component.toJSON());
return serializeObject(component.toJSON()!);
}
describe("TextForEvent", () => {
@ -168,26 +174,26 @@ describe("TextForEvent", () => {
});
describe("textForPowerEvent()", () => {
let mockClient;
let mockClient: Mocked<MatrixClient>;
const mockRoom = {
getMember: jest.fn(),
};
} as unknown as Mocked<Room>;
const userA = {
id: "@a",
userId: "@a",
name: "Alice",
rawDisplayName: "Alice",
};
} as RoomMember;
const userB = {
id: "@b",
userId: "@b",
name: "Bob (@b)",
rawDisplayName: "Bob",
};
} as RoomMember;
const userC = {
id: "@c",
userId: "@c",
name: "Bob (@c)",
rawDisplayName: "Bob",
};
} as RoomMember;
interface PowerEventProps {
usersDefault?: number;
prevDefault?: number;
@ -197,7 +203,7 @@ describe("TextForEvent", () => {
const mockPowerEvent = ({ usersDefault, prevDefault, users, prevUsers }: PowerEventProps): MatrixEvent => {
const mxEvent = new MatrixEvent({
type: EventType.RoomPowerLevels,
sender: userA.id,
sender: userA.userId,
state_key: "",
content: {
users_default: usersDefault,
@ -213,12 +219,12 @@ describe("TextForEvent", () => {
};
beforeAll(() => {
mockClient = createTestClient();
mockClient = createTestClient() as Mocked<MatrixClient>;
MatrixClientPeg.get = () => mockClient;
mockClient.getRoom.mockClear().mockReturnValue(mockRoom);
mockRoom.getMember
.mockClear()
.mockImplementation((userId) => [userA, userB, userC].find((u) => u.id === userId));
.mockImplementation((userId) => [userA, userB, userC].find((u) => u.userId === userId) || null);
(SettingsStore.getValue as jest.Mock).mockReturnValue(true);
});
@ -231,10 +237,10 @@ describe("TextForEvent", () => {
it("returns falsy when no users have changed power level", () => {
const event = mockPowerEvent({
users: {
[userA.id]: 100,
[userA.userId]: 100,
},
prevUsers: {
[userA.id]: 100,
[userA.userId]: 100,
},
});
expect(textForEvent(event)).toBeFalsy();
@ -245,10 +251,10 @@ describe("TextForEvent", () => {
usersDefault: 100,
prevDefault: 50,
users: {
[userA.id]: 100,
[userA.userId]: 100,
},
prevUsers: {
[userA.id]: 50,
[userA.userId]: 50,
},
});
expect(textForEvent(event)).toBeFalsy();
@ -257,10 +263,10 @@ describe("TextForEvent", () => {
it("returns correct message for a single user with changed power level", () => {
const event = mockPowerEvent({
users: {
[userB.id]: 100,
[userB.userId]: 100,
},
prevUsers: {
[userB.id]: 50,
[userB.userId]: 50,
},
});
const expectedText = "Alice changed the power level of Bob (@b) from Moderator to Admin.";
@ -272,10 +278,10 @@ describe("TextForEvent", () => {
usersDefault: 20,
prevDefault: 101,
users: {
[userB.id]: 20,
[userB.userId]: 20,
},
prevUsers: {
[userB.id]: 50,
[userB.userId]: 50,
},
});
const expectedText = "Alice changed the power level of Bob (@b) from Moderator to Default.";
@ -285,10 +291,10 @@ describe("TextForEvent", () => {
it("returns correct message for a single user with power level changed to a custom level", () => {
const event = mockPowerEvent({
users: {
[userB.id]: -1,
[userB.userId]: -1,
},
prevUsers: {
[userB.id]: 50,
[userB.userId]: 50,
},
});
const expectedText = "Alice changed the power level of Bob (@b) from Moderator to Custom (-1).";
@ -298,12 +304,12 @@ describe("TextForEvent", () => {
it("returns correct message for a multiple power level changes", () => {
const event = mockPowerEvent({
users: {
[userB.id]: 100,
[userC.id]: 50,
[userB.userId]: 100,
[userC.userId]: 50,
},
prevUsers: {
[userB.id]: 50,
[userC.id]: 101,
[userB.userId]: 50,
[userC.userId]: 101,
},
});
const expectedText =
@ -315,7 +321,7 @@ describe("TextForEvent", () => {
describe("textForCanonicalAliasEvent()", () => {
const userA = {
id: "@a",
userId: "@a",
name: "Alice",
};
@ -328,7 +334,7 @@ describe("TextForEvent", () => {
const mockEvent = ({ alias, prevAlias, altAliases, prevAltAliases }: AliasEventProps): MatrixEvent =>
new MatrixEvent({
type: EventType.RoomCanonicalAlias,
sender: userA.id,
sender: userA.userId,
state_key: "",
content: {
alias,
@ -418,7 +424,7 @@ describe("TextForEvent", () => {
});
describe("textForPollStartEvent()", () => {
let pollEvent;
let pollEvent: MatrixEvent;
beforeEach(() => {
pollEvent = new MatrixEvent({
@ -449,7 +455,7 @@ describe("TextForEvent", () => {
});
describe("textForMessageEvent()", () => {
let messageEvent;
let messageEvent: MatrixEvent;
beforeEach(() => {
messageEvent = new MatrixEvent({

View file

@ -20,34 +20,32 @@ import EventEmitter from "events";
import UserActivity from "../src/UserActivity";
class FakeDomEventEmitter extends EventEmitter {
addEventListener(what, l) {
addEventListener(what: string, l: (...args: any[]) => void) {
this.on(what, l);
}
removeEventListener(what, l) {
removeEventListener(what: string, l: (...args: any[]) => void) {
this.removeListener(what, l);
}
}
describe("UserActivity", function () {
let fakeWindow;
let fakeDocument;
let userActivity;
let clock;
let fakeWindow: FakeDomEventEmitter;
let fakeDocument: FakeDomEventEmitter & { hasFocus?(): boolean };
let userActivity: UserActivity;
let clock: FakeTimers.InstalledClock;
beforeEach(function () {
fakeWindow = new FakeDomEventEmitter();
fakeDocument = new FakeDomEventEmitter();
userActivity = new UserActivity(fakeWindow, fakeDocument);
userActivity = new UserActivity(fakeWindow as unknown as Window, fakeDocument as unknown as Document);
userActivity.start();
clock = FakeTimers.install();
});
afterEach(function () {
userActivity.stop();
userActivity = null;
clock.uninstall();
clock = null;
});
it("should return the same shared instance", function () {
@ -65,7 +63,7 @@ describe("UserActivity", function () {
it("should not consider user active after activity if no window focus", function () {
fakeDocument.hasFocus = jest.fn().mockReturnValue(false);
userActivity.onUserActivity({});
userActivity.onUserActivity({ type: "event" } as Event);
expect(userActivity.userActiveNow()).toBe(false);
expect(userActivity.userActiveRecently()).toBe(false);
});
@ -73,7 +71,7 @@ describe("UserActivity", function () {
it("should consider user active shortly after activity", function () {
fakeDocument.hasFocus = jest.fn().mockReturnValue(true);
userActivity.onUserActivity({});
userActivity.onUserActivity({ type: "event" } as Event);
expect(userActivity.userActiveNow()).toBe(true);
expect(userActivity.userActiveRecently()).toBe(true);
clock.tick(200);
@ -84,7 +82,7 @@ describe("UserActivity", function () {
it("should consider user not active after 10s of no activity", function () {
fakeDocument.hasFocus = jest.fn().mockReturnValue(true);
userActivity.onUserActivity({});
userActivity.onUserActivity({ type: "event" } as Event);
clock.tick(10000);
expect(userActivity.userActiveNow()).toBe(false);
});
@ -92,7 +90,7 @@ describe("UserActivity", function () {
it("should consider user passive after 10s of no activity", function () {
fakeDocument.hasFocus = jest.fn().mockReturnValue(true);
userActivity.onUserActivity({});
userActivity.onUserActivity({ type: "event" } as Event);
clock.tick(10000);
expect(userActivity.userActiveRecently()).toBe(true);
});
@ -100,7 +98,7 @@ describe("UserActivity", function () {
it("should not consider user passive after 10s if window un-focused", function () {
fakeDocument.hasFocus = jest.fn().mockReturnValue(true);
userActivity.onUserActivity({});
userActivity.onUserActivity({ type: "event" } as Event);
clock.tick(10000);
fakeDocument.hasFocus = jest.fn().mockReturnValue(false);
@ -112,7 +110,7 @@ describe("UserActivity", function () {
it("should not consider user passive after 3 mins", function () {
fakeDocument.hasFocus = jest.fn().mockReturnValue(true);
userActivity.onUserActivity({});
userActivity.onUserActivity({ type: "event" } as Event);
clock.tick(3 * 60 * 1000);
expect(userActivity.userActiveRecently()).toBe(false);
@ -121,11 +119,11 @@ describe("UserActivity", function () {
it("should extend timer on activity", function () {
fakeDocument.hasFocus = jest.fn().mockReturnValue(true);
userActivity.onUserActivity({});
userActivity.onUserActivity({ type: "event" } as Event);
clock.tick(1 * 60 * 1000);
userActivity.onUserActivity({});
userActivity.onUserActivity({ type: "event" } as Event);
clock.tick(1 * 60 * 1000);
userActivity.onUserActivity({});
userActivity.onUserActivity({ type: "event" } as Event);
clock.tick(1 * 60 * 1000);
expect(userActivity.userActiveRecently()).toBe(true);

View file

@ -20,7 +20,7 @@ import { mockPlatformPeg, unmockPlatformPeg } from "../test-utils";
const PATH_TO_KEYBOARD_SHORTCUTS = "../../src/accessibility/KeyboardShortcuts";
const PATH_TO_KEYBOARD_SHORTCUT_UTILS = "../../src/accessibility/KeyboardShortcutUtils";
const mockKeyboardShortcuts = (override) => {
const mockKeyboardShortcuts = (override: Record<string, any>) => {
jest.doMock(PATH_TO_KEYBOARD_SHORTCUTS, () => {
const original = jest.requireActual(PATH_TO_KEYBOARD_SHORTCUTS);
return {

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import * as React from "react";
import React, { HTMLAttributes } from "react";
import { render } from "@testing-library/react";
import {
@ -26,8 +26,8 @@ import {
useRovingTabIndex,
} from "../../src/accessibility/RovingTabIndex";
const Button = (props) => {
const [onFocus, isActive, ref] = useRovingTabIndex();
const Button = (props: HTMLAttributes<HTMLButtonElement>) => {
const [onFocus, isActive, ref] = useRovingTabIndex<HTMLButtonElement>();
return <button {...props} onFocus={onFocus} tabIndex={isActive ? 0 : -1} ref={ref} />;
};

View file

@ -18,7 +18,7 @@ limitations under the License.
import React from "react";
import ReactDOM from "react-dom";
import { EventEmitter } from "events";
import { Room, RoomMember } from "matrix-js-sdk/src/matrix";
import { MatrixEvent, Room, RoomMember } from "matrix-js-sdk/src/matrix";
import FakeTimers from "@sinonjs/fake-timers";
import { render } from "@testing-library/react";
import { Thread } from "matrix-js-sdk/src/models/thread";
@ -46,7 +46,7 @@ jest.mock("../../../src/utils/beacon", () => ({
const roomId = "!roomId:server_name";
describe("MessagePanel", function () {
let clock = null;
let clock: FakeTimers.InstalledClock | null = null;
const realSetTimeout = window.setTimeout;
const events = mkEvents();
const userId = "@me:here";
@ -79,7 +79,7 @@ describe("MessagePanel", function () {
callEventGroupers: new Map(),
room,
className: "cls",
events: [],
events: [] as MatrixEvent[],
};
const defaultRoomContext = {
@ -322,8 +322,8 @@ describe("MessagePanel", function () {
];
}
function isReadMarkerVisible(rmContainer) {
return rmContainer && rmContainer.children.length > 0;
function isReadMarkerVisible(rmContainer?: Element) {
return rmContainer?.children.length > 0;
}
it("should show the events", function () {

View file

@ -49,7 +49,7 @@ describe("<RoomSearchView/>", () => {
stubClient();
client = MatrixClientPeg.get();
client.supportsThreads = jest.fn().mockReturnValue(true);
room = new Room("!room:server", client, client.getUserId());
room = new Room("!room:server", client, client.getUserId()!);
mocked(client.getRoom).mockReturnValue(room);
permalinkCreator = new RoomPermalinkCreator(room, room.roomId);
@ -92,7 +92,7 @@ describe("<RoomSearchView/>", () => {
result: {
room_id: room.roomId,
event_id: "$2",
sender: client.getUserId(),
sender: client.getUserId()!,
origin_server_ts: 1,
content: { body: "Foo Test Bar", msgtype: "m.text" },
type: EventType.RoomMessage,
@ -103,7 +103,7 @@ describe("<RoomSearchView/>", () => {
{
room_id: room.roomId,
event_id: "$1",
sender: client.getUserId(),
sender: client.getUserId()!,
origin_server_ts: 1,
content: { body: "Before", msgtype: "m.text" },
type: EventType.RoomMessage,
@ -113,7 +113,7 @@ describe("<RoomSearchView/>", () => {
{
room_id: room.roomId,
event_id: "$3",
sender: client.getUserId(),
sender: client.getUserId()!,
origin_server_ts: 1,
content: { body: "After", msgtype: "m.text" },
type: EventType.RoomMessage,
@ -154,7 +154,7 @@ describe("<RoomSearchView/>", () => {
result: {
room_id: room.roomId,
event_id: "$2",
sender: client.getUserId(),
sender: client.getUserId()!,
origin_server_ts: 1,
content: { body: "Foo Test Bar", msgtype: "m.text" },
type: EventType.RoomMessage,
@ -192,7 +192,7 @@ describe("<RoomSearchView/>", () => {
result: {
room_id: room.roomId,
event_id: "$2",
sender: client.getUserId(),
sender: client.getUserId()!,
origin_server_ts: 1,
content: { body: "Foo Test Bar", msgtype: "m.text" },
type: EventType.RoomMessage,
@ -221,7 +221,7 @@ describe("<RoomSearchView/>", () => {
result: {
room_id: room.roomId,
event_id: "$4",
sender: client.getUserId(),
sender: client.getUserId()!,
origin_server_ts: 4,
content: { body: "Potato", msgtype: "m.text" },
type: EventType.RoomMessage,

View file

@ -55,6 +55,7 @@ const RoomView = wrapInMatrixClientContext(_RoomView);
describe("RoomView", () => {
let cli: MockedObject<MatrixClient>;
let room: Room;
let rooms: Map<string, Room>;
let roomCount = 0;
let stores: SdkContextClass;
@ -64,8 +65,11 @@ describe("RoomView", () => {
cli = mocked(MatrixClientPeg.get());
room = new Room(`!${roomCount++}:example.org`, cli, "@alice:example.org");
jest.spyOn(room, "findPredecessor");
room.getPendingEvents = () => [];
cli.getRoom.mockImplementation(() => room);
rooms = new Map();
rooms.set(room.roomId, room);
cli.getRoom.mockImplementation((roomId: string | undefined) => rooms.get(roomId || "") || null);
// Re-emit certain events on the mocked client
room.on(RoomEvent.Timeline, (...args) => cli.emit(RoomEvent.Timeline, ...args));
room.on(RoomEvent.TimelineReset, (...args) => cli.emit(RoomEvent.TimelineReset, ...args));
@ -158,6 +162,42 @@ describe("RoomView", () => {
const getRoomViewInstance = async (): Promise<_RoomView> =>
(await mountRoomView()).find(_RoomView).instance() as _RoomView;
it("when there is no room predecessor, getHiddenHighlightCount should return 0", async () => {
const instance = await getRoomViewInstance();
expect(instance.getHiddenHighlightCount()).toBe(0);
});
describe("when there is an old room", () => {
let instance: _RoomView;
let oldRoom: Room;
beforeEach(async () => {
instance = await getRoomViewInstance();
oldRoom = new Room("!old:example.com", cli, cli.getSafeUserId());
rooms.set(oldRoom.roomId, oldRoom);
jest.spyOn(room, "findPredecessor").mockReturnValue({ roomId: oldRoom.roomId, eventId: null });
});
it("and it has 0 unreads, getHiddenHighlightCount should return 0", async () => {
jest.spyOn(oldRoom, "getUnreadNotificationCount").mockReturnValue(0);
expect(instance.getHiddenHighlightCount()).toBe(0);
// assert that msc3946ProcessDynamicPredecessor is false by default
expect(room.findPredecessor).toHaveBeenCalledWith(false);
});
it("and it has 23 unreads, getHiddenHighlightCount should return 23", async () => {
jest.spyOn(oldRoom, "getUnreadNotificationCount").mockReturnValue(23);
expect(instance.getHiddenHighlightCount()).toBe(23);
});
it("and feature_dynamic_room_predecessors is enabled it should pass the setting to findPredecessor", async () => {
SettingsStore.setValue("feature_dynamic_room_predecessors", null, SettingLevel.DEVICE, true);
expect(instance.getHiddenHighlightCount()).toBe(0);
expect(room.findPredecessor).toHaveBeenCalledWith(true);
SettingsStore.setValue("feature_dynamic_room_predecessors", null, SettingLevel.DEVICE, null);
});
});
it("updates url preview visibility on encryption state change", async () => {
// we should be starting unencrypted
expect(cli.isCryptoEnabled()).toEqual(false);
@ -248,6 +288,7 @@ describe("RoomView", () => {
beforeEach(async () => {
localRoom = room = await createDmLocalRoom(cli, [new DirectoryMember({ user_id: "@user:example.com" })]);
rooms.set(localRoom.roomId, localRoom);
cli.store.storeRoom(room);
});

View file

@ -43,20 +43,20 @@ describe("<TabbedView />", () => {
it("renders first tab as active tab when no initialTabId", () => {
const { container } = render(getComponent());
expect(getActiveTab(container).textContent).toEqual(generalTab.label);
expect(getActiveTabBody(container).textContent).toEqual("general");
expect(getActiveTab(container)?.textContent).toEqual(generalTab.label);
expect(getActiveTabBody(container)?.textContent).toEqual("general");
});
it("renders first tab as active tab when initialTabId is not valid", () => {
const { container } = render(getComponent({ initialTabId: "bad-tab-id" }));
expect(getActiveTab(container).textContent).toEqual(generalTab.label);
expect(getActiveTabBody(container).textContent).toEqual("general");
expect(getActiveTab(container)?.textContent).toEqual(generalTab.label);
expect(getActiveTabBody(container)?.textContent).toEqual("general");
});
it("renders initialTabId tab as active when valid", () => {
const { container } = render(getComponent({ initialTabId: securityTab.id }));
expect(getActiveTab(container).textContent).toEqual(securityTab.label);
expect(getActiveTabBody(container).textContent).toEqual("security");
expect(getActiveTab(container)?.textContent).toEqual(securityTab.label);
expect(getActiveTabBody(container)?.textContent).toEqual("security");
});
it("renders without error when there are no tabs", () => {
@ -71,8 +71,8 @@ describe("<TabbedView />", () => {
fireEvent.click(getByTestId(getTabTestId(securityTab)));
});
expect(getActiveTab(container).textContent).toEqual(securityTab.label);
expect(getActiveTabBody(container).textContent).toEqual("security");
expect(getActiveTab(container)?.textContent).toEqual(securityTab.label);
expect(getActiveTabBody(container)?.textContent).toEqual("security");
});
it("calls onchange on on tab click", () => {
@ -90,29 +90,29 @@ describe("<TabbedView />", () => {
// start with middle tab active
const { container, rerender } = render(getComponent({ initialTabId: labsTab.id }));
expect(getActiveTab(container).textContent).toEqual(labsTab.label);
expect(getActiveTab(container)?.textContent).toEqual(labsTab.label);
rerender(getComponent({ tabs: [labsTab, generalTab, securityTab] }));
// labs tab still active
expect(getActiveTab(container).textContent).toEqual(labsTab.label);
expect(getActiveTab(container)?.textContent).toEqual(labsTab.label);
});
it("does not reactivate inititalTabId on rerender", () => {
const { container, getByTestId, rerender } = render(getComponent());
expect(getActiveTab(container).textContent).toEqual(generalTab.label);
expect(getActiveTab(container)?.textContent).toEqual(generalTab.label);
// make security tab active
act(() => {
fireEvent.click(getByTestId(getTabTestId(securityTab)));
});
expect(getActiveTab(container).textContent).toEqual(securityTab.label);
expect(getActiveTab(container)?.textContent).toEqual(securityTab.label);
// rerender with new tab location
rerender(getComponent({ tabLocation: TabLocation.TOP }));
// still security tab
expect(getActiveTab(container).textContent).toEqual(securityTab.label);
expect(getActiveTab(container)?.textContent).toEqual(securityTab.label);
});
});

View file

@ -83,7 +83,7 @@ describe("ThreadView", () => {
return renderResult;
}
async function sendMessage(container, text): Promise<void> {
async function sendMessage(container: HTMLElement, text: string): Promise<void> {
const composer = getByTestId(container, "basicmessagecomposer");
await userEvent.click(composer);
await userEvent.keyboard(text);
@ -91,7 +91,7 @@ describe("ThreadView", () => {
await userEvent.click(sendMessageBtn);
}
function expectedMessageBody(rootEvent, message) {
function expectedMessageBody(rootEvent: MatrixEvent, message: string) {
return {
"body": message,
"m.relates_to": {

View file

@ -16,7 +16,7 @@ limitations under the License.
import React from "react";
// eslint-disable-next-line deprecate/import
import { mount } from "enzyme";
import { mount, ReactWrapper } from "enzyme";
import { mocked } from "jest-mock";
import { logger } from "matrix-js-sdk/src/logger";
import { act } from "react-dom/test-utils";
@ -71,7 +71,7 @@ describe("<RecordingPlayback />", () => {
mocked(createAudioContext).mockReturnValue(mockAudioContext as unknown as AudioContext);
});
const getPlayButton = (component) => findByTestId(component, "play-pause-button").at(0);
const getPlayButton = (component: ReactWrapper) => findByTestId(component, "play-pause-button").at(0);
it("renders recording playback", () => {
const playback = new Playback(new ArrayBuffer(8));

View file

@ -19,7 +19,7 @@ import { mocked } from "jest-mock";
import { MatrixClient, PendingEventOrdering } from "matrix-js-sdk/src/client";
import { Room } from "matrix-js-sdk/src/models/room";
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import React from "react";
import React, { ComponentProps } from "react";
import MemberAvatar from "../../../../src/components/views/avatars/MemberAvatar";
import RoomContext from "../../../../src/contexts/RoomContext";
@ -35,7 +35,7 @@ describe("MemberAvatar", () => {
let room: Room;
let member: RoomMember;
function getComponent(props) {
function getComponent(props: Partial<ComponentProps<typeof MemberAvatar>>) {
return (
<RoomContext.Provider value={getRoomContext(room, {})}>
<MemberAvatar member={null} width={35} height={35} {...props} />

View file

@ -101,7 +101,7 @@ describe("<BeaconViewDialog />", () => {
it("renders a map with markers", () => {
const room = setupRoom([defaultEvent]);
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent));
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent))!;
beacon.addLocations([location1]);
const component = getComponent();
expect(component.find("Map").props()).toEqual(
@ -116,7 +116,7 @@ describe("<BeaconViewDialog />", () => {
it("does not render any own beacon status when user is not live sharing", () => {
// default event belongs to alice, we are bob
const room = setupRoom([defaultEvent]);
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent));
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent))!;
beacon.addLocations([location1]);
const component = getComponent();
expect(component.find("DialogOwnBeaconStatus").html()).toBeNull();
@ -125,7 +125,7 @@ describe("<BeaconViewDialog />", () => {
it("renders own beacon status when user is live sharing", () => {
// default event belongs to alice
const room = setupRoom([defaultEvent]);
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent));
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent))!;
beacon.addLocations([location1]);
// mock own beacon store to show default event as alice's live beacon
jest.spyOn(OwnBeaconStore.instance, "getLiveBeaconIds").mockReturnValue([beacon.identifier]);
@ -141,7 +141,7 @@ describe("<BeaconViewDialog />", () => {
it("updates markers on changes to beacons", () => {
const room = setupRoom([defaultEvent]);
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent));
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent))!;
beacon.addLocations([location1]);
const component = getComponent();
expect(component.find("BeaconMarker").length).toEqual(1);
@ -161,7 +161,7 @@ describe("<BeaconViewDialog />", () => {
it("does not update bounds or center on changing beacons", () => {
const room = setupRoom([defaultEvent]);
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent));
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent))!;
beacon.addLocations([location1]);
const component = getComponent();
expect(component.find("BeaconMarker").length).toEqual(1);
@ -200,7 +200,7 @@ describe("<BeaconViewDialog />", () => {
it("renders map without markers when no live beacons remain", () => {
const onFinished = jest.fn();
const room = setupRoom([defaultEvent]);
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent));
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent))!;
beacon.addLocations([location1]);
const component = getComponent({ onFinished });
expect(component.find("BeaconMarker").length).toEqual(1);
@ -233,7 +233,7 @@ describe("<BeaconViewDialog />", () => {
describe("sidebar", () => {
it("opens sidebar on view list button click", () => {
const room = setupRoom([defaultEvent]);
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent));
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent))!;
beacon.addLocations([location1]);
const component = getComponent();
@ -244,7 +244,7 @@ describe("<BeaconViewDialog />", () => {
it("closes sidebar on close button click", () => {
const room = setupRoom([defaultEvent]);
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent));
const beacon = room.currentState.beacons.get(getBeaconInfoIdentifier(defaultEvent))!;
beacon.addLocations([location1]);
const component = getComponent();

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import React, { ComponentProps } from "react";
import { fireEvent, render } from "@testing-library/react";
import { act } from "react-dom/test-utils";
@ -29,7 +29,7 @@ import {
} from "../../../test-utils";
describe("<DialogSidebar />", () => {
const defaultProps = {
const defaultProps: ComponentProps<typeof DialogSidebar> = {
beacons: [],
requestClose: jest.fn(),
onBeaconClick: jest.fn(),

View file

@ -15,16 +15,15 @@ limitations under the License.
*/
import React from "react";
// eslint-disable-next-line deprecate/import
import { mount } from "enzyme";
import { act } from "react-dom/test-utils";
import { mocked } from "jest-mock";
import { Beacon } from "matrix-js-sdk/src/matrix";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import OwnBeaconStatus from "../../../../src/components/views/beacon/OwnBeaconStatus";
import { BeaconDisplayStatus } from "../../../../src/components/views/beacon/displayStatus";
import { useOwnLiveBeacons } from "../../../../src/utils/beacon";
import { findByTestId, makeBeaconInfoEvent } from "../../../test-utils";
import { makeBeaconInfoEvent } from "../../../test-utils";
jest.mock("../../../../src/utils/beacon/useOwnLiveBeacons", () => ({
useOwnLiveBeacons: jest.fn(),
@ -36,8 +35,11 @@ describe("<OwnBeaconStatus />", () => {
};
const userId = "@user:server";
const roomId = "!room:server";
let defaultBeacon;
const getComponent = (props = {}) => mount(<OwnBeaconStatus {...defaultProps} {...props} />);
let defaultBeacon: Beacon;
const renderComponent = (props: Partial<React.ComponentProps<typeof OwnBeaconStatus>> = {}) =>
render(<OwnBeaconStatus {...defaultProps} {...props} />);
const getRetryButton = () => screen.getByRole("button", { name: "Retry" });
const getStopButton = () => screen.getByRole("button", { name: "Stop" });
beforeEach(() => {
jest.spyOn(global.Date, "now").mockReturnValue(123456789);
@ -47,13 +49,8 @@ describe("<OwnBeaconStatus />", () => {
});
it("renders without a beacon instance", () => {
const component = getComponent();
expect(component).toMatchSnapshot();
});
it("renders loading state correctly", () => {
const component = getComponent();
expect(component.find("BeaconStatus").props()).toBeTruthy();
const { asFragment } = renderComponent();
expect(asFragment()).toMatchSnapshot();
});
describe("Active state", () => {
@ -62,24 +59,19 @@ describe("<OwnBeaconStatus />", () => {
mocked(useOwnLiveBeacons).mockReturnValue({
onStopSharing: jest.fn(),
});
const component = getComponent({ displayStatus, beacon: defaultBeacon });
expect(component.text()).toContain("Live location enabled");
expect(findByTestId(component, "beacon-status-stop-beacon").length).toBeTruthy();
renderComponent({ displayStatus, beacon: defaultBeacon });
expect(screen.getByText("Live location enabled")).toBeInTheDocument();
expect(getStopButton()).toBeInTheDocument();
});
it("stops sharing on stop button click", () => {
it("stops sharing on stop button click", async () => {
const displayStatus = BeaconDisplayStatus.Active;
const onStopSharing = jest.fn();
mocked(useOwnLiveBeacons).mockReturnValue({
onStopSharing,
});
const component = getComponent({ displayStatus, beacon: defaultBeacon });
act(() => {
findByTestId(component, "beacon-status-stop-beacon").at(0).simulate("click");
});
renderComponent({ displayStatus, beacon: defaultBeacon });
await userEvent.click(getStopButton());
expect(onStopSharing).toHaveBeenCalled();
});
});
@ -87,11 +79,11 @@ describe("<OwnBeaconStatus />", () => {
describe("errors", () => {
it("renders in error mode when displayStatus is error", () => {
const displayStatus = BeaconDisplayStatus.Error;
const component = getComponent({ displayStatus });
expect(component.text()).toEqual("Live location error");
renderComponent({ displayStatus });
expect(screen.getByText("Live location error")).toBeInTheDocument();
// no actions for plain error
expect(component.find("AccessibleButton").length).toBeFalsy();
expect(screen.queryByRole("button")).not.toBeInTheDocument();
});
describe("with location publish error", () => {
@ -101,23 +93,21 @@ describe("<OwnBeaconStatus />", () => {
hasLocationPublishError: true,
onResetLocationPublishError: jest.fn(),
});
const component = getComponent({ displayStatus, beacon: defaultBeacon });
expect(component.text()).toContain("Live location error");
renderComponent({ displayStatus, beacon: defaultBeacon });
expect(screen.getByText("Live location error")).toBeInTheDocument();
// retry button
expect(findByTestId(component, "beacon-status-reset-wire-error").length).toBeTruthy();
expect(getRetryButton()).toBeInTheDocument();
});
it("retry button resets location publish error", () => {
it("retry button resets location publish error", async () => {
const displayStatus = BeaconDisplayStatus.Active;
const onResetLocationPublishError = jest.fn();
mocked(useOwnLiveBeacons).mockReturnValue({
hasLocationPublishError: true,
onResetLocationPublishError,
});
const component = getComponent({ displayStatus, beacon: defaultBeacon });
act(() => {
findByTestId(component, "beacon-status-reset-wire-error").at(0).simulate("click");
});
renderComponent({ displayStatus, beacon: defaultBeacon });
await userEvent.click(getRetryButton());
expect(onResetLocationPublishError).toHaveBeenCalled();
});
@ -131,23 +121,21 @@ describe("<OwnBeaconStatus />", () => {
hasStopSharingError: true,
onStopSharing: jest.fn(),
});
const component = getComponent({ displayStatus, beacon: defaultBeacon });
expect(component.text()).toContain("Live location error");
renderComponent({ displayStatus, beacon: defaultBeacon });
expect(screen.getByText("Live location error")).toBeInTheDocument();
// retry button
expect(findByTestId(component, "beacon-status-stop-beacon-retry").length).toBeTruthy();
expect(getRetryButton()).toBeInTheDocument();
});
it("retry button retries stop sharing", () => {
it("retry button retries stop sharing", async () => {
const displayStatus = BeaconDisplayStatus.Active;
const onStopSharing = jest.fn();
mocked(useOwnLiveBeacons).mockReturnValue({
hasStopSharingError: true,
onStopSharing,
});
const component = getComponent({ displayStatus, beacon: defaultBeacon });
act(() => {
findByTestId(component, "beacon-status-stop-beacon-retry").at(0).simulate("click");
});
renderComponent({ displayStatus, beacon: defaultBeacon });
await userEvent.click(getRetryButton());
expect(onStopSharing).toHaveBeenCalled();
});
@ -155,7 +143,7 @@ describe("<OwnBeaconStatus />", () => {
});
it("renders loading state correctly", () => {
const component = getComponent();
const component = renderComponent();
expect(component).toBeTruthy();
});
});

View file

@ -1,27 +1,19 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<OwnBeaconStatus /> renders without a beacon instance 1`] = `
<OwnBeaconStatus
displayStatus="Loading"
>
<BeaconStatus
displayLiveTimeRemaining={true}
displayStatus="Loading"
label="Live location enabled"
<DocumentFragment>
<div
class="mx_BeaconStatus mx_BeaconStatus_Loading"
>
<div
className="mx_BeaconStatus mx_BeaconStatus_Loading"
class="mx_BeaconStatus_description"
>
<div
className="mx_BeaconStatus_description"
<span
class="mx_BeaconStatus_description_status"
>
<span
className="mx_BeaconStatus_description_status"
>
Loading live location...
</span>
</div>
Loading live location...
</span>
</div>
</BeaconStatus>
</OwnBeaconStatus>
</div>
</DocumentFragment>
`;

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import React, { ComponentProps } from "react";
import { IPassphraseInfo } from "matrix-js-sdk/src/crypto/api";
import { act, fireEvent, render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
@ -29,7 +29,7 @@ const securityKey = "EsTc WKmb ivvk jLS7 Y1NH 5CcQ mP1E JJwj B3Fd pFWm t4Dp dbyu
describe("AccessSecretStorageDialog", () => {
let mockClient: Mocked<MatrixClient>;
const defaultProps = {
const defaultProps: ComponentProps<typeof AccessSecretStorageDialog> = {
onFinished: jest.fn(),
checkPrivateKey: jest.fn(),
keyInfo: undefined,

View file

@ -16,7 +16,7 @@ limitations under the License.
import React from "react";
// eslint-disable-next-line deprecate/import
import { mount } from "enzyme";
import { mount, ReactWrapper } from "enzyme";
import { mocked } from "jest-mock";
import { act } from "react-dom/test-utils";
import { Room } from "matrix-js-sdk/src/matrix";
@ -60,42 +60,43 @@ describe("<ExportDialog />", () => {
const getComponent = (props = {}) => mount(<ExportDialog {...defaultProps} {...props} />);
const getSizeInput = (component) => component.find('input[id="size-limit"]');
const getExportTypeInput = (component) => component.find('select[id="export-type"]');
const getAttachmentsCheckbox = (component) => component.find('input[id="include-attachments"]');
const getMessageCountInput = (component) => component.find('input[id="message-count"]');
const getExportFormatInput = (component, format) => component.find(`input[id="exportFormat-${format}"]`);
const getPrimaryButton = (component) => component.find('[data-testid="dialog-primary-button"]');
const getSecondaryButton = (component) => component.find('[data-testid="dialog-cancel-button"]');
const getSizeInput = (component: ReactWrapper) => component.find('input[id="size-limit"]');
const getExportTypeInput = (component: ReactWrapper) => component.find('select[id="export-type"]');
const getAttachmentsCheckbox = (component: ReactWrapper) => component.find('input[id="include-attachments"]');
const getMessageCountInput = (component: ReactWrapper) => component.find('input[id="message-count"]');
const getExportFormatInput = (component: ReactWrapper, format: ExportFormat) =>
component.find(`input[id="exportFormat-${format}"]`);
const getPrimaryButton = (component: ReactWrapper) => component.find('[data-testid="dialog-primary-button"]');
const getSecondaryButton = (component: ReactWrapper) => component.find('[data-testid="dialog-cancel-button"]');
const submitForm = async (component) =>
const submitForm = async (component: ReactWrapper) =>
act(async () => {
getPrimaryButton(component).simulate("click");
component.setProps({});
});
const selectExportFormat = async (component, format: ExportFormat) =>
const selectExportFormat = async (component: ReactWrapper, format: ExportFormat) =>
act(async () => {
getExportFormatInput(component, format).simulate("change");
component.setProps({});
});
const selectExportType = async (component, type: ExportType) =>
const selectExportType = async (component: ReactWrapper, type: ExportType) =>
act(async () => {
getExportTypeInput(component).simulate("change", { target: { value: type } });
component.setProps({});
});
const setMessageCount = async (component, count: number) =>
const setMessageCount = async (component: ReactWrapper, count: number) =>
act(async () => {
getMessageCountInput(component).simulate("change", { target: { value: count } });
component.setProps({});
});
const setSizeLimit = async (component, limit: number) =>
const setSizeLimit = async (component: ReactWrapper, limit: number) =>
act(async () => {
getSizeInput(component).simulate("change", { target: { value: limit } });
component.setProps({});
});
const setIncludeAttachments = async (component, checked) =>
const setIncludeAttachments = async (component: ReactWrapper, checked: boolean) =>
act(async () => {
getAttachmentsCheckbox(component).simulate("change", { target: { checked } });
component.setProps({});

View file

@ -125,8 +125,8 @@ describe("ForwardDialog", () => {
const { container } = mountForwardDialog();
// Make sendEvent require manual resolution so we can see the sending state
let finishSend;
let cancelSend;
let finishSend: (arg?: any) => void;
let cancelSend: () => void;
mockClient.sendEvent.mockImplementation(
<T extends {}>() =>
new Promise<T>((resolve, reject) => {
@ -135,8 +135,8 @@ describe("ForwardDialog", () => {
}),
);
let firstButton;
let secondButton;
let firstButton: Element;
let secondButton: Element;
const update = () => {
[firstButton, secondButton] = container.querySelectorAll(".mx_ForwardList_sendButton");
};
@ -253,7 +253,7 @@ describe("ForwardDialog", () => {
[M_ASSET.name]: { type: LocationAssetType.Pin },
[M_LOCATION.name]: {
uri: geoUri,
description: undefined,
description: undefined as string,
},
};
expect(mockClient.sendEvent).toHaveBeenCalledWith(
@ -280,7 +280,7 @@ describe("ForwardDialog", () => {
[M_ASSET.name]: { type: LocationAssetType.Pin },
[M_LOCATION.name]: {
uri: geoUri,
description: undefined,
description: undefined as string,
},
};
expect(mockClient.sendEvent).toHaveBeenCalledWith(
@ -301,7 +301,7 @@ describe("ForwardDialog", () => {
[M_ASSET.name]: { type: LocationAssetType.Pin },
[M_LOCATION.name]: {
uri: geoUri,
description: undefined,
description: undefined as string,
},
geo_uri: geoUri,
[M_TIMESTAMP.name]: timestamp,

View file

@ -16,9 +16,8 @@ limitations under the License.
*/
import React from "react";
import { act } from "react-dom/test-utils";
// eslint-disable-next-line deprecate/import
import { mount, ReactWrapper } from "enzyme";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import InteractiveAuthDialog from "../../../../src/components/views/dialogs/InteractiveAuthDialog";
import { flushPromises, getMockClientWithEventEmitter, unmockClientPeg } from "../../../test-utils";
@ -33,7 +32,10 @@ describe("InteractiveAuthDialog", function () {
makeRequest: jest.fn().mockResolvedValue(undefined),
onFinished: jest.fn(),
};
const getComponent = (props = {}) => mount(<InteractiveAuthDialog {...defaultProps} {...props} />);
const renderComponent = (props = {}) => render(<InteractiveAuthDialog {...defaultProps} {...props} />);
const getPasswordField = () => screen.getByLabelText("Password");
const getSubmitButton = () => screen.getByRole("button", { name: "Continue" });
beforeEach(function () {
jest.clearAllMocks();
@ -44,8 +46,6 @@ describe("InteractiveAuthDialog", function () {
unmockClientPeg();
});
const getSubmitButton = (wrapper: ReactWrapper) => wrapper.find('[type="submit"]').at(0);
it("Should successfully complete a password flow", async () => {
const onFinished = jest.fn();
const makeRequest = jest.fn().mockResolvedValue({ a: 1 });
@ -56,31 +56,24 @@ describe("InteractiveAuthDialog", function () {
flows: [{ stages: ["m.login.password"] }],
};
const wrapper = getComponent({ makeRequest, onFinished, authData });
renderComponent({ makeRequest, onFinished, authData });
const passwordNode = wrapper.find('input[type="password"]').at(0);
const submitNode = getSubmitButton(wrapper);
const passwordField = getPasswordField();
const submitButton = getSubmitButton();
const formNode = wrapper.find("form").at(0);
expect(passwordNode).toBeTruthy();
expect(submitNode).toBeTruthy();
expect(passwordField).toBeTruthy();
expect(submitButton).toBeTruthy();
// submit should be disabled
expect(submitNode.props().disabled).toBe(true);
expect(submitButton).toBeDisabled();
// put something in the password box
act(() => {
passwordNode.simulate("change", { target: { value: "s3kr3t" } });
wrapper.setProps({});
});
await userEvent.type(passwordField, "s3kr3t");
expect(wrapper.find('input[type="password"]').at(0).props().value).toEqual("s3kr3t");
expect(getSubmitButton(wrapper).props().disabled).toBe(false);
expect(submitButton).not.toBeDisabled();
// hit enter; that should trigger a request
act(() => {
formNode.simulate("submit");
});
await userEvent.click(submitButton);
// wait for auth request to resolve
await flushPromises();

View file

@ -76,9 +76,9 @@ describe("InviteDialog", () => {
});
it("should label with space name", () => {
mockClient.getRoom(roomId).isSpaceRoom = jest.fn().mockReturnValue(true);
mockClient.getRoom(roomId).getType = jest.fn().mockReturnValue(RoomType.Space);
mockClient.getRoom(roomId).name = "Space";
mockClient.getRoom(roomId)!.isSpaceRoom = jest.fn().mockReturnValue(true);
mockClient.getRoom(roomId)!.getType = jest.fn().mockReturnValue(RoomType.Space);
mockClient.getRoom(roomId)!.name = "Space";
render(<InviteDialog kind={KIND_INVITE} roomId={roomId} onFinished={jest.fn()} />);
expect(screen.queryByText("Invite to Space")).toBeTruthy();

View file

@ -73,8 +73,9 @@ describe("<UserSettingsDialog />", () => {
mockSdkConfig.get.mockReturnValue({ brand: "Test" });
});
const getActiveTabLabel = (container) => container.querySelector(".mx_TabbedView_tabLabel_active").textContent;
const getActiveTabHeading = (container) => container.querySelector(".mx_SettingsTab_heading").textContent;
const getActiveTabLabel = (container: Element) =>
container.querySelector(".mx_TabbedView_tabLabel_active").textContent;
const getActiveTabHeading = (container: Element) => container.querySelector(".mx_SettingsTab_heading").textContent;
it("should render general settings tab when no initialTabId", () => {
const { container } = render(getComponent());

View file

@ -15,15 +15,17 @@ limitations under the License.
*/
import React from "react";
import { render } from "@testing-library/react";
import { MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
import { fireEvent, render } from "@testing-library/react";
import { Room } from "matrix-js-sdk/src/matrix";
import { PollHistoryDialog } from "../../../../../src/components/views/dialogs/polls/PollHistoryDialog";
import {
getMockClientWithEventEmitter,
makePollEndEvent,
makePollStartEvent,
mockClientMethodsUser,
mockIntlDateTimeFormat,
setupRoomWithPollEvents,
unmockIntlDateTimeFormat,
} from "../../../../test-utils";
@ -33,6 +35,8 @@ describe("<PollHistoryDialog />", () => {
const mockClient = getMockClientWithEventEmitter({
...mockClientMethodsUser(userId),
getRoom: jest.fn(),
relations: jest.fn(),
decryptEventIfNeeded: jest.fn(),
});
const room = new Room(roomId, mockClient, userId);
@ -49,6 +53,7 @@ describe("<PollHistoryDialog />", () => {
beforeEach(() => {
mockClient.getRoom.mockReturnValue(room);
mockClient.relations.mockResolvedValue({ events: [] });
const timeline = room.getLiveTimeline();
jest.spyOn(timeline, "getEvents").mockReturnValue([]);
});
@ -63,24 +68,58 @@ describe("<PollHistoryDialog />", () => {
expect(() => getComponent()).toThrow("Cannot find room");
});
it("renders a no polls message when there are no polls in the timeline", () => {
it("renders a no polls message when there are no active polls in the timeline", () => {
const { getByText } = getComponent();
expect(getByText("There are no polls in this room")).toBeTruthy();
expect(getByText("There are no active polls in this room")).toBeTruthy();
});
it("renders a list of polls when there are polls in the timeline", async () => {
it("renders a no past polls message when there are no past polls in the timeline", () => {
const { getByText } = getComponent();
fireEvent.click(getByText("Past polls"));
expect(getByText("There are no past polls in this room")).toBeTruthy();
});
it("renders a list of active polls when there are polls in the timeline", async () => {
const timestamp = 1675300825090;
const pollStart1 = makePollStartEvent("Question?", userId, undefined, { ts: timestamp, id: "$1" });
const pollStart2 = makePollStartEvent("Where?", userId, undefined, { ts: timestamp + 10000, id: "$2" });
const pollStart3 = makePollStartEvent("What?", userId, undefined, { ts: timestamp + 70000, id: "$3" });
const pollEnd3 = makePollEndEvent(pollStart3.getId()!, roomId, userId, timestamp + 1);
await setupRoomWithPollEvents([pollStart2, pollStart3, pollStart1], [], [pollEnd3], mockClient, room);
const { container, queryByText, getByTestId } = getComponent();
expect(getByTestId("filter-tab-PollHistoryDialog_filter-ACTIVE").firstElementChild).toBeChecked();
expect(container).toMatchSnapshot();
// this poll is ended, and default filter is ACTIVE
expect(queryByText("What?")).not.toBeInTheDocument();
});
it("filters ended polls", async () => {
const pollStart1 = makePollStartEvent("Question?", userId, undefined, { ts: 1675300825090, id: "$1" });
const pollStart2 = makePollStartEvent("Where?", userId, undefined, { ts: 1675300725090, id: "$2" });
const pollStart3 = makePollStartEvent("What?", userId, undefined, { ts: 1675200725090, id: "$3" });
const message = new MatrixEvent({
type: "m.room.message",
content: {},
});
const timeline = room.getLiveTimeline();
jest.spyOn(timeline, "getEvents").mockReturnValue([pollStart1, pollStart2, pollStart3, message]);
const { container } = getComponent();
const pollEnd3 = makePollEndEvent(pollStart3.getId()!, roomId, userId, 1675200725090 + 1);
await setupRoomWithPollEvents([pollStart1, pollStart2, pollStart3], [], [pollEnd3], mockClient, room);
expect(container).toMatchSnapshot();
const { getByText, queryByText, getByTestId } = getComponent();
expect(getByText("Question?")).toBeInTheDocument();
expect(getByText("Where?")).toBeInTheDocument();
// this poll is ended, and default filter is ACTIVE
expect(queryByText("What?")).not.toBeInTheDocument();
fireEvent.click(getByText("Past polls"));
expect(getByTestId("filter-tab-PollHistoryDialog_filter-ENDED").firstElementChild).toBeChecked();
// active polls no longer shown
expect(queryByText("Question?")).not.toBeInTheDocument();
expect(queryByText("Where?")).not.toBeInTheDocument();
// this poll is ended
expect(getByText("What?")).toBeInTheDocument();
});
});

View file

@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<PollHistoryDialog /> renders a list of polls when there are polls in the timeline 1`] = `
exports[`<PollHistoryDialog /> renders a list of active polls when there are polls in the timeline 1`] = `
<div>
<div
data-focus-guard="true"
@ -35,25 +35,38 @@ exports[`<PollHistoryDialog /> renders a list of polls when there are polls in t
<div
class="mx_PollHistoryList"
>
<fieldset
class="mx_FilterTabGroup"
>
<label
data-testid="filter-tab-PollHistoryDialog_filter-ACTIVE"
>
<input
checked=""
name="PollHistoryDialog_filter"
type="radio"
value="ACTIVE"
/>
<span>
Active polls
</span>
</label>
<label
data-testid="filter-tab-PollHistoryDialog_filter-ENDED"
>
<input
name="PollHistoryDialog_filter"
type="radio"
value="ENDED"
/>
<span>
Past polls
</span>
</label>
</fieldset>
<ol
class="mx_PollHistoryList_list"
>
<li
class="mx_PollListItem"
data-testid="pollListItem-$1"
>
<span>
02/02/23
</span>
<div
class="mx_PollListItem_icon"
/>
<span
class="mx_PollListItem_question"
>
Question?
</span>
</li>
<li
class="mx_PollListItem"
data-testid="pollListItem-$2"
@ -72,10 +85,10 @@ exports[`<PollHistoryDialog /> renders a list of polls when there are polls in t
</li>
<li
class="mx_PollListItem"
data-testid="pollListItem-$3"
data-testid="pollListItem-$1"
>
<span>
31/01/23
02/02/23
</span>
<div
class="mx_PollListItem_icon"
@ -83,7 +96,7 @@ exports[`<PollHistoryDialog /> renders a list of polls when there are polls in t
<span
class="mx_PollListItem_question"
>
What?
Question?
</span>
</li>
</ol>

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import React, { ComponentProps } from "react";
// eslint-disable-next-line deprecate/import
import { mount, ReactWrapper } from "enzyme";
import { MatrixEvent, RoomMember } from "matrix-js-sdk/src/matrix";
@ -60,7 +60,7 @@ describe("EventListSummary", function () {
*/
interface MembershipEventParams {
senderId?: string;
userId: string;
userId?: string;
membership: string;
prevMembership?: string;
}
@ -100,11 +100,11 @@ describe("EventListSummary", function () {
// Generate the same sequence of `events` for `n` users, where each user ID
// is created by replacing the first "$" in userIdTemplate with `i` for
// `i = 0 .. n`.
const generateEventsForUsers = (userIdTemplate, n, events) => {
const generateEventsForUsers = (userIdTemplate: string, n: number, events: MembershipEventParams[]) => {
let eventsForUsers: MatrixEvent[] = [];
let userId = "";
for (let i = 0; i < n; i++) {
userId = userIdTemplate.replace("$", i);
userId = userIdTemplate.replace("$", String(i));
events.forEach((e) => {
e.userId = userId;
});
@ -117,7 +117,7 @@ describe("EventListSummary", function () {
...mockClientMethodsUser(),
});
const defaultProps = {
const defaultProps: ComponentProps<typeof EventListSummary> = {
layout: Layout.Bubble,
events: [],
children: [],

View file

@ -0,0 +1,54 @@
/*
Copyright 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 React from "react";
import { fireEvent, render } from "@testing-library/react";
import { FilterTabGroup } from "../../../../src/components/views/elements/FilterTabGroup";
describe("<FilterTabGroup />", () => {
enum TestOption {
Apple = "Apple",
Banana = "Banana",
Orange = "Orange",
}
const defaultProps = {
"name": "test",
"value": TestOption.Apple,
"onFilterChange": jest.fn(),
"tabs": [
{ id: TestOption.Apple, label: `Label for ${TestOption.Apple}` },
{ id: TestOption.Banana, label: `Label for ${TestOption.Banana}` },
{ id: TestOption.Orange, label: `Label for ${TestOption.Orange}` },
],
"data-testid": "test",
};
const getComponent = (props = {}) => <FilterTabGroup<TestOption> {...defaultProps} {...props} />;
it("renders options", () => {
const { container } = render(getComponent());
expect(container).toMatchSnapshot();
});
it("calls onChange handler on selection", () => {
const onFilterChange = jest.fn();
const { getByText } = render(getComponent({ onFilterChange }));
fireEvent.click(getByText("Label for Banana"));
expect(onFilterChange).toHaveBeenCalledWith(TestOption.Banana);
});
});

View file

@ -15,7 +15,7 @@ limitations under the License.
*/
import React from "react";
import { fireEvent, render } from "@testing-library/react";
import { fireEvent, render, RenderResult } from "@testing-library/react";
import StyledRadioGroup from "../../../../src/components/views/elements/StyledRadioGroup";
@ -44,8 +44,10 @@ describe("<StyledRadioGroup />", () => {
};
const getComponent = (props = {}) => render(<StyledRadioGroup {...defaultProps} {...props} />);
const getInputByValue = (component, value) => component.container.querySelector(`input[value="${value}"]`);
const getCheckedInput = (component) => component.container.querySelector("input[checked]");
const getInputByValue = (component: RenderResult, value: string) =>
component.container.querySelector<HTMLInputElement>(`input[value="${value}"]`);
const getCheckedInput = (component: RenderResult) =>
component.container.querySelector<HTMLInputElement>("input[checked]");
it("renders radios correctly when no value is provided", () => {
const component = getComponent();

View file

@ -61,7 +61,7 @@ describe("<TooltipTarget />", () => {
});
const alignmentKeys = Object.keys(Alignment).filter((o: any) => isNaN(o));
it.each(alignmentKeys)("displays %s aligned tooltip on mouseover", async (alignment) => {
it.each(alignmentKeys)("displays %s aligned tooltip on mouseover", async (alignment: any) => {
const wrapper = getComponent({ alignment: Alignment[alignment] });
act(() => {
Simulate.mouseOver(wrapper);

View file

@ -0,0 +1,48 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<FilterTabGroup /> renders options 1`] = `
<div>
<fieldset
class="mx_FilterTabGroup"
data-testid="test"
>
<label
data-testid="filter-tab-test-Apple"
>
<input
checked=""
name="test"
type="radio"
value="Apple"
/>
<span>
Label for Apple
</span>
</label>
<label
data-testid="filter-tab-test-Banana"
>
<input
name="test"
type="radio"
value="Banana"
/>
<span>
Label for Banana
</span>
</label>
<label
data-testid="filter-tab-test-Orange"
>
<input
name="test"
type="radio"
value="Orange"
/>
<span>
Label for Orange
</span>
</label>
</fieldset>
</div>
`;

View file

@ -16,7 +16,7 @@ limitations under the License.
import React from "react";
// eslint-disable-next-line deprecate/import
import { mount } from "enzyme";
import { mount, ReactWrapper } from "enzyme";
import { act } from "react-dom/test-utils";
import LiveDurationDropdown, {
@ -33,9 +33,9 @@ describe("<LiveDurationDropdown />", () => {
};
const getComponent = (props = {}) => mount(<LiveDurationDropdown {...defaultProps} {...props} />);
const getOption = (wrapper, timeout) => findById(wrapper, `live-duration__${timeout}`).at(0);
const getSelectedOption = (wrapper) => findById(wrapper, "live-duration_value");
const openDropdown = (wrapper) =>
const getOption = (wrapper: ReactWrapper, timeout: number) => findById(wrapper, `live-duration__${timeout}`).at(0);
const getSelectedOption = (wrapper: ReactWrapper) => findById(wrapper, "live-duration_value");
const openDropdown = (wrapper: ReactWrapper) =>
act(() => {
wrapper.find('[role="button"]').at(0).simulate("click");
wrapper.setProps({});

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from "react";
import * as maplibregl from "maplibre-gl";
// eslint-disable-next-line deprecate/import
import { mount } from "enzyme";
import { mount, ReactWrapper } from "enzyme";
import { act } from "react-dom/test-utils";
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { MatrixClient } from "matrix-js-sdk/src/client";
@ -239,11 +239,12 @@ describe("LocationPicker", () => {
const shareType = LocationShareType.Live;
testUserLocationShareTypes(shareType);
const getOption = (wrapper, timeout) => findById(wrapper, `live-duration__${timeout}`).at(0);
const getDropdown = (wrapper) => findByTestId(wrapper, "live-duration-dropdown");
const getSelectedOption = (wrapper) => findById(wrapper, "live-duration_value");
const getOption = (wrapper: ReactWrapper, timeout: number) =>
findById(wrapper, `live-duration__${timeout}`).at(0);
const getDropdown = (wrapper: ReactWrapper) => findByTestId(wrapper, "live-duration-dropdown");
const getSelectedOption = (wrapper: ReactWrapper) => findById(wrapper, "live-duration_value");
const openDropdown = (wrapper) =>
const openDropdown = (wrapper: ReactWrapper) =>
act(() => {
const dropdown = getDropdown(wrapper);
dropdown.find('[role="button"]').at(0).simulate("click");

View file

@ -52,7 +52,6 @@ describe("<LocationViewDialog />", () => {
// @ts-ignore cheat assignment to property
selfShareEvent.sender = member;
const component = getComponent({ mxEvent: selfShareEvent });
// @ts-ignore fix when moving to rtl
expect(component.find("SmartMarker").props()["roomMember"]).toEqual(member);
expect(component.find("SmartMarker").prop("roomMember")).toEqual(member);
});
});

View file

@ -40,7 +40,7 @@ describe("DateSeparator", () => {
};
const RealDate = global.Date;
class MockDate extends Date {
constructor(date) {
constructor(date: string | number | Date) {
super(date || now);
}
}

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import React, { ComponentProps } from "react";
// eslint-disable-next-line deprecate/import
import { mount } from "enzyme";
import { act } from "react-dom/test-utils";
@ -63,7 +63,7 @@ describe("<MBeaconBody />", () => {
const defaultEvent = makeBeaconInfoEvent(aliceId, roomId, { isLive: true }, "$alice-room1-1");
const defaultProps = {
const defaultProps: ComponentProps<typeof MBeaconBody> = {
mxEvent: defaultEvent,
highlights: [],
highlightLink: "",
@ -80,7 +80,10 @@ describe("<MBeaconBody />", () => {
wrappingComponentProps: { value: mockClient },
});
const modalSpy = jest.spyOn(Modal, "createDialog").mockReturnValue(undefined);
const modalSpy = jest.spyOn(Modal, "createDialog").mockReturnValue({
finished: Promise.resolve([true]),
close: () => {},
});
beforeEach(() => {
jest.clearAllMocks();
@ -169,7 +172,7 @@ describe("<MBeaconBody />", () => {
const room = makeRoomWithStateEvents([aliceBeaconInfo1], { roomId, mockClient });
const component = getComponent({ mxEvent: aliceBeaconInfo1 });
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(aliceBeaconInfo1));
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(aliceBeaconInfo1))!;
// update alice's beacon with a new edition
// beacon instance emits
act(() => {
@ -190,7 +193,7 @@ describe("<MBeaconBody />", () => {
const aliceBeaconInfo = makeBeaconInfoEvent(aliceId, roomId, { isLive: true }, "$alice-room1-1");
const room = makeRoomWithStateEvents([aliceBeaconInfo], { roomId, mockClient });
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(aliceBeaconInfo));
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(aliceBeaconInfo))!;
const component = getComponent({ mxEvent: aliceBeaconInfo });
act(() => {
@ -240,7 +243,7 @@ describe("<MBeaconBody />", () => {
it("renders a live beacon with a location correctly", () => {
const room = makeRoomWithStateEvents([aliceBeaconInfo], { roomId, mockClient });
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(aliceBeaconInfo));
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(aliceBeaconInfo))!;
beaconInstance.addLocations([location1]);
const component = getComponent({ mxEvent: aliceBeaconInfo });
@ -249,7 +252,7 @@ describe("<MBeaconBody />", () => {
it("opens maximised map view on click when beacon has a live location", () => {
const room = makeRoomWithStateEvents([aliceBeaconInfo], { roomId, mockClient });
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(aliceBeaconInfo));
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(aliceBeaconInfo))!;
beaconInstance.addLocations([location1]);
const component = getComponent({ mxEvent: aliceBeaconInfo });
@ -274,7 +277,7 @@ describe("<MBeaconBody />", () => {
it("renders a live beacon with a location correctly", () => {
const room = makeRoomWithStateEvents([aliceBeaconInfo], { roomId, mockClient });
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(aliceBeaconInfo));
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(aliceBeaconInfo))!;
beaconInstance.addLocations([location1]);
const component = getComponent({ mxEvent: aliceBeaconInfo });
@ -283,7 +286,7 @@ describe("<MBeaconBody />", () => {
it("opens maximised map view on click when beacon has a live location", () => {
const room = makeRoomWithStateEvents([aliceBeaconInfo], { roomId, mockClient });
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(aliceBeaconInfo));
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(aliceBeaconInfo))!;
beaconInstance.addLocations([location1]);
const component = getComponent({ mxEvent: aliceBeaconInfo });
@ -299,7 +302,7 @@ describe("<MBeaconBody />", () => {
const room = makeRoomWithStateEvents([aliceBeaconInfo], { roomId, mockClient });
const component = getComponent({ mxEvent: aliceBeaconInfo });
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(aliceBeaconInfo));
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(aliceBeaconInfo))!;
act(() => {
beaconInstance.addLocations([location1]);
component.setProps({});
@ -343,9 +346,9 @@ describe("<MBeaconBody />", () => {
const redactionEvent = new MatrixEvent({ type: EventType.RoomRedaction, content: { reason: "test reason" } });
const setupRoomWithBeacon = (beaconInfoEvent, locationEvents: MatrixEvent[] = []) => {
const setupRoomWithBeacon = (beaconInfoEvent: MatrixEvent, locationEvents: MatrixEvent[] = []) => {
const room = makeRoomWithStateEvents([beaconInfoEvent], { roomId, mockClient });
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(beaconInfoEvent));
const beaconInstance = room.currentState.beacons.get(getBeaconInfoIdentifier(beaconInfoEvent))!;
beaconInstance.addLocations(locationEvents);
};
const mockGetRelationsForEvent = (locationEvents: MatrixEvent[] = []) => {

View file

@ -69,7 +69,7 @@ describe("<MImageBody/>", () => {
const props = {
onHeightChanged: jest.fn(),
onMessageAllowed: jest.fn(),
permalinkCreator: new RoomPermalinkCreator(new Room(encryptedMediaEvent.getRoomId(), cli, cli.getUserId())),
permalinkCreator: new RoomPermalinkCreator(new Room(encryptedMediaEvent.getRoomId()!, cli, cli.getUserId()!)),
};
it("should show error when encrypted media cannot be downloaded", async () => {

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import React, { ComponentProps } from "react";
// eslint-disable-next-line deprecate/import
import { mount } from "enzyme";
import { LocationAssetType } from "matrix-js-sdk/src/@types/location";
@ -46,7 +46,7 @@ describe("MLocationBody", () => {
isGuest: jest.fn().mockReturnValue(false),
});
const defaultEvent = makeLocationEvent("geo:51.5076,-0.1276", LocationAssetType.Pin);
const defaultProps = {
const defaultProps: ComponentProps<typeof MLocationBody> = {
mxEvent: defaultEvent,
highlights: [],
highlightLink: "",
@ -79,7 +79,7 @@ describe("MLocationBody", () => {
});
describe("with error", () => {
let sdkConfigSpy;
let sdkConfigSpy: jest.SpyInstance<any>;
beforeEach(() => {
// eat expected errors to keep console clean
@ -171,7 +171,7 @@ describe("MLocationBody", () => {
const component = getComponent({ mxEvent: selfShareEvent });
// render self locations with user avatars
expect(component.find("SmartMarker").at(0).props()["roomMember"]).toEqual(member);
expect(component.find("SmartMarker").at(0).prop("roomMember")).toEqual(member);
});
});
});

View file

@ -42,7 +42,7 @@ import MPollBody from "../../../../src/components/views/messages/MPollBody";
import { RoomPermalinkCreator } from "../../../../src/utils/permalinks/Permalinks";
import { MediaEventHelper } from "../../../../src/utils/MediaEventHelper";
const CHECKED = "mx_MPollBody_option_checked";
const CHECKED = "mx_PollOption_checked";
const userId = "@me:example.com";
const mockClient = getMockClientWithEventEmitter({
@ -227,7 +227,7 @@ describe("MPollBody", () => {
content: newPollStart(undefined, undefined, true),
});
const props = getMPollBodyPropsFromEvent(mxEvent);
const room = await setupRoomWithPollEvents(mxEvent, votes, [], mockClient);
const room = await setupRoomWithPollEvents([mxEvent], votes, [], mockClient);
const renderResult = renderMPollBodyWithWrapper(props);
// wait for /relations promise to resolve
await flushPromises();
@ -255,7 +255,7 @@ describe("MPollBody", () => {
content: newPollStart(undefined, undefined, true),
});
const props = getMPollBodyPropsFromEvent(mxEvent);
const room = await setupRoomWithPollEvents(mxEvent, votes, [], mockClient);
const room = await setupRoomWithPollEvents([mxEvent], votes, [], mockClient);
const renderResult = renderMPollBodyWithWrapper(props);
// wait for /relations promise to resolve
await flushPromises();
@ -383,7 +383,7 @@ describe("MPollBody", () => {
const votes: MatrixEvent[] = [];
const ends: MatrixEvent[] = [];
const { container } = await newMPollBody(votes, ends, answers);
expect(container.querySelectorAll(".mx_MPollBody_option").length).toBe(20);
expect(container.querySelectorAll(".mx_PollOption").length).toBe(20);
});
it("hides scores if I voted but the poll is undisclosed", async () => {
@ -429,7 +429,7 @@ describe("MPollBody", () => {
];
const ends = [newPollEndEvent("@me:example.com", 12)];
const renderResult = await newMPollBody(votes, ends, undefined, false);
expect(endedVotesCount(renderResult, "pizza")).toBe("3 votes");
expect(endedVotesCount(renderResult, "pizza")).toBe('<div class="mx_PollOption_winnerIcon"></div>3 votes');
expect(endedVotesCount(renderResult, "poutine")).toBe("1 vote");
expect(endedVotesCount(renderResult, "italian")).toBe("0 votes");
expect(endedVotesCount(renderResult, "wings")).toBe("1 vote");
@ -531,9 +531,9 @@ describe("MPollBody", () => {
const ends = [newPollEndEvent("@me:example.com", 25)];
const renderResult = await newMPollBody(votes, ends);
expect(endedVotesCount(renderResult, "pizza")).toBe("0 votes");
expect(endedVotesCount(renderResult, "poutine")).toBe("1 vote");
expect(endedVotesCount(renderResult, "poutine")).toBe('<div class="mx_PollOption_winnerIcon"></div>1 vote');
expect(endedVotesCount(renderResult, "italian")).toBe("0 votes");
expect(endedVotesCount(renderResult, "wings")).toBe("1 vote");
expect(endedVotesCount(renderResult, "wings")).toBe('<div class="mx_PollOption_winnerIcon"></div>1 vote');
expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Final result based on 2 votes");
});
@ -542,7 +542,7 @@ describe("MPollBody", () => {
const ends = [newPollEndEvent("@me:example.com", 25)];
const renderResult = await newMPollBody(votes, ends);
expect(endedVotesCount(renderResult, "pizza")).toBe("0 votes");
expect(endedVotesCount(renderResult, "poutine")).toBe("1 vote");
expect(endedVotesCount(renderResult, "poutine")).toBe('<div class="mx_PollOption_winnerIcon"></div>1 vote');
expect(endedVotesCount(renderResult, "italian")).toBe("0 votes");
expect(endedVotesCount(renderResult, "wings")).toBe("0 votes");
expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Final result based on 1 vote");
@ -564,7 +564,7 @@ describe("MPollBody", () => {
expect(endedVotesCount(renderResult, "pizza")).toBe("2 votes");
expect(endedVotesCount(renderResult, "poutine")).toBe("0 votes");
expect(endedVotesCount(renderResult, "italian")).toBe("0 votes");
expect(endedVotesCount(renderResult, "wings")).toBe("3 votes");
expect(endedVotesCount(renderResult, "wings")).toBe('<div class="mx_PollOption_winnerIcon"></div>3 votes');
expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Final result based on 5 votes");
});
@ -584,7 +584,7 @@ describe("MPollBody", () => {
expect(endedVotesCount(renderResult, "pizza")).toBe("2 votes");
expect(endedVotesCount(renderResult, "poutine")).toBe("0 votes");
expect(endedVotesCount(renderResult, "italian")).toBe("0 votes");
expect(endedVotesCount(renderResult, "wings")).toBe("3 votes");
expect(endedVotesCount(renderResult, "wings")).toBe('<div class="mx_PollOption_winnerIcon"></div>3 votes');
expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Final result based on 5 votes");
});
@ -607,7 +607,7 @@ describe("MPollBody", () => {
expect(endedVotesCount(renderResult, "pizza")).toBe("2 votes");
expect(endedVotesCount(renderResult, "poutine")).toBe("0 votes");
expect(endedVotesCount(renderResult, "italian")).toBe("0 votes");
expect(endedVotesCount(renderResult, "wings")).toBe("3 votes");
expect(endedVotesCount(renderResult, "wings")).toBe('<div class="mx_PollOption_winnerIcon"></div>3 votes');
expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Final result based on 5 votes");
});
@ -634,7 +634,7 @@ describe("MPollBody", () => {
expect(endedVotesCount(renderResult, "pizza")).toBe("2 votes");
expect(endedVotesCount(renderResult, "poutine")).toBe("0 votes");
expect(endedVotesCount(renderResult, "italian")).toBe("0 votes");
expect(endedVotesCount(renderResult, "wings")).toBe("3 votes");
expect(endedVotesCount(renderResult, "wings")).toBe('<div class="mx_PollOption_winnerIcon"></div>3 votes');
expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Final result based on 5 votes");
});
@ -653,8 +653,8 @@ describe("MPollBody", () => {
expect(endedVoteChecked(renderResult, "pizza")).toBe(false);
// Double-check by looking for the endedOptionWinner class
expect(endedVoteDiv(renderResult, "wings").className.includes("mx_MPollBody_endedOptionWinner")).toBe(true);
expect(endedVoteDiv(renderResult, "pizza").className.includes("mx_MPollBody_endedOptionWinner")).toBe(false);
expect(endedVoteDiv(renderResult, "wings").className.includes("mx_PollOption_endedOptionWinner")).toBe(true);
expect(endedVoteDiv(renderResult, "pizza").className.includes("mx_PollOption_endedOptionWinner")).toBe(false);
});
it("highlights multiple winning votes", async () => {
@ -670,13 +670,13 @@ describe("MPollBody", () => {
expect(endedVoteChecked(renderResult, "wings")).toBe(true);
expect(endedVoteChecked(renderResult, "poutine")).toBe(true);
expect(endedVoteChecked(renderResult, "italian")).toBe(false);
expect(renderResult.container.getElementsByClassName("mx_MPollBody_option_checked")).toHaveLength(3);
expect(renderResult.container.getElementsByClassName(CHECKED)).toHaveLength(3);
});
it("highlights nothing if poll has no votes", async () => {
const ends = [newPollEndEvent("@me:example.com", 25)];
const renderResult = await newMPollBody([], ends);
expect(renderResult.container.getElementsByClassName("mx_MPollBody_option_checked")).toHaveLength(0);
expect(renderResult.container.getElementsByClassName(CHECKED)).toHaveLength(0);
});
it("says poll is not ended if there is no end event", async () => {
@ -700,7 +700,7 @@ describe("MPollBody", () => {
});
const ends = [newPollEndEvent("@me:example.com", 25)];
await setupRoomWithPollEvents(pollEvent, [], ends, mockClient);
await setupRoomWithPollEvents([pollEvent], [], ends, mockClient);
const poll = mockClient.getRoom(pollEvent.getRoomId()!)!.polls.get(pollEvent.getId()!)!;
// start fetching, dont await
poll.getResponses();
@ -745,7 +745,7 @@ describe("MPollBody", () => {
expect(inputs[0].getAttribute("value")).toEqual("n1");
expect(inputs[1].getAttribute("value")).toEqual("n2");
expect(inputs[2].getAttribute("value")).toEqual("n3");
const options = container.querySelectorAll(".mx_MPollBody_optionText");
const options = container.querySelectorAll(".mx_PollOption_optionText");
expect(options).toHaveLength(3);
expect(options[0].innerHTML).toEqual("new answer 1");
expect(options[1].innerHTML).toEqual("new answer 2");
@ -920,7 +920,7 @@ async function newMPollBodyFromEvent(
): Promise<RenderResult> {
const props = getMPollBodyPropsFromEvent(mxEvent);
await setupRoomWithPollEvents(mxEvent, relationEvents, endEvents, mockClient);
await setupRoomWithPollEvents([mxEvent], relationEvents, endEvents, mockClient);
return renderMPollBodyWithWrapper(props);
}
@ -934,11 +934,11 @@ function voteButton({ getByTestId }: RenderResult, value: string): Element {
}
function votesCount({ getByTestId }: RenderResult, value: string): string {
return getByTestId(`pollOption-${value}`).querySelector(".mx_MPollBody_optionVoteCount")!.innerHTML;
return getByTestId(`pollOption-${value}`).querySelector(".mx_PollOption_optionVoteCount")!.innerHTML;
}
function endedVoteChecked({ getByTestId }: RenderResult, value: string): boolean {
return getByTestId(`pollOption-${value}`).className.includes("mx_MPollBody_option_checked");
return getByTestId(`pollOption-${value}`).className.includes(CHECKED);
}
function endedVoteDiv({ getByTestId }: RenderResult, value: string): Element {
@ -1036,7 +1036,7 @@ async function runIsPollEnded(ends: MatrixEvent[]) {
content: newPollStart(),
});
await setupRoomWithPollEvents(pollEvent, [], ends, mockClient);
await setupRoomWithPollEvents([pollEvent], [], ends, mockClient);
return isPollEnded(pollEvent, mockClient);
}

View file

@ -50,7 +50,7 @@ describe("<MPollEndBody />", () => {
const setupRoomWithEventsTimeline = async (pollEnd: MatrixEvent, pollStart?: MatrixEvent): Promise<Room> => {
if (pollStart) {
await setupRoomWithPollEvents(pollStart, [], [pollEnd], mockClient);
await setupRoomWithPollEvents([pollStart], [], [pollEnd], mockClient);
}
const room = mockClient.getRoom(roomId) || new Room(roomId, mockClient, userId);

View file

@ -14,8 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
import React, { ComponentProps } from "react";
import { IContent, MatrixEvent } from "matrix-js-sdk/src/matrix";
import { render, RenderResult } from "@testing-library/react";
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
@ -43,7 +43,7 @@ describe("MVideoBody", () => {
});
function makeMVideoBody(w: number, h: number): RenderResult {
const content = {
const content: IContent = {
info: {
"w": w,
"h": h,
@ -66,7 +66,7 @@ function makeMVideoBody(w: number, h: number): RenderResult {
content,
});
const defaultProps = {
const defaultProps: ComponentProps<typeof MVideoBody> = {
mxEvent: event,
highlights: [],
highlightLink: "",

View file

@ -76,7 +76,7 @@ describe("<MessageActionBar />", () => {
});
const localStorageMock = (() => {
let store = {};
let store: Record<string, any> = {};
return {
getItem: jest.fn().mockImplementation((key) => store[key] ?? null),
setItem: jest.fn().mockImplementation((key, value) => {

View file

@ -15,7 +15,7 @@ limitations under the License.
*/
import React from "react";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import { MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix";
import { MockedObject } from "jest-mock";
import { render } from "@testing-library/react";
@ -38,9 +38,9 @@ describe("<TextualBody />", () => {
beforeEach(() => {
defaultMatrixClient = getMockClientWithEventEmitter({
getRoom: () => defaultRoom,
getAccountData: () => undefined,
getAccountData: (): MatrixEvent | undefined => undefined,
isGuest: () => false,
mxcUrlToHttp: (s) => s,
mxcUrlToHttp: (s: string) => s,
});
});
@ -56,7 +56,7 @@ describe("<TextualBody />", () => {
});
const defaultProps = {
mxEvent: defaultEvent,
highlights: [],
highlights: [] as string[],
highlightLink: "",
onMessageAllowed: jest.fn(),
onHeightChanged: jest.fn(),
@ -158,17 +158,17 @@ describe("<TextualBody />", () => {
});
describe("renders formatted m.text correctly", () => {
let matrixClient;
let matrixClient: MatrixClient;
beforeEach(() => {
matrixClient = getMockClientWithEventEmitter({
getRoom: () => mkStubRoom("room_id", "room name", undefined),
getAccountData: () => undefined,
getAccountData: (): MatrixEvent | undefined => undefined,
getUserId: () => "@me:my_server",
getHomeserverUrl: () => "https://my_server/",
on: () => undefined,
removeListener: () => undefined,
on: (): void => undefined,
removeListener: (): void => undefined,
isGuest: () => false,
mxcUrlToHttp: (s) => s,
mxcUrlToHttp: (s: string) => s,
});
DMRoomMap.makeShared();
});
@ -375,10 +375,10 @@ describe("<TextualBody />", () => {
const matrixClient = getMockClientWithEventEmitter({
getRoom: () => mkStubRoom("room_id", "room name", undefined),
getAccountData: () => undefined,
getUrlPreview: (url) => new Promise(() => {}),
getAccountData: (): MatrixClient | undefined => undefined,
getUrlPreview: (url: string) => new Promise(() => {}),
isGuest: () => false,
mxcUrlToHttp: (s) => s,
mxcUrlToHttp: (s: string) => s,
});
DMRoomMap.makeShared();

View file

@ -22,65 +22,65 @@ exports[`<MPollEndBody /> when poll start event exists in current timeline rende
class="mx_MPollBody_allOptions"
>
<div
class="mx_MPollBody_option mx_MPollBody_option_ended"
class="mx_PollOption mx_PollOption_ended"
data-testid="pollOption-socks"
>
<div
class="mx_MPollBody_endedOption"
class="mx_PollOption_endedOption"
data-value="socks"
>
<div
class="mx_MPollBody_optionDescription"
class="mx_PollOption_content"
>
<div
class="mx_MPollBody_optionText"
class="mx_PollOption_optionText"
>
Socks
</div>
<div
class="mx_MPollBody_optionVoteCount"
class="mx_PollOption_optionVoteCount"
>
0 votes
</div>
</div>
</div>
<div
class="mx_MPollBody_popularityBackground"
class="mx_PollOption_popularityBackground"
>
<div
class="mx_MPollBody_popularityAmount"
class="mx_PollOption_popularityAmount"
style="width: 0%;"
/>
</div>
</div>
<div
class="mx_MPollBody_option mx_MPollBody_option_ended"
class="mx_PollOption mx_PollOption_ended"
data-testid="pollOption-shoes"
>
<div
class="mx_MPollBody_endedOption"
class="mx_PollOption_endedOption"
data-value="shoes"
>
<div
class="mx_MPollBody_optionDescription"
class="mx_PollOption_content"
>
<div
class="mx_MPollBody_optionText"
class="mx_PollOption_optionText"
>
Shoes
</div>
<div
class="mx_MPollBody_optionVoteCount"
class="mx_PollOption_optionVoteCount"
>
0 votes
</div>
</div>
</div>
<div
class="mx_MPollBody_popularityBackground"
class="mx_PollOption_popularityBackground"
>
<div
class="mx_MPollBody_popularityAmount"
class="mx_PollOption_popularityAmount"
style="width: 0%;"
/>
</div>

View file

@ -83,7 +83,7 @@ describe("<PinnedMessagesCard />", () => {
};
const mountPins = async (room: Room): Promise<ReactWrapper<ComponentProps<typeof PinnedMessagesCard>>> => {
let pins;
let pins!: ReactWrapper<ComponentProps<typeof PinnedMessagesCard>>;
await act(async () => {
pins = mount(
<PinnedMessagesCard
@ -239,9 +239,9 @@ describe("<PinnedMessagesCard />", () => {
const answers = (poll.unstableExtensibleEvent as PollStartEvent).answers;
const responses = [
["@alice:example.org", 0],
["@bob:example.org", 0],
["@eve:example.org", 1],
["@alice:example.org", 0] as [string, number],
["@bob:example.org", 0] as [string, number],
["@eve:example.org", 1] as [string, number],
].map(([user, option], i) =>
mkEvent({
...PollResponseEvent.from([answers[option as number].id], poll.getId()!).serialize(),
@ -287,8 +287,8 @@ describe("<PinnedMessagesCard />", () => {
const pinTile = pins.find(MPollBody);
expect(pinTile.length).toEqual(1);
expect(pinTile.find(".mx_MPollBody_option_ended").length).toEqual(2);
expect(pinTile.find(".mx_MPollBody_optionVoteCount").first().text()).toEqual("2 votes");
expect(pinTile.find(".mx_MPollBody_optionVoteCount").last().text()).toEqual("1 vote");
expect(pinTile.find(".mx_PollOption_ended").length).toEqual(2);
expect(pinTile.find(".mx_PollOption_optionVoteCount").first().text()).toEqual("2 votes");
expect(pinTile.find(".mx_PollOption_optionVoteCount").last().text()).toEqual("1 vote");
});
});

View file

@ -15,13 +15,14 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import React, { Component } from "react";
import ReactTestUtils from "react-dom/test-utils";
import ReactDOM from "react-dom";
import { Room } from "matrix-js-sdk/src/models/room";
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { User } from "matrix-js-sdk/src/models/user";
import { compare } from "matrix-js-sdk/src/utils";
import { MatrixClient, RoomState } from "matrix-js-sdk/src/matrix";
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
import * as TestUtils from "../../../test-utils";
@ -43,15 +44,15 @@ describe("MemberList", () => {
return room;
}
let parentDiv = null;
let client = null;
let root = null;
let memberListRoom;
let memberList = null;
let parentDiv: HTMLDivElement = null;
let client: MatrixClient = null;
let root: Component = null;
let memberListRoom: Room;
let memberList: MemberList = null;
let adminUsers = [];
let moderatorUsers = [];
let defaultUsers = [];
let adminUsers: RoomMember[] = [];
let moderatorUsers: RoomMember[] = [];
let defaultUsers: RoomMember[] = [];
beforeEach(function () {
TestUtils.stubClient();
@ -109,13 +110,14 @@ describe("MemberList", () => {
memberListRoom.currentState = {
members: {},
getMember: jest.fn(),
getStateEvents: (eventType, stateKey) => (stateKey === undefined ? [] : null), // ignore 3pid invites
};
getStateEvents: ((eventType, stateKey) =>
stateKey === undefined ? [] : null) as RoomState["getStateEvents"], // ignore 3pid invites
} as unknown as RoomState;
for (const member of [...adminUsers, ...moderatorUsers, ...defaultUsers]) {
memberListRoom.currentState.members[member.userId] = member;
}
const gatherWrappedRef = (r) => {
const gatherWrappedRef = (r: MemberList) => {
memberList = r;
};
const context = new TestSdkContext();
@ -131,7 +133,7 @@ describe("MemberList", () => {
/>
</SDKContext.Provider>,
parentDiv,
);
) as unknown as Component;
});
afterEach((done) => {
@ -144,7 +146,7 @@ describe("MemberList", () => {
done();
});
function expectOrderedByPresenceAndPowerLevel(memberTiles, isPresenceEnabled) {
function expectOrderedByPresenceAndPowerLevel(memberTiles: MemberTile[], isPresenceEnabled: boolean) {
let prevMember = null;
for (const tile of memberTiles) {
const memberA = prevMember;
@ -164,8 +166,8 @@ describe("MemberList", () => {
let groupChange = false;
if (isPresenceEnabled) {
const convertPresence = (p) => (p === "unavailable" ? "online" : p);
const presenceIndex = (p) => {
const convertPresence = (p: string) => (p === "unavailable" ? "online" : p);
const presenceIndex = (p: string) => {
const order = ["active", "online", "offline"];
const idx = order.indexOf(convertPresence(p));
return idx === -1 ? order.length : idx; // unknown states at the end
@ -212,7 +214,7 @@ describe("MemberList", () => {
}
}
function itDoesOrderMembersCorrectly(enablePresence) {
function itDoesOrderMembersCorrectly(enablePresence: boolean) {
describe("does order members correctly", () => {
// Note: even if presence is disabled, we still expect that the presence
// tests will pass. All expectOrderedByPresenceAndPowerLevel does is ensure
@ -251,7 +253,7 @@ describe("MemberList", () => {
// We already have admin, moderator, and default users so leave them alone
// Bypass all the event listeners and skip to the good part
memberList._showPresence = enablePresence;
memberList.showPresence = enablePresence;
memberList.updateListNow();
const tiles = ReactTestUtils.scryRenderedComponentsWithType(root, MemberTile);

View file

@ -53,7 +53,7 @@ describe("NewRoomIntro", () => {
describe("for a DM Room", () => {
beforeEach(() => {
jest.spyOn(DMRoomMap.shared(), "getUserIdForRoomId").mockReturnValue(userId);
const room = new Room(roomId, client, client.getUserId());
const room = new Room(roomId, client, client.getUserId()!);
room.name = "test_room";
renderNewRoomIntro(client, room);
});
@ -67,7 +67,7 @@ describe("NewRoomIntro", () => {
describe("for a DM LocalRoom", () => {
beforeEach(() => {
jest.spyOn(DMRoomMap.shared(), "getUserIdForRoomId").mockReturnValue(userId);
const localRoom = new LocalRoom(roomId, client, client.getUserId());
const localRoom = new LocalRoom(roomId, client, client.getUserId()!);
localRoom.name = "test_room";
localRoom.targets.push(new DirectoryMember({ user_id: userId }));
renderNewRoomIntro(client, localRoom);

View file

@ -248,13 +248,12 @@ function createRoom(info: IRoomCreationInfo) {
}
function mountHeader(room: Room, propsOverride = {}, roomContext?: Partial<IRoomState>): ReactWrapper {
const props = {
const props: RoomHeaderProps = {
room,
inRoom: true,
onSearchClick: () => {},
onInviteClick: null,
onForgetClick: () => {},
onCallPlaced: (_type) => {},
onAppsClick: () => {},
e2eStatus: E2EStatus.Normal,
appsShown: true,
@ -320,7 +319,7 @@ function mkJoinEvent(roomId: string, userId: string) {
}
function mkDirectEvent(roomId: string, userId: string, otherUsers: string[]): MatrixEvent {
const content = {};
const content: Record<string, string[]> = {};
for (const otherUserId of otherUsers) {
content[otherUserId] = [roomId];
}

View file

@ -61,7 +61,7 @@ const setupMainMenu = async (client: MatrixClient, testSpace: Room): Promise<Ren
expect(wrapper.container.textContent).toBe("Test Space");
act(() => {
wrapper.container.querySelector<HTMLElement>('[aria-label="Test Space menu"]').click();
wrapper.container.querySelector<HTMLElement>('[aria-label="Test Space menu"]')?.click();
});
return wrapper;
@ -77,7 +77,7 @@ const setupPlusMenu = async (client: MatrixClient, testSpace: Room): Promise<Ren
expect(wrapper.container.textContent).toBe("Test Space");
act(() => {
wrapper.container.querySelector<HTMLElement>('[aria-label="Add"]').click();
wrapper.container.querySelector<HTMLElement>('[aria-label="Add"]')?.click();
});
return wrapper;
@ -92,7 +92,7 @@ const checkMenuLabels = (items: NodeListOf<Element>, labelArray: Array<string>)
expect(items).toHaveLength(labelArray.length);
const checkLabel = (item: Element, label: string) => {
expect(item.querySelector(".mx_IconizedContextMenu_label").textContent).toBe(label);
expect(item.querySelector(".mx_IconizedContextMenu_label")?.textContent).toBe(label);
};
labelArray.forEach((label, index) => {

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import React, { ComponentProps } from "react";
import { render, fireEvent, RenderResult, waitFor } from "@testing-library/react";
import { Room, RoomMember, MatrixError, IContent } from "matrix-js-sdk/src/matrix";
@ -71,7 +71,7 @@ describe("<RoomPreviewBar />", () => {
const inviterUserId = "@inviter:test.com";
const otherUserId = "@othertester:test.com";
const getComponent = (props = {}) => {
const getComponent = (props: ComponentProps<typeof RoomPreviewBar> = {}) => {
const defaultProps = {
room: createRoom(roomId, userId),
};
@ -84,9 +84,9 @@ describe("<RoomPreviewBar />", () => {
const getActions = (wrapper: RenderResult) =>
wrapper.container.querySelector<HTMLDivElement>(".mx_RoomPreviewBar_actions");
const getPrimaryActionButton = (wrapper: RenderResult) =>
getActions(wrapper).querySelector(".mx_AccessibleButton_kind_primary");
getActions(wrapper)?.querySelector(".mx_AccessibleButton_kind_primary");
const getSecondaryActionButton = (wrapper: RenderResult) =>
getActions(wrapper).querySelector(".mx_AccessibleButton_kind_secondary");
getActions(wrapper)?.querySelector(".mx_AccessibleButton_kind_secondary");
beforeEach(() => {
stubClient();
@ -102,17 +102,17 @@ describe("<RoomPreviewBar />", () => {
const component = getComponent({ joining: true });
expect(isSpinnerRendered(component)).toBeTruthy();
expect(getMessage(component).textContent).toEqual("Joining …");
expect(getMessage(component)?.textContent).toEqual("Joining …");
});
it("renders rejecting message", () => {
const component = getComponent({ rejecting: true });
expect(isSpinnerRendered(component)).toBeTruthy();
expect(getMessage(component).textContent).toEqual("Rejecting invite …");
expect(getMessage(component)?.textContent).toEqual("Rejecting invite …");
});
it("renders loading message", () => {
const component = getComponent({ loading: true });
expect(isSpinnerRendered(component)).toBeTruthy();
expect(getMessage(component).textContent).toEqual("Loading …");
expect(getMessage(component)?.textContent).toEqual("Loading …");
});
it("renders not logged in message", () => {
@ -120,7 +120,7 @@ describe("<RoomPreviewBar />", () => {
const component = getComponent({ loading: true });
expect(isSpinnerRendered(component)).toBeFalsy();
expect(getMessage(component).textContent).toEqual("Join the conversation with an account");
expect(getMessage(component)?.textContent).toEqual("Join the conversation with an account");
});
it("should send room oob data to start login", async () => {
@ -136,8 +136,8 @@ describe("<RoomPreviewBar />", () => {
const dispatcherSpy = jest.fn();
const dispatcherRef = defaultDispatcher.register(dispatcherSpy);
expect(getMessage(component).textContent).toEqual("Join the conversation with an account");
fireEvent.click(getPrimaryActionButton(component));
expect(getMessage(component)?.textContent).toEqual("Join the conversation with an account");
fireEvent.click(getPrimaryActionButton(component)!);
await waitFor(() =>
expect(dispatcherSpy).toHaveBeenCalledWith(
@ -222,13 +222,13 @@ describe("<RoomPreviewBar />", () => {
});
describe("without an invited email", () => {
describe("for a non-dm room", () => {
const mockGetMember = (id) => {
const mockGetMember = (id: string) => {
if (id === userId) return userMember;
return inviterMember;
};
const onJoinClick = jest.fn();
const onRejectClick = jest.fn();
let room;
let room: Room;
beforeEach(() => {
room = createRoom(roomId, userId);
@ -268,27 +268,27 @@ describe("<RoomPreviewBar />", () => {
it("joins room on primary button click", () => {
const component = getComponent({ inviterName, room, onJoinClick, onRejectClick });
fireEvent.click(getPrimaryActionButton(component));
fireEvent.click(getPrimaryActionButton(component)!);
expect(onJoinClick).toHaveBeenCalled();
});
it("rejects invite on secondary button click", () => {
const component = getComponent({ inviterName, room, onJoinClick, onRejectClick });
fireEvent.click(getSecondaryActionButton(component));
fireEvent.click(getSecondaryActionButton(component)!);
expect(onRejectClick).toHaveBeenCalled();
});
});
describe("for a dm room", () => {
const mockGetMember = (id) => {
const mockGetMember = (id: string) => {
if (id === userId) return userMemberWithDmInvite;
return inviterMember;
};
const onJoinClick = jest.fn();
const onRejectClick = jest.fn();
let room;
let room: Room;
beforeEach(() => {
room = createRoom(roomId, userId);
@ -324,14 +324,14 @@ describe("<RoomPreviewBar />", () => {
{ medium: "not-email", address: "address 2" },
];
const testJoinButton = (props) => async () => {
const testJoinButton = (props: ComponentProps<typeof RoomPreviewBar>) => async () => {
const onJoinClick = jest.fn();
const onRejectClick = jest.fn();
const component = getComponent({ ...props, onJoinClick, onRejectClick });
await new Promise(setImmediate);
expect(getPrimaryActionButton(component)).toBeTruthy();
expect(getSecondaryActionButton(component)).toBeFalsy();
fireEvent.click(getPrimaryActionButton(component));
fireEvent.click(getPrimaryActionButton(component)!);
expect(onJoinClick).toHaveBeenCalled();
};

View file

@ -78,6 +78,7 @@ describe("<SendMessageComposer/>", () => {
resizing: false,
narrow: false,
activeCall: null,
msc3946ProcessDynamicPredecessor: false,
};
describe("createMessageContent", () => {
const permalinkCreator = jest.fn() as any;

View file

@ -24,8 +24,8 @@ import * as mockKeyboard from "../../../../../../src/Keyboard";
describe("PlainTextComposer", () => {
const customRender = (
onChange = (_content: string) => void 0,
onSend = () => void 0,
onChange = (_content: string): void => void 0,
onSend = (): void => void 0,
disabled = false,
initialContent?: string,
) => {

View file

@ -21,7 +21,7 @@ import { Key } from "../../../../src/Keyboard";
import { mockPlatformPeg, unmockPlatformPeg } from "../../../test-utils/platform";
import { KeyboardKey, KeyboardShortcut } from "../../../../src/components/views/settings/KeyboardShortcut";
const renderKeyboardShortcut = (Component, props?) => {
const renderKeyboardShortcut = (Component: React.FunctionComponentFactory<any>, props: Record<string, any>) => {
return render(<Component {...props} />).container;
};

View file

@ -22,6 +22,7 @@ import {
MatrixEvent,
Room,
NotificationCountType,
PushRuleActionName,
} from "matrix-js-sdk/src/matrix";
import { IThreepid, ThreepidMedium } from "matrix-js-sdk/src/@types/threepids";
import { act } from "react-dom/test-utils";
@ -38,15 +39,14 @@ jest.mock("matrix-js-sdk/src/logger");
// Avoid indirectly importing any eagerly created stores that would require extra setup
jest.mock("../../../../src/Notifier");
const masterRule = {
actions: ["dont_notify"],
const masterRule: IPushRule = {
actions: [PushRuleActionName.DontNotify],
conditions: [],
default: true,
enabled: false,
rule_id: RuleId.Master,
};
// eslint-disable-next-line max-len
const oneToOneRule = {
const oneToOneRule: IPushRule = {
conditions: [
{ kind: "room_member_count", is: "2" },
{ kind: "event_match", key: "type", pattern: "m.room.message" },
@ -56,8 +56,7 @@ const oneToOneRule = {
default: true,
enabled: true,
} as IPushRule;
// eslint-disable-next-line max-len
const encryptedOneToOneRule = {
const encryptedOneToOneRule: IPushRule = {
conditions: [
{ kind: "room_member_count", is: "2" },
{ kind: "event_match", key: "type", pattern: "m.room.encrypted" },
@ -67,15 +66,13 @@ const encryptedOneToOneRule = {
default: true,
enabled: true,
} as IPushRule;
// eslint-disable-next-line max-len
const encryptedGroupRule = {
const encryptedGroupRule: IPushRule = {
conditions: [{ kind: "event_match", key: "type", pattern: "m.room.encrypted" }],
actions: ["dont_notify"],
rule_id: ".m.rule.encrypted",
default: true,
enabled: true,
} as IPushRule;
// eslint-disable-next-line max-len
const pushRules: IPushRules = {
global: {
underride: [
@ -367,7 +364,7 @@ describe("<Notifications />", () => {
it("toggles and sets settings correctly", async () => {
await getComponentAndWait();
let audioNotifsToggle;
let audioNotifsToggle: HTMLDivElement;
const update = () => {
audioNotifsToggle = screen

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import React, { ComponentProps } from "react";
import { fireEvent, render } from "@testing-library/react";
import { PUSHER_ENABLED } from "matrix-js-sdk/src/@types/event";
@ -28,11 +28,10 @@ describe("<DeviceDetails />", () => {
isVerified: false,
deviceType: DeviceType.Unknown,
};
const defaultProps = {
const defaultProps: ComponentProps<typeof DeviceDetails> = {
device: baseDevice,
pusher: null,
isSigningOut: false,
isLoading: false,
onSignOutDevice: jest.fn(),
saveDeviceName: jest.fn(),
setPushNotifications: jest.fn(),

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import React, { ComponentProps } from "react";
import { act, fireEvent, render } from "@testing-library/react";
import { FilteredDeviceList } from "../../../../../src/components/views/settings/devices/FilteredDeviceList";
@ -26,6 +26,9 @@ mockPlatformPeg();
const MS_DAY = 86400000;
describe("<FilteredDeviceList />", () => {
// 14.03.2022 16:15
const now = 1647270879403;
jest.spyOn(global.Date, "now").mockReturnValue(now);
const newDevice = {
device_id: "new",
last_seen_ts: Date.now() - 500,
@ -56,13 +59,12 @@ describe("<FilteredDeviceList />", () => {
last_seen_ts: Date.now() - MS_DAY * 100,
deviceType: DeviceType.Unknown,
};
const defaultProps = {
const defaultProps: ComponentProps<typeof FilteredDeviceList> = {
onFilterChange: jest.fn(),
onDeviceExpandToggle: jest.fn(),
onSignOutDevices: jest.fn(),
saveDeviceName: jest.fn(),
setPushNotifications: jest.fn(),
setPusherEnabled: jest.fn(),
setSelectedDeviceIds: jest.fn(),
localNotificationSettings: new Map(),
expandedDeviceIds: [],
@ -81,6 +83,10 @@ describe("<FilteredDeviceList />", () => {
const getComponent = (props = {}) => <FilteredDeviceList {...defaultProps} {...props} />;
afterAll(() => {
jest.spyOn(global.Date, "now").mockRestore();
});
it("renders devices in correct order", () => {
const { container } = render(getComponent());
const tiles = container.querySelectorAll(".mx_DeviceTile");

View file

@ -28,7 +28,7 @@ jest.mock("matrix-js-sdk/src/rendezvous/channels");
const mockedFlow = jest.fn();
jest.mock("../../../../../src/components/views/auth/LoginWithQRFlow", () => (props) => {
jest.mock("../../../../../src/components/views/auth/LoginWithQRFlow", () => (props: Record<string, any>) => {
mockedFlow(props);
return <div />;
});

View file

@ -14,6 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { UIAFlow } from "matrix-js-sdk/src/matrix";
import { deleteDevicesWithInteractiveAuth } from "../../../../../src/components/views/settings/devices/deleteDevices";
import Modal from "../../../../../src/Modal";
import { getMockClientWithEventEmitter, mockClientMethodsUser } from "../../../../test-utils";
@ -28,7 +30,7 @@ describe("deleteDevices()", () => {
const modalSpy = jest.spyOn(Modal, "createDialog");
const interactiveAuthError = { httpStatus: 401, data: { flows: [] } };
const interactiveAuthError = { httpStatus: 401, data: { flows: [] as UIAFlow[] } };
beforeEach(() => {
jest.clearAllMocks();

View file

@ -39,11 +39,11 @@ describe("RolesRoomSettingsTab", () => {
};
const getVoiceBroadcastsSelect = (): HTMLElement => {
return renderTab().container.querySelector("select[label='Voice broadcasts']");
return renderTab().container.querySelector("select[label='Voice broadcasts']")!;
};
const getVoiceBroadcastsSelectedOption = (): HTMLElement => {
return renderTab().container.querySelector("select[label='Voice broadcasts'] option:checked");
return renderTab().container.querySelector("select[label='Voice broadcasts'] option:checked")!;
};
beforeEach(() => {
@ -65,7 +65,7 @@ describe("RolesRoomSettingsTab", () => {
state_key: "",
content: {
users: {
[cli.getUserId()]: 100,
[cli.getUserId()!]: 100,
"@admin:server": 100,
},
},
@ -108,19 +108,19 @@ describe("RolesRoomSettingsTab", () => {
};
const getStartCallSelect = (tab: RenderResult): HTMLElement => {
return tab.container.querySelector("select[label='Start Element Call calls']");
return tab.container.querySelector("select[label='Start Element Call calls']")!;
};
const getStartCallSelectedOption = (tab: RenderResult): HTMLElement => {
return tab.container.querySelector("select[label='Start Element Call calls'] option:checked");
return tab.container.querySelector("select[label='Start Element Call calls'] option:checked")!;
};
const getJoinCallSelect = (tab: RenderResult): HTMLElement => {
return tab.container.querySelector("select[label='Join Element Call calls']");
return tab.container.querySelector("select[label='Join Element Call calls']")!;
};
const getJoinCallSelectedOption = (tab: RenderResult): HTMLElement => {
return tab.container.querySelector("select[label='Join Element Call calls'] option:checked");
return tab.container.querySelector("select[label='Join Element Call calls'] option:checked")!;
};
describe("Element Call enabled", () => {

View file

@ -46,7 +46,7 @@ describe("RolesRoomSettingsTab", () => {
});
describe("Element Call", () => {
const mockPowerLevels = (events): void => {
const mockPowerLevels = (events: Record<string, number>): void => {
jest.spyOn(room.currentState, "getStateEvents").mockReturnValue({
getContent: () => ({
events,

View file

@ -24,7 +24,7 @@ import { mockPlatformPeg } from "../../../../../test-utils/platform";
const PATH_TO_KEYBOARD_SHORTCUTS = "../../../../../../src/accessibility/KeyboardShortcuts";
const PATH_TO_KEYBOARD_SHORTCUT_UTILS = "../../../../../../src/accessibility/KeyboardShortcutUtils";
const mockKeyboardShortcuts = (override) => {
const mockKeyboardShortcuts = (override: Record<string, any>) => {
jest.doMock(PATH_TO_KEYBOARD_SHORTCUTS, () => {
const original = jest.requireActual(PATH_TO_KEYBOARD_SHORTCUTS);
return {
@ -34,7 +34,7 @@ const mockKeyboardShortcuts = (override) => {
});
};
const mockKeyboardShortcutUtils = (override) => {
const mockKeyboardShortcutUtils = (override: Record<string, any>) => {
jest.doMock(PATH_TO_KEYBOARD_SHORTCUT_UTILS, () => {
const original = jest.requireActual(PATH_TO_KEYBOARD_SHORTCUT_UTILS);
return {
@ -68,7 +68,7 @@ describe("KeyboardUserSettingsTab", () => {
},
});
mockKeyboardShortcutUtils({
getKeyboardShortcutValue: (name) => {
getKeyboardShortcutValue: (name: string) => {
switch (name) {
case "keybind1":
return {
@ -88,7 +88,7 @@ describe("KeyboardUserSettingsTab", () => {
}
}
},
getKeyboardShortcutDisplayName: (name) => {
getKeyboardShortcutDisplayName: (name: string) => {
switch (name) {
case "keybind1":
return "Cancel replying to a message";

View file

@ -927,7 +927,7 @@ describe("<SessionManagerTab />", () => {
// get a handle for resolving the delete call
// because promise flushing after the confirm modal is resolving this too
// and we want to test the loading state here
let resolveDeleteRequest;
let resolveDeleteRequest: (v?: IAuthData) => void;
mockClient.deleteMultipleDevices.mockImplementation(() => {
const promise = new Promise<IAuthData>((resolve) => {
resolveDeleteRequest = resolve;

View file

@ -21,7 +21,7 @@ import { MatrixClient } from "matrix-js-sdk/src/matrix";
import UnwrappedSpacePanel from "../../../../src/components/views/spaces/SpacePanel";
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
import { SpaceKey } from "../../../../src/stores/spaces";
import { MetaSpace, SpaceKey } from "../../../../src/stores/spaces";
import { shouldShowComponent } from "../../../../src/customisations/helpers/UIComponents";
import { UIComponent } from "../../../../src/settings/UIFeature";
import { wrapInSdkContext } from "../../../test-utils";
@ -31,9 +31,9 @@ jest.mock("../../../../src/stores/spaces/SpaceStore", () => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const EventEmitter = require("events");
class MockSpaceStore extends EventEmitter {
invitedSpaces = [];
enabledMetaSpaces = [];
spacePanelSpaces = [];
invitedSpaces: SpaceKey[] = [];
enabledMetaSpaces: MetaSpace[] = [];
spacePanelSpaces: string[] = [];
activeSpace: SpaceKey = "!space1";
}
return {

View file

@ -93,15 +93,15 @@ describe("<SpaceSettingsVisibilityTab />", () => {
};
const getByTestId = (container: Element, id: string) => container.querySelector(`[data-test-id=${id}]`);
const toggleGuestAccessSection = async (component) => {
const toggleGuestAccessSection = async (component: Element) => {
const toggleButton = getByTestId(component, "toggle-guest-access-btn");
await act(async () => {
Simulate.click(toggleButton);
});
};
const getGuestAccessToggle = (component) => component.querySelector('[aria-label="Enable guest access"');
const getHistoryVisibilityToggle = (component) => component.querySelector('[aria-label="Preview Space"');
const getErrorMessage = (component) => getByTestId(component, "space-settings-error")?.textContent;
const getGuestAccessToggle = (component: Element) => component.querySelector('[aria-label="Enable guest access"');
const getHistoryVisibilityToggle = (component: Element) => component.querySelector('[aria-label="Preview Space"');
const getErrorMessage = (component: Element) => getByTestId(component, "space-settings-error")?.textContent;
beforeEach(() => {
(mockMatrixClient.sendStateEvent as jest.Mock).mockClear().mockResolvedValue({});

View file

@ -16,6 +16,7 @@ limitations under the License.
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
import { parseEvent } from "../../src/editor/deserialize";
import { Part } from "../../src/editor/parts";
import { createPartCreator } from "./mock";
const FOUR_SPACES = " ".repeat(4);
@ -50,12 +51,12 @@ function textMessageReply(body: string, msgtype = "m.text") {
} as unknown as MatrixEvent;
}
function mergeAdjacentParts(parts) {
let prevPart;
function mergeAdjacentParts(parts: Part[]) {
let prevPart: Part | undefined;
for (let i = 0; i < parts.length; ++i) {
let part = parts[i];
const isEmpty = !part.text.length;
const isMerged = !isEmpty && prevPart && prevPart.merge(part);
const isMerged = !isEmpty && prevPart && prevPart.merge?.(part);
if (isEmpty || isMerged) {
// remove empty or merged part
part = prevPart;
@ -67,7 +68,7 @@ function mergeAdjacentParts(parts) {
}
}
function normalize(parts) {
function normalize(parts: Part[]) {
// merge adjacent parts as this will happen
// in the model anyway, and whether 1 or multiple
// plain parts are returned is an implementation detail

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { Room, MatrixClient } from "matrix-js-sdk/src/matrix";
import { Room, MatrixClient, RoomMember } from "matrix-js-sdk/src/matrix";
import AutocompleteWrapperModel, { UpdateCallback } from "../../src/editor/autocomplete";
import { Caret } from "../../src/editor/caret";
@ -63,7 +63,7 @@ class MockAutoComplete {
// MockClient & MockRoom are only used for avatars in room and user pills,
// which is not tested
class MockRoom {
getMember() {
getMember(): RoomMember | null {
return null;
}
}

View file

@ -16,9 +16,10 @@ limitations under the License.
import EditorModel from "../../src/editor/model";
import { createPartCreator } from "./mock";
import { Caret } from "../../src/editor/caret";
function createRenderer() {
const render = (c) => {
const render = (c: Caret) => {
render.caret = c;
render.count += 1;
};

View file

@ -22,7 +22,7 @@ describe("useDebouncedCallback", () => {
beforeAll(() => jest.useFakeTimers());
afterAll(() => jest.useRealTimers());
function render(enabled: boolean, callback: (...params: any) => void, params: any) {
function render(enabled: boolean, callback: (...params: any[]) => void, params: any[]) {
return renderHook(({ enabled, callback, params }) => useDebouncedCallback(enabled, callback, params), {
initialProps: {
enabled,
@ -34,7 +34,7 @@ describe("useDebouncedCallback", () => {
it("should be able to handle empty parameters", async () => {
// When
const params = [];
const params: any[] = [];
const callback = jest.fn();
render(true, callback, params);
jest.advanceTimersByTime(1);

View file

@ -22,12 +22,12 @@ import { act } from "react-dom/test-utils";
import { useLatestResult } from "../../src/hooks/useLatestResult";
function LatestResultsComponent({ query, doRequest }) {
function LatestResultsComponent({ query, doRequest }: { query: number; doRequest(query: number): Promise<number> }) {
const [value, setValueInternal] = useState<number>(0);
const [updateQuery, updateResult] = useLatestResult(setValueInternal);
useEffect(() => {
updateQuery(query);
doRequest(query).then((it) => {
doRequest(query).then((it: number) => {
updateResult(query, it);
});
}, [doRequest, query, updateQuery, updateResult]);
@ -37,7 +37,7 @@ function LatestResultsComponent({ query, doRequest }) {
describe("useLatestResult", () => {
it("should return results", async () => {
const doRequest = async (query) => {
const doRequest = async (query: number) => {
await sleep(180);
return query;
};
@ -63,7 +63,7 @@ describe("useLatestResult", () => {
});
it("should prevent out-of-order results", async () => {
const doRequest = async (query) => {
const doRequest = async (query: number) => {
await sleep(query);
return query;
};

View file

@ -16,6 +16,7 @@ limitations under the License.
// eslint-disable-next-line deprecate/import
import { mount } from "enzyme";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import { sleep } from "matrix-js-sdk/src/utils";
import React from "react";
import { act } from "react-dom/test-utils";
@ -24,7 +25,7 @@ import { useProfileInfo } from "../../src/hooks/useProfileInfo";
import { MatrixClientPeg } from "../../src/MatrixClientPeg";
import { stubClient } from "../test-utils/test-utils";
function ProfileInfoComponent({ onClick }) {
function ProfileInfoComponent({ onClick }: { onClick(hook: ReturnType<typeof useProfileInfo>): void }) {
const profileInfo = useProfileInfo();
const { ready, loading, profile } = profileInfo;
@ -38,7 +39,7 @@ function ProfileInfoComponent({ onClick }) {
}
describe("useProfileInfo", () => {
let cli;
let cli: MatrixClient;
beforeEach(() => {
stubClient();
@ -58,7 +59,6 @@ describe("useProfileInfo", () => {
<ProfileInfoComponent
onClick={(hook) => {
hook.search({
limit: 1,
query,
});
}}
@ -79,7 +79,6 @@ describe("useProfileInfo", () => {
<ProfileInfoComponent
onClick={(hook) => {
hook.search({
limit: 1,
query: "",
});
}}
@ -103,7 +102,6 @@ describe("useProfileInfo", () => {
<ProfileInfoComponent
onClick={(hook) => {
hook.search({
limit: 1,
query,
});
}}
@ -130,7 +128,6 @@ describe("useProfileInfo", () => {
<ProfileInfoComponent
onClick={(hook) => {
hook.search({
limit: 1,
query,
});
}}
@ -153,7 +150,6 @@ describe("useProfileInfo", () => {
<ProfileInfoComponent
onClick={(hook) => {
hook.search({
limit: 1,
query,
});
}}

View file

@ -16,6 +16,7 @@ limitations under the License.
// eslint-disable-next-line deprecate/import
import { mount } from "enzyme";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import { sleep } from "matrix-js-sdk/src/utils";
import React from "react";
import { act } from "react-dom/test-utils";
@ -24,7 +25,7 @@ import { usePublicRoomDirectory } from "../../src/hooks/usePublicRoomDirectory";
import { MatrixClientPeg } from "../../src/MatrixClientPeg";
import { stubClient } from "../test-utils/test-utils";
function PublicRoomComponent({ onClick }) {
function PublicRoomComponent({ onClick }: { onClick(hook: ReturnType<typeof usePublicRoomDirectory>): void }) {
const roomDirectory = usePublicRoomDirectory();
const { ready, loading, publicRooms } = roomDirectory;
@ -38,7 +39,7 @@ function PublicRoomComponent({ onClick }) {
}
describe("usePublicRoomDirectory", () => {
let cli;
let cli: MatrixClient;
beforeEach(() => {
stubClient();

View file

@ -16,6 +16,7 @@ limitations under the License.
// eslint-disable-next-line deprecate/import
import { mount } from "enzyme";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import { sleep } from "matrix-js-sdk/src/utils";
import React from "react";
import { act } from "react-dom/test-utils";
@ -24,7 +25,7 @@ import { useUserDirectory } from "../../src/hooks/useUserDirectory";
import { MatrixClientPeg } from "../../src/MatrixClientPeg";
import { stubClient } from "../test-utils";
function UserDirectoryComponent({ onClick }) {
function UserDirectoryComponent({ onClick }: { onClick(hook: ReturnType<typeof useUserDirectory>): void }) {
const userDirectory = useUserDirectory();
const { ready, loading, users } = userDirectory;
@ -37,7 +38,7 @@ function UserDirectoryComponent({ onClick }) {
}
describe("useUserDirectory", () => {
let cli;
let cli: MatrixClient;
beforeEach(() => {
stubClient();
@ -53,6 +54,7 @@ describe("useUserDirectory", () => {
display_name: query,
},
],
limited: false,
});
});

View file

@ -49,7 +49,7 @@ describe("languageHandler", function () {
{ policyLink: () => "foo" },
"Accept foo to continue:",
],
["handles text in tags", textInTagSub, {}, { a: (sub) => `x${sub}x` }, "xUpgradex to your own domain"],
["handles text in tags", textInTagSub, {}, { a: (sub: string) => `x${sub}x` }, "xUpgradex to your own domain"],
[
"handles variable substitution with React function component",
variableSub,
@ -82,7 +82,7 @@ describe("languageHandler", function () {
],
];
let oldNodeEnv;
let oldNodeEnv: string;
beforeAll(() => {
oldNodeEnv = process.env.NODE_ENV;
process.env.NODE_ENV = "test";
@ -138,7 +138,7 @@ describe("languageHandler", function () {
// counterpart doesnt expose any way to restore default config
// missingEntryGenerator is mocked in the root setup file
// reset to default here
const counterpartDefaultMissingEntryGen = function (key) {
const counterpartDefaultMissingEntryGen = function (key: string) {
return "missing translation: " + key;
};
setMissingEntryGenerator(counterpartDefaultMissingEntryGen);

View file

@ -16,7 +16,7 @@ limitations under the License.
import { linkify, Type } from "../src/linkify-matrix";
describe("linkify-matrix", () => {
const linkTypesByInitialCharacter = {
const linkTypesByInitialCharacter: Record<string, string> = {
"#": "roomalias",
"@": "userid",
};

View file

@ -28,7 +28,7 @@ const TEST_DATA = [
];
describe("SettingsStore", () => {
let platformSettings: object;
let platformSettings: Record<string, any>;
beforeAll(() => {
jest.clearAllMocks();

View file

@ -72,17 +72,15 @@ describe("IncompatibleController", () => {
describe("getValueOverride()", () => {
it("returns forced value when setting is incompatible", () => {
settingsGetValueSpy.mockReturnValue(true);
const forcedValue = { key: null };
const controller = new IncompatibleController("feature_spotlight", forcedValue);
const controller = new IncompatibleController("feature_spotlight", { key: null });
expect(
controller.getValueOverride(SettingLevel.ACCOUNT, "$room:server", true, SettingLevel.ACCOUNT),
).toEqual(forcedValue);
).toEqual({ key: null });
});
it("returns null when setting is not incompatible", () => {
settingsGetValueSpy.mockReturnValue(false);
const forcedValue = { key: null };
const controller = new IncompatibleController("feature_spotlight", forcedValue);
const controller = new IncompatibleController("feature_spotlight", { key: null });
expect(
controller.getValueOverride(SettingLevel.ACCOUNT, "$room:server", true, SettingLevel.ACCOUNT),
).toEqual(null);

View file

@ -30,8 +30,10 @@ const lv = {
// de_DE.json
// lv.json - mock version with few translations, used to test fallback translation
function weblateToCounterpart(inTrs: object): object {
const outTrs = {};
type Translations = Record<string, Record<string, string> | string>;
function weblateToCounterpart(inTrs: Record<string, string>): Translations {
const outTrs: Translations = {};
for (const key of Object.keys(inTrs)) {
const keyParts = key.split("|", 2);

View file

@ -16,7 +16,7 @@ limitations under the License.
import fetchMock from "fetch-mock-jest";
import { TextDecoder, TextEncoder } from "util";
import fetch from "node-fetch";
import { Response } from "node-fetch";
// jest 27 removes setImmediate from jsdom
// polyfill until setImmediate use in client can be removed
@ -88,7 +88,8 @@ fetchMock.get("/image-file-stub", "image file stub");
// @ts-ignore
window.fetch = fetchMock.sandbox();
window.Response = fetch.Response;
// @ts-ignore
window.Response = Response;
// set up mediaDevices mock
Object.defineProperty(navigator, "mediaDevices", {

View file

@ -26,6 +26,7 @@ import {
import { makeBeaconContent, makeBeaconInfoContent } from "matrix-js-sdk/src/content-helpers";
import { M_BEACON } from "matrix-js-sdk/src/@types/beacon";
import { logger } from "matrix-js-sdk/src/logger";
import { Mocked } from "jest-mock";
import { OwnBeaconStore, OwnBeaconStoreEvent } from "../../src/stores/OwnBeaconStore";
import {
@ -48,7 +49,7 @@ jest.mock("lodash", () => ({
jest.useFakeTimers();
describe("OwnBeaconStore", () => {
let geolocation;
let geolocation: Mocked<Geolocation>;
// 14.03.2022 16:15
const now = 1647270879403;
const HOUR_MS = 3600000;
@ -82,7 +83,7 @@ describe("OwnBeaconStore", () => {
// make fresh rooms every time
// as we update room state
const makeRoomsWithStateEvents = (stateEvents = []): [Room, Room] => {
const makeRoomsWithStateEvents = (stateEvents: MatrixEvent[] = []): [Room, Room] => {
const room1 = new Room(room1Id, mockClient, aliceId);
const room2 = new Room(room2Id, mockClient, aliceId);
@ -100,7 +101,7 @@ describe("OwnBeaconStore", () => {
return store;
};
const expireBeaconAndEmit = (store, beaconInfoEvent: MatrixEvent): void => {
const expireBeaconAndEmit = (store: OwnBeaconStore, beaconInfoEvent: MatrixEvent): void => {
const beacon = store.getBeaconById(getBeaconInfoIdentifier(beaconInfoEvent));
// time travel until beacon is expired
advanceDateAndTime(beacon.beaconInfo.timeout + 100);
@ -112,7 +113,11 @@ describe("OwnBeaconStore", () => {
mockClient.emit(BeaconEvent.LivenessChange, false, beacon);
};
const updateBeaconLivenessAndEmit = (store, beaconInfoEvent: MatrixEvent, isLive: boolean): void => {
const updateBeaconLivenessAndEmit = (
store: OwnBeaconStore,
beaconInfoEvent: MatrixEvent,
isLive: boolean,
): void => {
const beacon = store.getBeaconById(getBeaconInfoIdentifier(beaconInfoEvent));
// matches original state of event content
// except for live property

View file

@ -20,7 +20,7 @@ import { EventType } from "matrix-js-sdk/src/@types/event";
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import { defer } from "matrix-js-sdk/src/utils";
import { ClientEvent, RoomEvent, MatrixEvent } from "matrix-js-sdk/src/matrix";
import { ClientEvent, RoomEvent, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
import SpaceStore from "../../src/stores/spaces/SpaceStore";
import {
@ -68,7 +68,7 @@ const space2 = "!space2:server";
const space3 = "!space3:server";
const space4 = "!space4:server";
const getUserIdForRoomId = jest.fn((roomId) => {
const getUserIdForRoomId = jest.fn((roomId: string) => {
return {
[dm1]: dm1Partner.userId,
[dm2]: dm2Partner.userId,
@ -97,10 +97,10 @@ describe("SpaceStore", () => {
const spyDispatcher = jest.spyOn(defaultDispatcher, "dispatch");
let rooms = [];
let rooms: Room[] = [];
const mkRoom = (roomId: string) => testUtils.mkRoom(client, roomId, rooms);
const mkSpace = (spaceId: string, children: string[] = []) => testUtils.mkSpace(client, spaceId, rooms, children);
const viewRoom = (roomId) => defaultDispatcher.dispatch({ action: Action.ViewRoom, room_id: roomId }, true);
const viewRoom = (roomId: string) => defaultDispatcher.dispatch({ action: Action.ViewRoom, room_id: roomId }, true);
const run = async () => {
mocked(client).getRoom.mockImplementation((roomId) => rooms.find((room) => room.roomId === roomId));
@ -785,17 +785,17 @@ describe("SpaceStore", () => {
mkSpace(space1, [fav1, room1, space4]);
});
const addChildRoom = (spaceId, childId) => {
const addChildRoom = (spaceId: string, childId: string) => {
const childEvent = mkEvent({
event: true,
type: EventType.SpaceChild,
room: spaceId,
user: client.getUserId(),
user: client.getUserId()!,
skey: childId,
content: { via: [], canonical: true },
ts: Date.now(),
});
const spaceRoom = client.getRoom(spaceId);
const spaceRoom = client.getRoom(spaceId)!;
mocked(spaceRoom.currentState).getStateEvents.mockImplementation(
testUtils.mockStateEventImplementation([childEvent]),
);
@ -803,12 +803,12 @@ describe("SpaceStore", () => {
client.emit(RoomStateEvent.Events, childEvent, spaceRoom.currentState, undefined);
};
const addMember = (spaceId, user: RoomMember) => {
const addMember = (spaceId: string, user: RoomMember) => {
const memberEvent = mkEvent({
event: true,
type: EventType.RoomMember,
room: spaceId,
user: client.getUserId(),
user: client.getUserId()!,
skey: user.userId,
content: { membership: "join" },
ts: Date.now(),
@ -998,8 +998,8 @@ describe("SpaceStore", () => {
});
describe("context switching tests", () => {
let dispatcherRef;
let currentRoom = null;
let dispatcherRef: string;
let currentRoom: Room | null = null;
beforeEach(async () => {
[room1, room2, orphan1].forEach(mkRoom);
@ -1313,8 +1313,8 @@ describe("SpaceStore", () => {
callback: (...args: any[]) => void,
): () => void {
callback();
emitter.addListener(eventName, callback);
return () => emitter.removeListener(eventName, callback);
emitter?.addListener(eventName, callback);
return () => emitter?.removeListener(eventName, callback);
}
let metaSpaces;

View file

@ -31,7 +31,7 @@ describe("VoiceRecordingStore", () => {
const room1Recording = { destroy: jest.fn() } as unknown as VoiceMessageRecording;
const room2Recording = { destroy: jest.fn() } as unknown as VoiceMessageRecording;
const state = {
const state: Record<string, VoiceMessageRecording | undefined> = {
[room1Id]: room1Recording,
[room2Id]: room2Recording,
[room3Id]: undefined,

View file

@ -13,7 +13,9 @@ 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 { mocked } from "jest-mock";
import { Room } from "matrix-js-sdk/src/models/room";
import { SpaceWatcher } from "../../../src/stores/room-list/SpaceWatcher";
import type { RoomListStoreClass } from "../../../src/stores/room-list/RoomListStore";
@ -30,8 +32,8 @@ import DMRoomMap from "../../../src/utils/DMRoomMap";
let filter: SpaceFilterCondition = null;
const mockRoomListStore = {
addFilter: (f) => (filter = f),
removeFilter: () => (filter = null),
addFilter: (f: SpaceFilterCondition) => (filter = f),
removeFilter: (): void => (filter = null),
} as unknown as RoomListStoreClass;
const getUserIdForRoomId = jest.fn();
@ -47,7 +49,7 @@ describe("SpaceWatcher", () => {
const store = SpaceStore.instance;
const client = mocked(MatrixClientPeg.get());
let rooms = [];
let rooms: Room[] = [];
const mkSpaceForRooms = (spaceId: string, children: string[] = []) => mkSpace(client, spaceId, rooms, children);
const setShowAllRooms = async (value: boolean) => {

View file

@ -15,17 +15,20 @@ limitations under the License.
*/
import { Room } from "matrix-js-sdk/src/models/room";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import { stubClient, mkRoom, mkMessage } from "../../../test-utils";
import { mkMessage, mkRoom, stubClient } from "../../../test-utils";
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
import "../../../../src/stores/room-list/RoomListStore";
import { RecentAlgorithm } from "../../../../src/stores/room-list/algorithms/tag-sorting/RecentAlgorithm";
import { EffectiveMembership } from "../../../../src/utils/membership";
import { makeThreadEvent, mkThread } from "../../../test-utils/threads";
import { DefaultTagID } from "../../../../src/stores/room-list/models";
describe("RecentAlgorithm", () => {
let algorithm;
let cli;
let algorithm: RecentAlgorithm;
let cli: MatrixClient;
beforeEach(() => {
stubClient();
cli = MatrixClientPeg.get();
@ -102,7 +105,7 @@ describe("RecentAlgorithm", () => {
room1.addLiveEvents([evt]);
room2.addLiveEvents([evt2]);
expect(algorithm.sortRooms([room2, room1])).toEqual([room1, room2]);
expect(algorithm.sortRooms([room2, room1], DefaultTagID.Untagged)).toEqual([room1, room2]);
});
it("orders rooms without messages first", () => {
@ -122,7 +125,7 @@ describe("RecentAlgorithm", () => {
room1.addLiveEvents([evt]);
expect(algorithm.sortRooms([room2, room1])).toEqual([room2, room1]);
expect(algorithm.sortRooms([room2, room1], DefaultTagID.Untagged)).toEqual([room2, room1]);
const { events } = mkThread({
room: room1,
@ -162,21 +165,21 @@ describe("RecentAlgorithm", () => {
});
room2.addLiveEvents(events2);
expect(algorithm.sortRooms([room1, room2])).toEqual([room2, room1]);
expect(algorithm.sortRooms([room1, room2], DefaultTagID.Untagged)).toEqual([room2, room1]);
const threadReply = makeThreadEvent({
user: "@bob:matrix.org",
room: room1.roomId,
event: true,
msg: `hello world`,
rootEventId: rootEvent.getId(),
replyToEventId: rootEvent.getId(),
rootEventId: rootEvent.getId()!,
replyToEventId: rootEvent.getId()!,
// replies are 1ms after each other
ts: 50,
});
room1.addLiveEvents([threadReply]);
expect(algorithm.sortRooms([room1, room2])).toEqual([room1, room2]);
expect(algorithm.sortRooms([room1, room2], DefaultTagID.Untagged)).toEqual([room1, room2]);
});
});
});

View file

@ -20,7 +20,7 @@ import { Room } from "matrix-js-sdk/src/matrix";
import SettingsStore from "../../../../src/settings/SettingsStore";
import { FILTER_CHANGED } from "../../../../src/stores/room-list/filters/IFilterCondition";
import { SpaceFilterCondition } from "../../../../src/stores/room-list/filters/SpaceFilterCondition";
import { MetaSpace } from "../../../../src/stores/spaces";
import { MetaSpace, SpaceKey } from "../../../../src/stores/spaces";
import SpaceStore from "../../../../src/stores/spaces/SpaceStore";
jest.mock("../../../../src/settings/SettingsStore");
@ -50,8 +50,8 @@ describe("SpaceFilterCondition", () => {
const user2Id = "@u2:server";
const user3Id = "@u3:server";
const makeMockGetValue =
(settings = {}) =>
(settingName, space) =>
(settings: Record<string, any> = {}) =>
(settingName: string, space: SpaceKey) =>
settings[settingName]?.[space] || false;
beforeEach(() => {
@ -61,7 +61,7 @@ describe("SpaceFilterCondition", () => {
SpaceStoreInstanceMock.isRoomInSpace.mockReturnValue(true);
});
const initFilter = (space): SpaceFilterCondition => {
const initFilter = (space: SpaceKey): SpaceFilterCondition => {
const filter = new SpaceFilterCondition();
filter.updateSpace(space);
jest.runOnlyPendingTimers();

View file

@ -130,7 +130,7 @@ describe("StopGapWidgetDriver", () => {
const aliceMobile = new DeviceInfo("aliceMobile");
const bobDesktop = new DeviceInfo("bobDesktop");
mocked(client.crypto.deviceList).downloadKeys.mockResolvedValue({
mocked(client.crypto!.deviceList).downloadKeys.mockResolvedValue({
"@alice:example.org": { aliceWeb, aliceMobile },
"@bob:example.org": { bobDesktop },
});

View file

@ -38,7 +38,7 @@ describe("WidgetPermissionStore", () => {
type: "m.custom",
url: "https://invalid.address.here",
});
let settings = {}; // key value store
let settings: Record<string, any> = {}; // key value store
beforeEach(() => {
settings = {}; // clear settings

View file

@ -165,7 +165,7 @@ export const mockGeolocation = (): MockedObject<Geolocation> => {
* See for error codes: https://developer.mozilla.org/en-US/docs/Web/API/GeolocationPositionError
*/
export const watchPositionMockImplementation = (delays: number[], errorCodes: number[] = []) => {
return (callback: PositionCallback, error: PositionErrorCallback) => {
return (callback: PositionCallback, error: PositionErrorCallback): number => {
const position = makeGeolocationPosition({});
let totalDelay = 0;
@ -180,6 +180,8 @@ export const watchPositionMockImplementation = (delays: number[], errorCodes: nu
}, totalDelay);
return timeout;
});
return totalDelay;
};
};

View file

@ -24,12 +24,12 @@ export const addTextToComposer = (container: HTMLElement, text: string) =>
act(() => {
// couldn't get input event on contenteditable to work
// paste works without illegal private method access
const pasteEvent = {
const pasteEvent: Partial<ClipboardEvent> = {
clipboardData: {
types: [],
files: [],
getData: (type) => (type === "text/plain" ? text : undefined),
},
getData: (type: string) => (type === "text/plain" ? text : undefined),
} as unknown as DataTransfer,
};
fireEvent.paste(container.querySelector('[role="textbox"]'), pasteEvent);
});
@ -38,12 +38,12 @@ export const addTextToComposerEnzyme = (wrapper: ReactWrapper, text: string) =>
act(() => {
// couldn't get input event on contenteditable to work
// paste works without illegal private method access
const pasteEvent = {
const pasteEvent: Partial<ClipboardEvent> = {
clipboardData: {
types: [],
files: [],
getData: (type) => (type === "text/plain" ? text : undefined),
},
getData: (type: string) => (type === "text/plain" ? text : undefined),
} as unknown as DataTransfer,
};
wrapper.find('[role="textbox"]').simulate("paste", pasteEvent);
wrapper.update();

View file

@ -89,13 +89,14 @@ export const makePollEndEvent = (pollStartEventId: string, roomId: string, sende
* @returns
*/
export const setupRoomWithPollEvents = async (
mxEvent: MatrixEvent,
pollStartEvents: MatrixEvent[],
relationEvents: Array<MatrixEvent>,
endEvents: Array<MatrixEvent> = [],
mockClient: Mocked<MatrixClient>,
existingRoom?: Room,
): Promise<Room> => {
const room = new Room(mxEvent.getRoomId()!, mockClient, mockClient.getSafeUserId());
room.processPollEvents([mxEvent, ...relationEvents, ...endEvents]);
const room = existingRoom || new Room(pollStartEvents[0].getRoomId()!, mockClient, mockClient.getSafeUserId());
room.processPollEvents([...pollStartEvents, ...relationEvents, ...endEvents]);
// set redaction allowed for current user only
// poll end events are validated against this
@ -106,8 +107,10 @@ export const setupRoomWithPollEvents = async (
// wait for events to process on room
await flushPromises();
mockClient.getRoom.mockReturnValue(room);
mockClient.relations.mockResolvedValue({
events: [...relationEvents, ...endEvents],
mockClient.relations.mockImplementation(async (_roomId: string, eventId: string) => {
return {
events: [...relationEvents, ...endEvents].filter((event) => event.getRelation()?.event_id === eventId),
};
});
return room;
};

View file

@ -86,6 +86,7 @@ export function getRoomContext(room: Room, override: Partial<IRoomState>): IRoom
resizing: false,
narrow: false,
activeCall: null,
msc3946ProcessDynamicPredecessor: false,
...override,
};

View file

@ -69,12 +69,12 @@ export const makeThreadEvents = ({
ts,
});
const rootEventId = rootEvent.getId();
const rootEventId = rootEvent.getId()!;
const events = [rootEvent];
for (let i = 1; i < length; i++) {
const prevEvent = events[i - 1];
const replyToEventId = prevEvent.getId();
const replyToEventId = prevEvent.getId()!;
const user = participantUserIds[i % participantUserIds.length];
events.push(
makeThreadEvent({
@ -95,7 +95,7 @@ export const makeThreadEvents = ({
[RelationType.Thread]: {
latest_event: events[events.length - 1],
count: length,
current_user_participated: [...participantUserIds, authorId].includes(currentUserId),
current_user_participated: [...participantUserIds, authorId].includes(currentUserId!),
},
},
});
@ -126,7 +126,7 @@ export const mkThread = ({
participantUserIds,
length,
ts,
currentUserId: client.getUserId(),
currentUserId: client.getUserId()!,
});
expect(rootEvent).toBeTruthy();
@ -134,7 +134,7 @@ export const mkThread = ({
room?.reEmitter.reEmit(evt, [MatrixEventEvent.BeforeRedaction]);
}
const thread = room.createThread(rootEvent.getId(), rootEvent, events, true);
const thread = room.createThread(rootEvent.getId()!, rootEvent, events, true);
// So that we do not have to mock the thread loading
thread.initialEventsFetched = true;

View file

@ -47,7 +47,7 @@ export function untilDispatch(
const callback = waitForAction as (payload: ActionPayload) => boolean;
return new Promise((resolve, reject) => {
let fulfilled = false;
let timeoutId;
let timeoutId: number;
// set a timeout handler if needed
if (timeout > 0) {
timeoutId = window.setTimeout(() => {
@ -95,7 +95,7 @@ export function untilEmission(
const callerLine = new Error().stack.toString().split("\n")[2];
return new Promise((resolve, reject) => {
let fulfilled = false;
let timeoutId;
let timeoutId: number;
// set a timeout handler if needed
if (timeout > 0) {
timeoutId = window.setTimeout(() => {

View file

@ -26,7 +26,7 @@ type WrapperProps<T> = { wrappedRef?: RefCallback<ComponentType<T>> } & T;
export function wrapInMatrixClientContext<T>(WrappedComponent: ComponentType<T>): ComponentType<WrapperProps<T>> {
class Wrapper extends React.Component<WrapperProps<T>> {
_matrixClient: MatrixClient;
constructor(props) {
constructor(props: WrapperProps<T>) {
super(props);
this._matrixClient = peg.get();

View file

@ -18,33 +18,29 @@ import { setTheme } from "../src/theme";
describe("theme", () => {
describe("setTheme", () => {
let lightTheme;
let darkTheme;
let lightTheme: HTMLStyleElement;
let darkTheme: HTMLStyleElement;
let spyQuerySelectorAll: jest.MockInstance<NodeListOf<Element>, [selectors: string]>;
beforeEach(() => {
const styles = [
{
attributes: {
"data-mx-theme": {
value: "light",
},
dataset: {
mxTheme: "light",
},
disabled: true,
href: "urlLight",
onload: () => void 0,
},
onload: (): void => void 0,
} as unknown as HTMLStyleElement,
{
attributes: {
"data-mx-theme": {
value: "dark",
},
dataset: {
mxTheme: "dark",
},
disabled: true,
href: "urlDark",
onload: () => void 0,
},
onload: (): void => void 0,
} as unknown as HTMLStyleElement,
];
lightTheme = styles[0];
darkTheme = styles[1];
@ -62,7 +58,7 @@ describe("theme", () => {
// When
await new Promise((resolve) => {
setTheme("light").then(resolve);
lightTheme.onload();
lightTheme.onload(void 0);
});
// Then

View file

@ -0,0 +1,54 @@
/*
Copyright 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 { mocked, Mocked } from "jest-mock";
import { EventType, IContent, MatrixClient } from "matrix-js-sdk/src/matrix";
import DMRoomMap from "../../src/utils/DMRoomMap";
import { mkEvent, stubClient } from "../test-utils";
describe("DMRoomMap", () => {
const roomId1 = "!room1:example.com";
const roomId2 = "!room2:example.com";
const roomId3 = "!room3:example.com";
const roomId4 = "!room4:example.com";
const mDirectContent = {
"user@example.com": [roomId1, roomId2],
"@user:example.com": [roomId1, roomId3, roomId4],
"@user2:example.com": [] as string[],
} satisfies IContent;
let client: Mocked<MatrixClient>;
let dmRoomMap: DMRoomMap;
beforeEach(() => {
client = mocked(stubClient());
const mDirectEvent = mkEvent({
event: true,
type: EventType.Direct,
user: client.getSafeUserId(),
content: mDirectContent,
});
client.getAccountData.mockReturnValue(mDirectEvent);
dmRoomMap = new DMRoomMap(client);
});
it("getRoomIds should return the room Ids", () => {
expect(dmRoomMap.getRoomIds()).toEqual(new Set([roomId1, roomId2, roomId3, roomId4]));
});
});

View file

@ -42,7 +42,7 @@ describe("formatSeconds", () => {
});
describe("formatRelativeTime", () => {
let dateSpy;
let dateSpy: jest.SpyInstance<number, []>;
beforeAll(() => {
dateSpy = jest
.spyOn(global.Date, "now")

View file

@ -432,7 +432,7 @@ describe("EventUtils", () => {
stubClient();
client = MatrixClientPeg.get();
room = new Room(ROOM_ID, client, client.getUserId(), {
room = new Room(ROOM_ID, client, client.getUserId()!, {
pendingEventOrdering: PendingEventOrdering.Detached,
});

Some files were not shown because too many files have changed in this diff Show more