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

@ -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({});