Merge remote-tracking branch 'origin/develop' into feat/emoji-picker-rich-text-mode

This commit is contained in:
Florian Duros 2022-12-06 16:38:46 +01:00
commit 1bd560d350
No known key found for this signature in database
GPG key ID: 9700AA5870258A0B
39 changed files with 805 additions and 125 deletions

View file

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

View file

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

View file

@ -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';

View file

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

View file

@ -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>
`;

View file

@ -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', () => ({