Skip to content
42 changes: 28 additions & 14 deletions playwright/e2e/timeline/timeline.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -908,23 +908,37 @@ test.describe("Timeline", () => {
});
});

test("should be able to hide an image", { tag: "@screenshot" }, async ({ page, app, room, context }) => {
await app.viewRoomById(room.roomId);
await sendImage(app.client, room.roomId, NEW_AVATAR);
await app.timeline.scrollToBottom();
const imgTile = page.locator(".mx_MImageBody").first();
await expect(imgTile).toBeVisible();
await imgTile.hover();
await page.getByRole("button", { name: "Hide" }).click();
test(
"should be able to hide an image",
{ tag: "@screenshot" },
async ({ page, app, homeserver, room, context }) => {
await app.viewRoomById(room.roomId);

// Check that the image is now hidden.
await expect(page.getByRole("button", { name: "Show image" })).toBeVisible();
});
const bot = new Bot(page, homeserver, {});
await bot.prepareClient();
await app.client.inviteUser(room.roomId, bot.credentials.userId);

test("should be able to hide a video", async ({ page, app, room, context }) => {
await sendImage(bot, room.roomId, NEW_AVATAR);
await app.timeline.scrollToBottom();
const imgTile = page.locator(".mx_MImageBody").first();
await expect(imgTile).toBeVisible();
await imgTile.hover();
await page.getByRole("button", { name: "Hide" }).click();

// Check that the image is now hidden.
await expect(page.getByRole("button", { name: "Show image" })).toBeVisible();
},
);

test("should be able to hide a video", async ({ page, app, homeserver, room, context }) => {
await app.viewRoomById(room.roomId);
const upload = await app.client.uploadContent(VIDEO_FILE, { name: "bbb.webm", type: "video/webm" });
await app.client.sendEvent(room.roomId, null, "m.room.message" as EventType, {

const bot = new Bot(page, homeserver, {});
await bot.prepareClient();
await app.client.inviteUser(room.roomId, bot.credentials.userId);

const upload = await bot.uploadContent(VIDEO_FILE, { name: "bbb.webm", type: "video/webm" });
await bot.sendEvent(room.roomId, null, "m.room.message" as EventType, {
msgtype: "m.video" as MsgType,
body: "bbb.webm",
url: upload.content_uri,
Expand Down
2 changes: 1 addition & 1 deletion src/components/views/messages/EventContentBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ const EventContentBody = memo(
forwardRef<HTMLElement, Props>(
({ as, mxEvent, stripReply, content, linkify, highlights, includeDir = true, ...options }, ref) => {
const enableBigEmoji = useSettingValue("TextualBody.enableBigEmoji");
const [mediaIsVisible] = useMediaVisible(mxEvent?.getId(), mxEvent?.getRoomId());
const [mediaIsVisible] = useMediaVisible(mxEvent);

const replacer = useReplacer(content, mxEvent, options);
const linkifyOptions = useMemo(
Expand Down
4 changes: 2 additions & 2 deletions src/components/views/messages/HideActionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ interface IProps {
* Quick action button for marking a media event as hidden.
*/
export const HideActionButton: React.FC<IProps> = ({ mxEvent }) => {
const [mediaIsVisible, setVisible] = useMediaVisible(mxEvent.getId(), mxEvent.getRoomId());
const [mediaIsVisible, setVisible] = useMediaVisible(mxEvent);

if (!mediaIsVisible) {
if (!mediaIsVisible || !setVisible) {
return;
}

Expand Down
6 changes: 3 additions & 3 deletions src/components/views/messages/MImageBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ interface IProps extends IBodyProps {
* Set the visibility of the media event.
* @param visible Should the event be visible.
*/
setMediaVisible: (visible: boolean) => void;
setMediaVisible?: (visible: boolean) => void;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was always optional an this is just fixing the type? As it seems slightly weird for it to be optional. Could probably do with some doc?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, at the time this was an attempt to make it so that if it was your own media then you wouldn't have a button to hide media. However this has led to a lot of extra code, and I think there might be a valid use case for potentially hiding images you don't want visible on your client.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh right, okay - it just not having the method in that case seems like a slightly weird interface, but not going to block on it

}

/**
Expand Down Expand Up @@ -95,7 +95,7 @@ export class MImageBodyInner extends React.Component<IProps, IState> {
protected onClick = (ev: React.MouseEvent): void => {
if (ev.button === 0 && !ev.metaKey) {
ev.preventDefault();
if (!this.props.mediaVisible) {
if (!this.props.mediaVisible && this.props.setMediaVisible) {
this.props.setMediaVisible(true);
return;
}
Expand Down Expand Up @@ -686,7 +686,7 @@ export class MImageBodyInner extends React.Component<IProps, IState> {

// Wrap MImageBody component so we can use a hook here.
const MImageBody: React.FC<IBodyProps> = (props) => {
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent.getId(), props.mxEvent.getRoomId());
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent);
return <MImageBodyInner mediaVisible={mediaVisible} setMediaVisible={setVisible} {...props} />;
};

Expand Down
2 changes: 1 addition & 1 deletion src/components/views/messages/MImageReplyBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class MImageReplyBodyInner extends MImageBodyInner {
}
}
const MImageReplyBody: React.FC<IBodyProps> = (props) => {
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent.getId(), props.mxEvent.getRoomId());
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent);
return <MImageReplyBodyInner mediaVisible={mediaVisible} setMediaVisible={setVisible} {...props} />;
};

Expand Down
2 changes: 1 addition & 1 deletion src/components/views/messages/MStickerBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class MStickerBodyInner extends MImageBodyInner {
}

const MStickerBody: React.FC<IBodyProps> = (props) => {
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent.getId(), props.mxEvent.getRoomId());
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent);
return <MStickerBodyInner mediaVisible={mediaVisible} setMediaVisible={setVisible} {...props} />;
};

Expand Down
6 changes: 3 additions & 3 deletions src/components/views/messages/MVideoBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ interface IProps extends IBodyProps {
* Set the visibility of the media event.
* @param visible Should the event be visible.
*/
setMediaVisible: (visible: boolean) => void;
setMediaVisible?: (visible: boolean) => void;
}

class MVideoBodyInner extends React.PureComponent<IProps, IState> {
Expand All @@ -64,7 +64,7 @@ class MVideoBodyInner extends React.PureComponent<IProps, IState> {
};

private onClick = (): void => {
this.props.setMediaVisible(true);
this.props.setMediaVisible?.(true);
};

private getContentUrl(): string | undefined {
Expand Down Expand Up @@ -342,7 +342,7 @@ class MVideoBodyInner extends React.PureComponent<IProps, IState> {

// Wrap MVideoBody component so we can use a hook here.
const MVideoBody: React.FC<IBodyProps> = (props) => {
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent.getId(), props.mxEvent.getRoomId());
const [mediaVisible, setVisible] = useMediaVisible(props.mxEvent);
return <MVideoBodyInner mediaVisible={mediaVisible} setMediaVisible={setVisible} {...props} />;
};

Expand Down
2 changes: 1 addition & 1 deletion src/components/views/messages/MessageActionBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ export default class MessageActionBar extends React.PureComponent<IMessageAction
/>,
);
}
if (MediaEventHelper.canHide(this.props.mxEvent)) {
if (MediaEventHelper.canHide(this.props.mxEvent, MatrixClientPeg.safeGet().getSafeUserId())) {
toolbarOpts.splice(0, 0, <HideActionButton mxEvent={this.props.mxEvent} key="hide" />);
}
} else if (
Expand Down
2 changes: 1 addition & 1 deletion src/components/views/rooms/LinkPreviewGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ interface IProps {
const LinkPreviewGroup: React.FC<IProps> = ({ links, mxEvent, onCancelClick }) => {
const cli = useContext(MatrixClientContext);
const [expanded, toggleExpanded] = useStateToggle();
const [mediaVisible] = useMediaVisible(mxEvent.getId(), mxEvent.getRoomId());
const [mediaVisible] = useMediaVisible(mxEvent);

const ts = mxEvent.getTs();
const previews = useAsyncMemo<[string, IPreviewUrlResponse][]>(
Expand Down
15 changes: 10 additions & 5 deletions src/hooks/useMediaVisible.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import { useCallback } from "react";
import { JoinRule } from "matrix-js-sdk/src/matrix";
import { JoinRule, type MatrixEvent } from "matrix-js-sdk/src/matrix";

import { SettingLevel } from "../settings/SettingLevel";
import { useSettingValue } from "./useSettings";
Expand All @@ -19,14 +19,15 @@

/**
* Should the media event be visible in the client, or hidden.
* @param eventId The eventId of the media event.
* @returns A boolean describing the hidden status, and a function to set the visiblity.
*/
export function useMediaVisible(eventId?: string, roomId?: string): [boolean, (visible: boolean) => void] {
const mediaPreviewSetting = useSettingValue("mediaPreviewConfig", roomId);
export function useMediaVisible(mxEvent?: MatrixEvent): [boolean, (visible: boolean) => void] | [true] {
const eventId = mxEvent?.getId();
const mediaPreviewSetting = useSettingValue("mediaPreviewConfig", mxEvent?.getRoomId());
const client = useMatrixClientContext();
const eventVisibility = useSettingValue("showMediaEventIds");
const joinRule = useRoomState(client.getRoom(roomId) ?? undefined, (state) => state.getJoinRule());
const room = client.getRoom(mxEvent?.getRoomId()) ?? undefined;
const joinRule = useRoomState(room, (state) => state.getJoinRule());
const setMediaVisible = useCallback(
(visible: boolean) => {
SettingsStore.setValue("showMediaEventIds", null, SettingLevel.DEVICE, {
Expand All @@ -37,6 +38,10 @@
[eventId, eventVisibility],
);

if (mxEvent?.getSender() === client.getUserId()) {

Check failure on line 41 in src/hooks/useMediaVisible.ts

View workflow job for this annotation

GitHub Actions / Jest (1)

MVideoBody › does not crash when given a portrait image

TypeError: client.getUserId is not a function at getUserId (src/hooks/useMediaVisible.ts:41:41) at MVideoBody (src/components/views/messages/MVideoBody.tsx:345:55) at Object.react-stack-bottom-frame (node_modules/react-dom/cjs/react-dom-client.development.js:23863:20) at renderWithHooks (node_modules/react-dom/cjs/react-dom-client.development.js:5529:22) at updateFunctionComponent (node_modules/react-dom/cjs/react-dom-client.development.js:8897:19) at beginWork (node_modules/react-dom/cjs/react-dom-client.development.js:10522:18) at runWithFiberInDEV (node_modules/react-dom/cjs/react-dom-client.development.js:1522:13) at performUnitOfWork (node_modules/react-dom/cjs/react-dom-client.development.js:15140:22) at workLoopSync (node_modules/react-dom/cjs/react-dom-client.development.js:14956:41) at renderRootSync (node_modules/react-dom/cjs/react-dom-client.development.js:14936:11) at performWorkOnRoot (node_modules/react-dom/cjs/react-dom-client.development.js:14462:44) at performWorkOnRootViaSchedulerTask (node_modules/react-dom/cjs/react-dom-client.development.js:16216:7) at flushActQueue (node_modules/react/cjs/react.development.js:566:34) at Object.<anonymous>.process.env.NODE_ENV.exports.act (node_modules/react/cjs/react.development.js:859:10) at node_modules/@testing-library/react/dist/act-compat.js:47:25 at renderRoot (node_modules/@testing-library/react/dist/pure.js:190:26) at render (node_modules/@testing-library/react/dist/pure.js:292:10) at customRender (test/test-utils/jest-matrix-react.tsx:29:18) at makeMVideoBody (test/unit-tests/components/views/messages/MVideoBody-test.tsx:197:18) at Object.makeMVideoBody (test/unit-tests/components/views/messages/MVideoBody-test.tsx:92:32)

Check failure on line 41 in src/hooks/useMediaVisible.ts

View workflow job for this annotation

GitHub Actions / Jest (1)

HideActionButton › should show button when event is visible by showMediaEventIds setting

TypeError: client.getUserId is not a function at getUserId (src/hooks/useMediaVisible.ts:41:41) at HideActionButton (src/components/views/messages/HideActionButton.tsx:28:57) at Object.react-stack-bottom-frame (node_modules/react-dom/cjs/react-dom-client.development.js:23863:20) at renderWithHooks (node_modules/react-dom/cjs/react-dom-client.development.js:5529:22) at updateFunctionComponent (node_modules/react-dom/cjs/react-dom-client.development.js:8897:19) at beginWork (node_modules/react-dom/cjs/react-dom-client.development.js:10522:18) at runWithFiberInDEV (node_modules/react-dom/cjs/react-dom-client.development.js:1522:13) at performUnitOfWork (node_modules/react-dom/cjs/react-dom-client.development.js:15140:22) at workLoopSync (node_modules/react-dom/cjs/react-dom-client.development.js:14956:41) at renderRootSync (node_modules/react-dom/cjs/react-dom-client.development.js:14936:11) at performWorkOnRoot (node_modules/react-dom/cjs/react-dom-client.development.js:14462:44) at performWorkOnRootViaSchedulerTask (node_modules/react-dom/cjs/react-dom-client.development.js:16216:7) at flushActQueue (node_modules/react/cjs/react.development.js:566:34) at Object.<anonymous>.process.env.NODE_ENV.exports.act (node_modules/react/cjs/react.development.js:859:10) at node_modules/@testing-library/react/dist/act-compat.js:47:25 at renderRoot (node_modules/@testing-library/react/dist/pure.js:190:26) at render (node_modules/@testing-library/react/dist/pure.js:292:10) at customRender (test/test-utils/jest-matrix-react.tsx:29:18) at Object.<anonymous> (test/unit-tests/components/views/messages/HideActionButton-test.tsx:58:15)

Check failure on line 41 in src/hooks/useMediaVisible.ts

View workflow job for this annotation

GitHub Actions / Jest (1)

HideActionButton › should show button when event is visible by mediaPreviewConfig setting

TypeError: client.getUserId is not a function at getUserId (src/hooks/useMediaVisible.ts:41:41) at HideActionButton (src/components/views/messages/HideActionButton.tsx:28:57) at Object.react-stack-bottom-frame (node_modules/react-dom/cjs/react-dom-client.development.js:23863:20) at renderWithHooks (node_modules/react-dom/cjs/react-dom-client.development.js:5529:22) at updateFunctionComponent (node_modules/react-dom/cjs/react-dom-client.development.js:8897:19) at beginWork (node_modules/react-dom/cjs/react-dom-client.development.js:10522:18) at runWithFiberInDEV (node_modules/react-dom/cjs/react-dom-client.development.js:1522:13) at performUnitOfWork (node_modules/react-dom/cjs/react-dom-client.development.js:15140:22) at workLoopSync (node_modules/react-dom/cjs/react-dom-client.development.js:14956:41) at renderRootSync (node_modules/react-dom/cjs/react-dom-client.development.js:14936:11) at performWorkOnRoot (node_modules/react-dom/cjs/react-dom-client.development.js:14462:44) at performWorkOnRootViaSchedulerTask (node_modules/react-dom/cjs/react-dom-client.development.js:16216:7) at flushActQueue (node_modules/react/cjs/react.development.js:566:34) at Object.<anonymous>.process.env.NODE_ENV.exports.act (node_modules/react/cjs/react.development.js:859:10) at node_modules/@testing-library/react/dist/act-compat.js:47:25 at renderRoot (node_modules/@testing-library/react/dist/pure.js:190:26) at render (node_modules/@testing-library/react/dist/pure.js:292:10) at customRender (test/test-utils/jest-matrix-react.tsx:29:18) at Object.<anonymous> (test/unit-tests/components/views/messages/HideActionButton-test.tsx:63:15)

Check failure on line 41 in src/hooks/useMediaVisible.ts

View workflow job for this annotation

GitHub Actions / Jest (1)

HideActionButton › should hide button when event is hidden by showMediaEventIds setting

TypeError: client.getUserId is not a function at getUserId (src/hooks/useMediaVisible.ts:41:41) at HideActionButton (src/components/views/messages/HideActionButton.tsx:28:57) at Object.react-stack-bottom-frame (node_modules/react-dom/cjs/react-dom-client.development.js:23863:20) at renderWithHooks (node_modules/react-dom/cjs/react-dom-client.development.js:5529:22) at updateFunctionComponent (node_modules/react-dom/cjs/react-dom-client.development.js:8897:19) at beginWork (node_modules/react-dom/cjs/react-dom-client.development.js:10522:18) at runWithFiberInDEV (node_modules/react-dom/cjs/react-dom-client.development.js:1522:13) at performUnitOfWork (node_modules/react-dom/cjs/react-dom-client.development.js:15140:22) at workLoopSync (node_modules/react-dom/cjs/react-dom-client.development.js:14956:41) at renderRootSync (node_modules/react-dom/cjs/react-dom-client.development.js:14936:11) at performWorkOnRoot (node_modules/react-dom/cjs/react-dom-client.development.js:14462:44) at performWorkOnRootViaSchedulerTask (node_modules/react-dom/cjs/react-dom-client.development.js:16216:7) at flushActQueue (node_modules/react/cjs/react.development.js:566:34) at Object.<anonymous>.process.env.NODE_ENV.exports.act (node_modules/react/cjs/react.development.js:859:10) at node_modules/@testing-library/react/dist/act-compat.js:47:25 at renderRoot (node_modules/@testing-library/react/dist/pure.js:190:26) at render (node_modules/@testing-library/react/dist/pure.js:292:10) at customRender (test/test-utils/jest-matrix-react.tsx:29:18) at Object.<anonymous> (test/unit-tests/components/views/messages/HideActionButton-test.tsx:68:15)

Check failure on line 41 in src/hooks/useMediaVisible.ts

View workflow job for this annotation

GitHub Actions / Jest (1)

HideActionButton › should hide button when event is hidden by showImages setting

TypeError: client.getUserId is not a function at getUserId (src/hooks/useMediaVisible.ts:41:41) at HideActionButton (src/components/views/messages/HideActionButton.tsx:28:57) at Object.react-stack-bottom-frame (node_modules/react-dom/cjs/react-dom-client.development.js:23863:20) at renderWithHooks (node_modules/react-dom/cjs/react-dom-client.development.js:5529:22) at updateFunctionComponent (node_modules/react-dom/cjs/react-dom-client.development.js:8897:19) at beginWork (node_modules/react-dom/cjs/react-dom-client.development.js:10522:18) at runWithFiberInDEV (node_modules/react-dom/cjs/react-dom-client.development.js:1522:13) at performUnitOfWork (node_modules/react-dom/cjs/react-dom-client.development.js:15140:22) at workLoopSync (node_modules/react-dom/cjs/react-dom-client.development.js:14956:41) at renderRootSync (node_modules/react-dom/cjs/react-dom-client.development.js:14936:11) at performWorkOnRoot (node_modules/react-dom/cjs/react-dom-client.development.js:14462:44) at performWorkOnRootViaSchedulerTask (node_modules/react-dom/cjs/react-dom-client.development.js:16216:7) at flushActQueue (node_modules/react/cjs/react.development.js:566:34) at Object.<anonymous>.process.env.NODE_ENV.exports.act (node_modules/react/cjs/react.development.js:859:10) at node_modules/@testing-library/react/dist/act-compat.js:47:25 at renderRoot (node_modules/@testing-library/react/dist/pure.js:190:26) at render (node_modules/@testing-library/react/dist/pure.js:292:10) at customRender (test/test-utils/jest-matrix-react.tsx:29:18) at Object.<anonymous> (test/unit-tests/components/views/messages/HideActionButton-test.tsx:73:15)

Check failure on line 41 in src/hooks/useMediaVisible.ts

View workflow job for this annotation

GitHub Actions / Jest (1)

HideActionButton › should store event as hidden when clicked

TypeError: client.getUserId is not a function at getUserId (src/hooks/useMediaVisible.ts:41:41) at HideActionButton (src/components/views/messages/HideActionButton.tsx:28:57) at Object.react-stack-bottom-frame (node_modules/react-dom/cjs/react-dom-client.development.js:23863:20) at renderWithHooks (node_modules/react-dom/cjs/react-dom-client.development.js:5529:22) at updateFunctionComponent (node_modules/react-dom/cjs/react-dom-client.development.js:8897:19) at beginWork (node_modules/react-dom/cjs/react-dom-client.development.js:10522:18) at runWithFiberInDEV (node_modules/react-dom/cjs/react-dom-client.development.js:1522:13) at performUnitOfWork (node_modules/react-dom/cjs/react-dom-client.development.js:15140:22) at workLoopSync (node_modules/react-dom/cjs/react-dom-client.development.js:14956:41) at renderRootSync (node_modules/react-dom/cjs/react-dom-client.development.js:14936:11) at performWorkOnRoot (node_modules/react-dom/cjs/react-dom-client.development.js:14462:44) at performWorkOnRootViaSchedulerTask (node_modules/react-dom/cjs/react-dom-client.development.js:16216:7) at flushActQueue (node_modules/react/cjs/react.development.js:566:34) at Object.<anonymous>.process.env.NODE_ENV.exports.act (node_modules/react/cjs/react.development.js:859:10) at node_modules/@testing-library/react/dist/act-compat.js:47:25 at renderRoot (node_modules/@testing-library/react/dist/pure.js:190:26) at render (node_modules/@testing-library/react/dist/pure.js:292:10) at customRender (test/test-utils/jest-matrix-react.tsx:29:18) at Object.<anonymous> (test/unit-tests/components/views/messages/HideActionButton-test.tsx:78:15)
return [true];
}

const roomIsPrivate = joinRule ? PRIVATE_JOIN_RULES.includes(joinRule) : false;

const explicitEventVisiblity = eventId ? eventVisibility[eventId] : undefined;
Expand Down
5 changes: 3 additions & 2 deletions src/utils/MediaEventHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,12 @@ export class MediaEventHelper implements IDestroyable {
/**
* Determine if the media event in question supports being hidden in the timeline.
* @param event Any matrix event.
* @returns `true` if the media can be hidden, otherwise false.
* @returns `true` if the media can be hidden, otherwise `false`.
*/
public static canHide(event: MatrixEvent): boolean {
public static canHide(event: MatrixEvent, myUserId: string): boolean {
if (!event) return false;
if (event.isRedacted()) return false;
if (event.getSender() === myUserId) return false;
const content = event.getContent();
const hideTypes: string[] = [MsgType.Video, MsgType.Image];
if (hideTypes.includes(content.msgtype!)) return true;
Expand Down
54 changes: 37 additions & 17 deletions test/unit-tests/hooks/useMediaVisible-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Please see LICENSE files in the repository root for full details.
*/

import { act, renderHook, waitFor } from "jest-matrix-react";
import { JoinRule, type MatrixClient, type Room } from "matrix-js-sdk/src/matrix";
import { JoinRule, MatrixEvent, type MatrixClient, type Room } from "matrix-js-sdk/src/matrix";

import { useMediaVisible } from "../../../src/hooks/useMediaVisible";
import { createTestClient, mkStubRoom, withClientContextRenderOptions } from "../../test-utils";
Expand All @@ -22,8 +22,18 @@ describe("useMediaVisible", () => {
let room: Room;
const mediaPreviewConfig: MediaPreviewConfig = MediaPreviewConfigController.default;

function render() {
return renderHook(() => useMediaVisible(EVENT_ID, ROOM_ID), withClientContextRenderOptions(matrixClient));
function render({ sender }: { sender?: string } = {}) {
return renderHook(
() =>
useMediaVisible(
new MatrixEvent({
event_id: EVENT_ID,
room_id: ROOM_ID,
sender,
}),
),
withClientContextRenderOptions(matrixClient),
);
}
beforeEach(() => {
matrixClient = createTestClient();
Expand All @@ -42,53 +52,63 @@ describe("useMediaVisible", () => {
jest.restoreAllMocks();
});

it("should display media by default", async () => {
const { result } = render();
expect(result.current[0]).toEqual(true);
it("should display media by default", () => {
const [visible] = render().result.current;
expect(visible).toEqual(true);
});

it("should hide media when media previews are Off", async () => {
it("should hide media when media previews are Off", () => {
mediaPreviewConfig.media_previews = MediaPreviewValue.Off;
const { result } = render();
expect(result.current[0]).toEqual(false);
const [visible] = render().result.current;
expect(visible).toEqual(false);
});

it("should always show media sent by us", () => {
mediaPreviewConfig.media_previews = MediaPreviewValue.Off;
const [visible, setVisible] = render({ sender: matrixClient.getUserId()! }).result.current;
expect(visible).toEqual(true);
expect(setVisible).toBeUndefined();
});

it.each([[JoinRule.Invite], [JoinRule.Knock], [JoinRule.Restricted]])(
"should display media when media previews are Private and the join rule is %s",
async (rule) => {
(rule) => {
mediaPreviewConfig.media_previews = MediaPreviewValue.Private;
room.currentState.getJoinRule = jest.fn().mockReturnValue(rule);
const { result } = render();
expect(result.current[0]).toEqual(true);
const [visible] = render().result.current;
expect(visible).toEqual(true);
},
);

it.each([[JoinRule.Public], ["anything_else"]])(
"should hide media when media previews are Private and the join rule is %s",
async (rule) => {
(rule) => {
mediaPreviewConfig.media_previews = MediaPreviewValue.Private;
room.currentState.getJoinRule = jest.fn().mockReturnValue(rule);
const { result } = render();
expect(result.current[0]).toEqual(false);
const [visible] = render().result.current;
expect(visible).toEqual(false);
},
);

it("should hide media after function is called", async () => {
const { result } = render();
expect(result.current[0]).toEqual(true);
expect(result.current[1]).toBeDefined();
act(() => {
result.current[1](false);
result.current[1]!(false);
});
await waitFor(() => {
expect(result.current[0]).toEqual(false);
});
});

it("should show media after function is called", async () => {
mediaPreviewConfig.media_previews = MediaPreviewValue.Off;
const { result } = render();
expect(result.current[0]).toEqual(false);
expect(result.current[1]).toBeDefined();
act(() => {
result.current[1](true);
result.current[1]!(true);
});
await waitFor(() => {
expect(result.current[0]).toEqual(true);
Expand Down
Loading