Merge remote-tracking branch 'origin/develop' into feat/emoji-picker-rich-text-mode
This commit is contained in:
commit
1bd560d350
39 changed files with 805 additions and 125 deletions
|
@ -38,6 +38,7 @@ describe("<ForgotPassword>", () => {
|
|||
let client: MatrixClient;
|
||||
let serverConfig: ValidatedServerConfig;
|
||||
let onComplete: () => void;
|
||||
let onLoginClick: () => void;
|
||||
let renderResult: RenderResult;
|
||||
let restoreConsole: () => void;
|
||||
|
||||
|
@ -49,9 +50,16 @@ describe("<ForgotPassword>", () => {
|
|||
});
|
||||
};
|
||||
|
||||
const submitForm = async (submitLabel: string): Promise<void> => {
|
||||
const clickButton = async (label: string): Promise<void> => {
|
||||
await act(async () => {
|
||||
await userEvent.click(screen.getByText(submitLabel), { delay: null });
|
||||
await userEvent.click(screen.getByText(label), { delay: null });
|
||||
});
|
||||
};
|
||||
|
||||
const itShouldCloseTheDialogAndShowThePasswordInput = (): void => {
|
||||
it("should close the dialog and show the password input", () => {
|
||||
expect(screen.queryByText("Verify your email to continue")).not.toBeInTheDocument();
|
||||
expect(screen.getByText("Reset your password")).toBeInTheDocument();
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -70,6 +78,7 @@ describe("<ForgotPassword>", () => {
|
|||
serverConfig.hsName = "example.com";
|
||||
|
||||
onComplete = jest.fn();
|
||||
onLoginClick = jest.fn();
|
||||
|
||||
jest.spyOn(AutoDiscoveryUtils, "validateServerConfigWithStaticUrls").mockResolvedValue(serverConfig);
|
||||
jest.spyOn(AutoDiscoveryUtils, "authComponentStateForError");
|
||||
|
@ -94,6 +103,7 @@ describe("<ForgotPassword>", () => {
|
|||
renderResult = render(<ForgotPassword
|
||||
serverConfig={serverConfig}
|
||||
onComplete={onComplete}
|
||||
onLoginClick={onLoginClick}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -108,6 +118,7 @@ describe("<ForgotPassword>", () => {
|
|||
renderResult.rerender(<ForgotPassword
|
||||
serverConfig={serverConfig}
|
||||
onComplete={onComplete}
|
||||
onLoginClick={onLoginClick}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -116,6 +127,16 @@ describe("<ForgotPassword>", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("when clicking »Sign in instead«", () => {
|
||||
beforeEach(async () => {
|
||||
await clickButton("Sign in instead");
|
||||
});
|
||||
|
||||
it("should call onLoginClick()", () => {
|
||||
expect(onLoginClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when entering a non-email value", () => {
|
||||
beforeEach(async () => {
|
||||
await typeIntoField("Email address", "not en email");
|
||||
|
@ -132,7 +153,7 @@ describe("<ForgotPassword>", () => {
|
|||
mocked(client).requestPasswordEmailToken.mockRejectedValue({
|
||||
errcode: "M_THREEPID_NOT_FOUND",
|
||||
});
|
||||
await submitForm("Send email");
|
||||
await clickButton("Send email");
|
||||
});
|
||||
|
||||
it("should show an email not found message", () => {
|
||||
|
@ -146,7 +167,7 @@ describe("<ForgotPassword>", () => {
|
|||
mocked(client).requestPasswordEmailToken.mockRejectedValue({
|
||||
name: "ConnectionError",
|
||||
});
|
||||
await submitForm("Send email");
|
||||
await clickButton("Send email");
|
||||
});
|
||||
|
||||
it("should show an info about that", () => {
|
||||
|
@ -166,7 +187,7 @@ describe("<ForgotPassword>", () => {
|
|||
serverIsAlive: false,
|
||||
serverDeadError: "server down",
|
||||
});
|
||||
await submitForm("Send email");
|
||||
await clickButton("Send email");
|
||||
});
|
||||
|
||||
it("should show the server error", () => {
|
||||
|
@ -180,7 +201,7 @@ describe("<ForgotPassword>", () => {
|
|||
mocked(client).requestPasswordEmailToken.mockResolvedValue({
|
||||
sid: testSid,
|
||||
});
|
||||
await submitForm("Send email");
|
||||
await clickButton("Send email");
|
||||
});
|
||||
|
||||
it("should send the mail and show the check email view", () => {
|
||||
|
@ -193,6 +214,16 @@ describe("<ForgotPassword>", () => {
|
|||
expect(screen.getByText(testEmail)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe("when clicking re-enter email", () => {
|
||||
beforeEach(async () => {
|
||||
await clickButton("Re-enter email address");
|
||||
});
|
||||
|
||||
it("go back to the email input", () => {
|
||||
expect(screen.queryByText("Enter your email to reset password")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when clicking resend email", () => {
|
||||
beforeEach(async () => {
|
||||
await userEvent.click(screen.getByText("Resend"), { delay: null });
|
||||
|
@ -212,7 +243,7 @@ describe("<ForgotPassword>", () => {
|
|||
|
||||
describe("when clicking next", () => {
|
||||
beforeEach(async () => {
|
||||
await submitForm("Next");
|
||||
await clickButton("Next");
|
||||
});
|
||||
|
||||
it("should show the password input view", () => {
|
||||
|
@ -246,7 +277,7 @@ describe("<ForgotPassword>", () => {
|
|||
retry_after_ms: (13 * 60 + 37) * 1000,
|
||||
},
|
||||
});
|
||||
await submitForm("Reset password");
|
||||
await clickButton("Reset password");
|
||||
});
|
||||
|
||||
it("should show the rate limit error message", () => {
|
||||
|
@ -258,7 +289,7 @@ describe("<ForgotPassword>", () => {
|
|||
|
||||
describe("and submitting it", () => {
|
||||
beforeEach(async () => {
|
||||
await submitForm("Reset password");
|
||||
await clickButton("Reset password");
|
||||
// double flush promises for the modal to appear
|
||||
await flushPromisesWithFakeTimers();
|
||||
await flushPromisesWithFakeTimers();
|
||||
|
@ -284,6 +315,46 @@ describe("<ForgotPassword>", () => {
|
|||
expect(screen.getByText(testEmail)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe("and dismissing the dialog by clicking the background", () => {
|
||||
beforeEach(async () => {
|
||||
await act(async () => {
|
||||
await userEvent.click(screen.getByTestId("dialog-background"), { delay: null });
|
||||
});
|
||||
// double flush promises for the modal to disappear
|
||||
await flushPromisesWithFakeTimers();
|
||||
await flushPromisesWithFakeTimers();
|
||||
});
|
||||
|
||||
itShouldCloseTheDialogAndShowThePasswordInput();
|
||||
});
|
||||
|
||||
describe("and dismissing the dialog", () => {
|
||||
beforeEach(async () => {
|
||||
await act(async () => {
|
||||
await userEvent.click(screen.getByLabelText("Close dialog"), { delay: null });
|
||||
});
|
||||
// double flush promises for the modal to disappear
|
||||
await flushPromisesWithFakeTimers();
|
||||
await flushPromisesWithFakeTimers();
|
||||
});
|
||||
|
||||
itShouldCloseTheDialogAndShowThePasswordInput();
|
||||
});
|
||||
|
||||
describe("when clicking re-enter email", () => {
|
||||
beforeEach(async () => {
|
||||
await clickButton("Re-enter email address");
|
||||
// double flush promises for the modal to disappear
|
||||
await flushPromisesWithFakeTimers();
|
||||
await flushPromisesWithFakeTimers();
|
||||
});
|
||||
|
||||
it("should close the dialog and go back to the email input", () => {
|
||||
expect(screen.queryByText("Verify your email to continue")).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("Enter your email to reset password")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when validating the link from the mail", () => {
|
||||
beforeEach(async () => {
|
||||
mocked(client.setPassword).mockResolvedValue({});
|
||||
|
|
|
@ -20,6 +20,7 @@ import React from "react";
|
|||
import {
|
||||
StatelessNotificationBadge,
|
||||
} from "../../../../../src/components/views/rooms/NotificationBadge/StatelessNotificationBadge";
|
||||
import SettingsStore from "../../../../../src/settings/SettingsStore";
|
||||
import { NotificationColor } from "../../../../../src/stores/notifications/NotificationColor";
|
||||
|
||||
describe("NotificationBadge", () => {
|
||||
|
@ -45,5 +46,19 @@ describe("NotificationBadge", () => {
|
|||
fireEvent.mouseLeave(container.firstChild);
|
||||
expect(cb).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
it("hides the bold icon when the settings is set", () => {
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
|
||||
return name === "feature_hidebold";
|
||||
});
|
||||
|
||||
const { container } = render(<StatelessNotificationBadge
|
||||
symbol=""
|
||||
color={NotificationColor.Bold}
|
||||
count={1}
|
||||
/>);
|
||||
|
||||
expect(container.firstChild).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -32,7 +32,7 @@ import RoomListStore, { RoomListStoreClass } from "../../../../src/stores/room-l
|
|||
import RoomListLayoutStore from "../../../../src/stores/room-list/RoomListLayoutStore";
|
||||
import RoomList from "../../../../src/components/views/rooms/RoomList";
|
||||
import RoomSublist from "../../../../src/components/views/rooms/RoomSublist";
|
||||
import RoomTile from "../../../../src/components/views/rooms/RoomTile";
|
||||
import { RoomTile } from "../../../../src/components/views/rooms/RoomTile";
|
||||
import { getMockClientWithEventEmitter, mockClientMethodsUser } from '../../../test-utils';
|
||||
import ResizeNotifier from '../../../../src/utils/ResizeNotifier';
|
||||
|
||||
|
|
|
@ -15,12 +15,13 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import React from "react";
|
||||
import { render, screen, act } from "@testing-library/react";
|
||||
import { render, screen, act, RenderResult } from "@testing-library/react";
|
||||
import { mocked, Mocked } from "jest-mock";
|
||||
import { MatrixClient, PendingEventOrdering } from "matrix-js-sdk/src/client";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
|
||||
import { Widget } from "matrix-widget-api";
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import type { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||
import type { ClientWidgetApi } from "matrix-widget-api";
|
||||
|
@ -30,6 +31,7 @@ import {
|
|||
MockedCall,
|
||||
useMockedCalls,
|
||||
setupAsyncStoreWithClient,
|
||||
filterConsole,
|
||||
} from "../../../test-utils";
|
||||
import { CallStore } from "../../../../src/stores/CallStore";
|
||||
import RoomTile from "../../../../src/components/views/rooms/RoomTile";
|
||||
|
@ -39,38 +41,79 @@ import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
|||
import PlatformPeg from "../../../../src/PlatformPeg";
|
||||
import BasePlatform from "../../../../src/BasePlatform";
|
||||
import { WidgetMessagingStore } from "../../../../src/stores/widgets/WidgetMessagingStore";
|
||||
import { VoiceBroadcastInfoState } from "../../../../src/voice-broadcast";
|
||||
import { mkVoiceBroadcastInfoStateEvent } from "../../../voice-broadcast/utils/test-utils";
|
||||
|
||||
describe("RoomTile", () => {
|
||||
jest.spyOn(PlatformPeg, "get")
|
||||
.mockReturnValue({ overrideBrowserShortcuts: () => false } as unknown as BasePlatform);
|
||||
useMockedCalls();
|
||||
|
||||
const setUpVoiceBroadcast = (state: VoiceBroadcastInfoState): void => {
|
||||
voiceBroadcastInfoEvent = mkVoiceBroadcastInfoStateEvent(
|
||||
room.roomId,
|
||||
state,
|
||||
client.getUserId(),
|
||||
client.getDeviceId(),
|
||||
);
|
||||
|
||||
act(() => {
|
||||
room.currentState.setStateEvents([voiceBroadcastInfoEvent]);
|
||||
});
|
||||
};
|
||||
|
||||
const renderRoomTile = (): void => {
|
||||
renderResult = render(
|
||||
<RoomTile
|
||||
room={room}
|
||||
showMessagePreview={false}
|
||||
isMinimized={false}
|
||||
tag={DefaultTagID.Untagged}
|
||||
/>,
|
||||
);
|
||||
};
|
||||
|
||||
let client: Mocked<MatrixClient>;
|
||||
let restoreConsole: () => void;
|
||||
let voiceBroadcastInfoEvent: MatrixEvent;
|
||||
let room: Room;
|
||||
let renderResult: RenderResult;
|
||||
|
||||
beforeEach(() => {
|
||||
restoreConsole = filterConsole(
|
||||
// irrelevant for this test
|
||||
"Room !1:example.org does not have an m.room.create event",
|
||||
);
|
||||
|
||||
stubClient();
|
||||
client = mocked(MatrixClientPeg.get());
|
||||
DMRoomMap.makeShared();
|
||||
|
||||
room = new Room("!1:example.org", client, "@alice:example.org", {
|
||||
pendingEventOrdering: PendingEventOrdering.Detached,
|
||||
});
|
||||
|
||||
client.getRoom.mockImplementation(roomId => roomId === room.roomId ? room : null);
|
||||
client.getRooms.mockReturnValue([room]);
|
||||
client.reEmitter.reEmit(room, [RoomStateEvent.Events]);
|
||||
|
||||
renderRoomTile();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
restoreConsole();
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe("call subtitle", () => {
|
||||
let room: Room;
|
||||
it("should render the room", () => {
|
||||
expect(renderResult.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when a call starts", () => {
|
||||
let call: MockedCall;
|
||||
let widget: Widget;
|
||||
|
||||
beforeEach(() => {
|
||||
room = new Room("!1:example.org", client, "@alice:example.org", {
|
||||
pendingEventOrdering: PendingEventOrdering.Detached,
|
||||
});
|
||||
|
||||
client.getRoom.mockImplementation(roomId => roomId === room.roomId ? room : null);
|
||||
client.getRooms.mockReturnValue([room]);
|
||||
client.reEmitter.reEmit(room, [RoomStateEvent.Events]);
|
||||
|
||||
setupAsyncStoreWithClient(CallStore.instance, client);
|
||||
setupAsyncStoreWithClient(WidgetMessagingStore.instance, client);
|
||||
|
||||
|
@ -83,18 +126,10 @@ describe("RoomTile", () => {
|
|||
WidgetMessagingStore.instance.storeMessaging(widget, room.roomId, {
|
||||
stop: () => {},
|
||||
} as unknown as ClientWidgetApi);
|
||||
|
||||
render(
|
||||
<RoomTile
|
||||
room={room}
|
||||
showMessagePreview={false}
|
||||
isMinimized={false}
|
||||
tag={DefaultTagID.Untagged}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
renderResult.unmount();
|
||||
call.destroy();
|
||||
client.reEmitter.stopReEmitting(room, [RoomStateEvent.Events]);
|
||||
WidgetMessagingStore.instance.stopMessaging(widget, room.roomId);
|
||||
|
@ -147,5 +182,45 @@ describe("RoomTile", () => {
|
|||
act(() => { call.participants = new Map(); });
|
||||
expect(screen.queryByLabelText(/participant/)).toBe(null);
|
||||
});
|
||||
|
||||
describe("and a live broadcast starts", () => {
|
||||
beforeEach(() => {
|
||||
setUpVoiceBroadcast(VoiceBroadcastInfoState.Started);
|
||||
});
|
||||
|
||||
it("should still render the call subtitle", () => {
|
||||
expect(screen.queryByText("Video")).toBeInTheDocument();
|
||||
expect(screen.queryByText("Live")).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when a live voice broadcast starts", () => {
|
||||
beforeEach(() => {
|
||||
setUpVoiceBroadcast(VoiceBroadcastInfoState.Started);
|
||||
});
|
||||
|
||||
it("should render the »Live« subtitle", () => {
|
||||
expect(screen.queryByText("Live")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe("and the broadcast stops", () => {
|
||||
beforeEach(() => {
|
||||
const stopEvent = mkVoiceBroadcastInfoStateEvent(
|
||||
room.roomId,
|
||||
VoiceBroadcastInfoState.Stopped,
|
||||
client.getUserId(),
|
||||
client.getDeviceId(),
|
||||
voiceBroadcastInfoEvent,
|
||||
);
|
||||
act(() => {
|
||||
room.currentState.setStateEvents([stopEvent]);
|
||||
});
|
||||
});
|
||||
|
||||
it("should not render the »Live« subtitle", () => {
|
||||
expect(screen.queryByText("Live")).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`RoomTile should render the room 1`] = `
|
||||
<div>
|
||||
<div
|
||||
aria-label="!1:example.org Unread messages."
|
||||
aria-selected="false"
|
||||
class="mx_AccessibleButton mx_RoomTile"
|
||||
role="treeitem"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div
|
||||
class="mx_DecoratedRoomAvatar"
|
||||
>
|
||||
<span
|
||||
class="mx_BaseAvatar"
|
||||
role="presentation"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="mx_BaseAvatar_initial"
|
||||
style="font-size: 20.8px; width: 32px; line-height: 32px;"
|
||||
>
|
||||
!
|
||||
</span>
|
||||
<img
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
class="mx_BaseAvatar_image"
|
||||
data-testid="avatar-img"
|
||||
src="data:image/png;base64,00"
|
||||
style="width: 32px; height: 32px;"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="mx_RoomTile_titleContainer"
|
||||
>
|
||||
<div
|
||||
class="mx_RoomTile_title mx_RoomTile_titleHasUnreadEvents"
|
||||
tabindex="-1"
|
||||
title="!1:example.org"
|
||||
>
|
||||
<span
|
||||
dir="auto"
|
||||
>
|
||||
!1:example.org
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="mx_RoomTile_badgeContainer"
|
||||
>
|
||||
<div
|
||||
class="mx_NotificationBadge mx_NotificationBadge_visible mx_NotificationBadge_dot"
|
||||
>
|
||||
<span
|
||||
class="mx_NotificationBadge_count"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-label="Room options"
|
||||
class="mx_AccessibleButton mx_RoomTile_menuButton"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
/>
|
||||
<div
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
aria-label="Notification options"
|
||||
class="mx_AccessibleButton mx_RoomTile_notificationsButton"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -38,6 +38,7 @@ jest.mock('../../../../src/settings/SettingsStore', () => ({
|
|||
setValue: jest.fn(),
|
||||
getValue: jest.fn(),
|
||||
monitorSetting: jest.fn(),
|
||||
watchSetting: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../../../src/dispatcher/dispatcher', () => ({
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue