Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Migrate some tests to React Testing Library (#9584)
Browse files Browse the repository at this point in the history
  • Loading branch information
Germain authored Nov 18, 2022
1 parent ef548a4 commit 38dbe8e
Show file tree
Hide file tree
Showing 12 changed files with 315 additions and 517 deletions.
1 change: 1 addition & 0 deletions src/components/structures/SearchBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ export default class SearchBox extends React.Component<IProps, IState> {
placeholder={this.state.blurred ? (blurredPlaceholder || placeholder) : placeholder}
autoComplete="off"
autoFocus={this.props.autoFocus}
data-testid="searchbox-input"
/>
{ clearButton }
</div>
Expand Down
117 changes: 55 additions & 62 deletions test/components/views/dialogs/ForwardDialog-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ limitations under the License.
*/

import React from "react";
// eslint-disable-next-line deprecate/import
import { mount, ReactWrapper } from "enzyme";
import { act } from "react-dom/test-utils";
import { MatrixEvent, EventType } from "matrix-js-sdk/src/matrix";
import { LocationAssetType, M_ASSET, M_LOCATION, M_TIMESTAMP } from "matrix-js-sdk/src/@types/location";
import { TEXT_NODE_TYPE } from "matrix-js-sdk/src/@types/extensible_events";
import { fireEvent, getByTestId, render, RenderResult, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
import ForwardDialog from "../../../../src/components/views/dialogs/ForwardDialog";
Expand All @@ -34,6 +34,7 @@ import {
mkEvent,
mkMessage,
mkStubRoom,
mockPlatformPeg,
} from "../../../test-utils";
import { TILE_SERVER_WK_KEY } from "../../../../src/utils/WellKnownUtils";

Expand Down Expand Up @@ -71,24 +72,18 @@ describe("ForwardDialog", () => {
});
const defaultRooms = ["a", "A", "b"].map(name => mkStubRoom(name, name, mockClient));

const mountForwardDialog = async (message = defaultMessage, rooms = defaultRooms) => {
const mountForwardDialog = (message = defaultMessage, rooms = defaultRooms) => {
mockClient.getVisibleRooms.mockReturnValue(rooms);
mockClient.getRoom.mockImplementation(roomId => rooms.find(room => room.roomId === roomId));

let wrapper;
await act(async () => {
wrapper = mount(
<ForwardDialog
matrixClient={mockClient}
event={message}
permalinkCreator={new RoomPermalinkCreator(undefined, sourceRoom)}
onFinished={jest.fn()}
/>,
);
// Wait one tick for our profile data to load so the state update happens within act
await new Promise(resolve => setImmediate(resolve));
});
wrapper.update();
const wrapper: RenderResult = render(
<ForwardDialog
matrixClient={mockClient}
event={message}
permalinkCreator={new RoomPermalinkCreator(undefined, sourceRoom)}
onFinished={jest.fn()}
/>,
);

return wrapper;
};
Expand All @@ -105,30 +100,29 @@ describe("ForwardDialog", () => {
});

it("shows a preview with us as the sender", async () => {
const wrapper = await mountForwardDialog();
const { container } = mountForwardDialog();

const previewBody = wrapper.find(".mx_EventTile_body");
expect(previewBody.text()).toBe("Hello world!");
expect(screen.queryByText("Hello world!")).toBeInTheDocument();

// We would just test SenderProfile for the user ID, but it's stubbed
const previewAvatar = wrapper.find(".mx_EventTile_avatar .mx_BaseAvatar_image");
expect(previewAvatar.prop("title")).toBe("@bob:example.org");
const previewAvatar = container.querySelector(".mx_EventTile_avatar .mx_BaseAvatar_image");
expect(previewAvatar?.getAttribute("title")).toBe("@bob:example.org");
});

it("filters the rooms", async () => {
const wrapper = await mountForwardDialog();
const { container } = mountForwardDialog();

expect(wrapper.find("Entry")).toHaveLength(3);
expect(container.querySelectorAll(".mx_ForwardList_entry")).toHaveLength(3);

const searchInput = wrapper.find("SearchBox input");
searchInput.instance().value = "a";
searchInput.simulate("change");
const searchInput = getByTestId(container, "searchbox-input");
act(() => userEvent.type(searchInput, "a"));

expect(wrapper.find("Entry")).toHaveLength(2);
expect(container.querySelectorAll(".mx_ForwardList_entry")).toHaveLength(3);
});

it("tracks message sending progress across multiple rooms", async () => {
const wrapper = await mountForwardDialog();
mockPlatformPeg();
const { container } = mountForwardDialog();

// Make sendEvent require manual resolution so we can see the sending state
let finishSend;
Expand All @@ -141,39 +135,37 @@ describe("ForwardDialog", () => {
let firstButton;
let secondButton;
const update = () => {
wrapper.update();
firstButton = wrapper.find("AccessibleButton.mx_ForwardList_sendButton").first();
secondButton = wrapper.find("AccessibleButton.mx_ForwardList_sendButton").at(1);
[firstButton, secondButton] = container.querySelectorAll(".mx_ForwardList_sendButton");
};
update();

expect(firstButton.is(".mx_ForwardList_canSend")).toBe(true);
expect(firstButton.className).toContain("mx_ForwardList_canSend");

act(() => { firstButton.simulate("click"); });
act(() => { fireEvent.click(firstButton); });
update();
expect(firstButton.is(".mx_ForwardList_sending")).toBe(true);
expect(firstButton.className).toContain("mx_ForwardList_sending");

await act(async () => {
cancelSend();
// Wait one tick for the button to realize the send failed
await new Promise(resolve => setImmediate(resolve));
});
update();
expect(firstButton.is(".mx_ForwardList_sendFailed")).toBe(true);
expect(firstButton.className).toContain("mx_ForwardList_sendFailed");

expect(secondButton.is(".mx_ForwardList_canSend")).toBe(true);
expect(secondButton.className).toContain("mx_ForwardList_canSend");

act(() => { secondButton.simulate("click"); });
act(() => { fireEvent.click(secondButton); });
update();
expect(secondButton.is(".mx_ForwardList_sending")).toBe(true);
expect(secondButton.className).toContain("mx_ForwardList_sending");

await act(async () => {
finishSend();
// Wait one tick for the button to realize the send succeeded
await new Promise(resolve => setImmediate(resolve));
});
update();
expect(secondButton.is(".mx_ForwardList_sent")).toBe(true);
expect(secondButton.className).toContain("mx_ForwardList_sent");
});

it("can render replies", async () => {
Expand All @@ -193,21 +185,22 @@ describe("ForwardDialog", () => {
event: true,
});

const wrapper = await mountForwardDialog(replyMessage);
expect(wrapper.find("ReplyChain")).toBeTruthy();
mountForwardDialog(replyMessage);

expect(screen.queryByText("Hi Alice!", { exact: false })).toBeInTheDocument();
});

it("disables buttons for rooms without send permissions", async () => {
const readOnlyRoom = mkStubRoom("a", "a", mockClient);
readOnlyRoom.maySendMessage = jest.fn().mockReturnValue(false);
const rooms = [readOnlyRoom, mkStubRoom("b", "b", mockClient)];

const wrapper = await mountForwardDialog(undefined, rooms);
const { container } = mountForwardDialog(undefined, rooms);

const [firstButton, secondButton] = container.querySelectorAll<HTMLButtonElement>(".mx_ForwardList_sendButton");

const firstButton = wrapper.find("AccessibleButton.mx_ForwardList_sendButton").first();
expect(firstButton.prop("disabled")).toBe(true);
const secondButton = wrapper.find("AccessibleButton.mx_ForwardList_sendButton").last();
expect(secondButton.prop("disabled")).toBe(false);
expect(firstButton.getAttribute("aria-disabled")).toBeTruthy();
expect(secondButton.getAttribute("aria-disabled")).toBeFalsy();
});

describe('Location events', () => {
Expand All @@ -229,17 +222,17 @@ describe("ForwardDialog", () => {
jest.spyOn(Date, 'now').mockRestore();
});

const sendToFirstRoom = (wrapper: ReactWrapper): void =>
const sendToFirstRoom = (container: HTMLElement): void =>
act(() => {
const sendToFirstRoomButton = wrapper.find("AccessibleButton.mx_ForwardList_sendButton").first();
sendToFirstRoomButton.simulate("click");
const sendToFirstRoomButton = container.querySelector(".mx_ForwardList_sendButton");
fireEvent.click(sendToFirstRoomButton!);
});

it('converts legacy location events to pin drop shares', async () => {
const wrapper = await mountForwardDialog(legacyLocationEvent);
const { container } = mountForwardDialog(legacyLocationEvent);

expect(wrapper.find('MLocationBody').length).toBeTruthy();
sendToFirstRoom(wrapper);
expect(container.querySelector(".mx_MLocationBody")).toBeTruthy();
sendToFirstRoom(container);

// text and description from original event are removed
// text gets new default message from event values
Expand All @@ -262,10 +255,10 @@ describe("ForwardDialog", () => {
});

it('removes personal information from static self location shares', async () => {
const wrapper = await mountForwardDialog(modernLocationEvent);
const { container } = mountForwardDialog(modernLocationEvent);

expect(wrapper.find('MLocationBody').length).toBeTruthy();
sendToFirstRoom(wrapper);
expect(container.querySelector(".mx_MLocationBody")).toBeTruthy();
sendToFirstRoom(container);

const timestamp = M_TIMESTAMP.findIn<number>(modernLocationEvent.getContent());
// text and description from original event are removed
Expand Down Expand Up @@ -302,23 +295,23 @@ describe("ForwardDialog", () => {
geo_uri: geoUri,
[M_TIMESTAMP.name]: timestamp,
};
const wrapper = await mountForwardDialog(beaconEvent);
const { container } = mountForwardDialog(beaconEvent);

expect(wrapper.find('MLocationBody').length).toBeTruthy();
expect(container.querySelector(".mx_MLocationBody")).toBeTruthy();

sendToFirstRoom(wrapper);
sendToFirstRoom(container);

expect(mockClient.sendEvent).toHaveBeenCalledWith(
roomId, EventType.RoomMessage, expectedContent,
);
});

it('forwards pin drop event', async () => {
const wrapper = await mountForwardDialog(pinDropLocationEvent);
const { container } = mountForwardDialog(pinDropLocationEvent);

expect(wrapper.find('MLocationBody').length).toBeTruthy();
expect(container.querySelector(".mx_MLocationBody")).toBeTruthy();

sendToFirstRoom(wrapper);
sendToFirstRoom(container);

expect(mockClient.sendEvent).toHaveBeenCalledWith(
roomId, pinDropLocationEvent.getType(), pinDropLocationEvent.getContent(),
Expand Down
17 changes: 9 additions & 8 deletions test/components/views/messages/MVideoBody-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@ limitations under the License.
*/

import React from 'react';
// eslint-disable-next-line deprecate/import
import { mount, ReactWrapper } from "enzyme";
import { MatrixEvent } from 'matrix-js-sdk/src/matrix';
import { render, RenderResult } from '@testing-library/react';

import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
import { RoomPermalinkCreator } from "../../../../src/utils/permalinks/Permalinks";
Expand All @@ -36,12 +35,13 @@ describe("MVideoBody", () => {
it('does not crash when given a portrait image', () => {
// Check for an unreliable crash caused by a fractional-sized
// image dimension being used for a CanvasImageData.
expect(makeMVideoBody(720, 1280).html()).toMatchSnapshot();
const { asFragment } = makeMVideoBody(720, 1280);
expect(asFragment()).toMatchSnapshot();
// If we get here, we did not crash.
});
});

function makeMVideoBody(w: number, h: number): ReactWrapper<any, Readonly<{}>, MVideoBody> {
function makeMVideoBody(w: number, h: number): RenderResult {
const content = {
info: {
"w": w,
Expand Down Expand Up @@ -79,8 +79,9 @@ function makeMVideoBody(w: number, h: number): ReactWrapper<any, Readonly<{}>, M
mxcUrlToHttp: jest.fn(),
});

return mount(<MVideoBody {...defaultProps} />, {
wrappingComponent: MatrixClientContext.Provider,
wrappingComponentProps: { value: mockClient },
});
return render(
<MatrixClientContext.Provider value={mockClient}>
<MVideoBody {...defaultProps} />
</MatrixClientContext.Provider>,
);
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`MVideoBody does not crash when given a portrait image 1`] = `"<span class="mx_MVideoBody"><div class="mx_MVideoBody_container" style="max-width: 182px; max-height: 324px;"><video class="mx_MVideoBody" controls="" controlslist="nodownload" preload="none" poster="data:image/png;base64,00"></video><div style="width: 182px; height: 324px;"></div></div></span>"`;
exports[`MVideoBody does not crash when given a portrait image 1`] = `
<DocumentFragment>
<span
class="mx_MVideoBody"
>
<div
class="mx_MVideoBody_container"
style="max-width: 182px; max-height: 324px;"
>
<video
class="mx_MVideoBody"
controls=""
controlslist="nodownload"
poster="data:image/png;base64,00"
preload="none"
/>
<div
style="width: 182px; height: 324px;"
/>
</div>
</span>
</DocumentFragment>
`;
Loading

0 comments on commit 38dbe8e

Please sign in to comment.