4315038346
* Refactor MessageActionBar into MVVM ActionBarView * Adding tooltips for menu items and correct i18n strings * Layout changes * Renaming some properties * Rename property * Create a first version of the view model and refactor media visibility logic * Refactor view to take options and rections menu as optional properties * Cleaner interface between view and view model * Refactor view properties and replace Menu and MenuItem * Bugfixes and switching to ActionBarView instead of MessageActionBar in element-web * Avoid creating view models and render toolbar until it is actually shown * Added unit and playwright tests and documented the view * Added view model unit tests and updated snapshots of dependant tests * Remove unused components and unnecessary css * Remove unused language tags * Fix for handling join-rules correctly * Prettier * Add handling of stale view model in async calls * Prettier * Split the element-web css into two different. One for legacy components and one for the ActionBarView * Missing variables used for linting * Fix for showing ActionBarView when using keyboard for navigation * Handle visibility on context menu closing * ThreadPanel uses the ActionBarView so restore css rule * Fix for visibility of the ActionBarView in Thread panel * Fix for ActionBarVuew visibility when closing right-click context menu and not still hovering * Add roving index to function as a toolbar * Adjust the RoomView test to send hover to the EventTile instead of the message text * Fix SonarCloud issues * Fix for SonarCloud issue * Merge fix * Rename mx_LegacyActionBar to mx_ThreadActionBar * Added documentation and simplified join rules * Generalize the ActionBarView and move logic to view model * Add the four new buttons to the ActionBarView * Update view model and tests to use the updated ActionBarView * Refactor element-web to use ActionBarView * Clean up styling in element-web * Clean up and updating snaps and screenshots * Added unit-tests for better coverage * Moving ActionBarView to the correct folder in shared components * Update snaps in element-web * Better documentation in stories * Merge fixes * Updates after review comments * Review comment fixes * Added documentation to view models and updated snaps * Hide button had the wrong label * Replace createRef with useRef
130 lines
4.8 KiB
TypeScript
130 lines
4.8 KiB
TypeScript
/*
|
|
Copyright 2025 New Vector Ltd.
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
|
Please see LICENSE files in the repository root for full details.
|
|
*/
|
|
|
|
import { act, renderHook, waitFor } from "jest-matrix-react";
|
|
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";
|
|
import { type MediaPreviewConfig, MediaPreviewValue } from "../../../src/@types/media_preview";
|
|
import MediaPreviewConfigController from "../../../src/settings/controllers/MediaPreviewConfigController";
|
|
import SettingsStore from "../../../src/settings/SettingsStore";
|
|
|
|
const EVENT_ID = "$fibble:example.org";
|
|
const ROOM_ID = "!foobar:example.org";
|
|
|
|
describe("useMediaVisible", () => {
|
|
let matrixClient: MatrixClient;
|
|
let room: Room;
|
|
const mediaPreviewConfig: MediaPreviewConfig = MediaPreviewConfigController.default;
|
|
|
|
function render({ sender }: { sender?: string } = {}) {
|
|
return renderHook(
|
|
() =>
|
|
useMediaVisible(
|
|
new MatrixEvent({
|
|
event_id: EVENT_ID,
|
|
room_id: ROOM_ID,
|
|
sender,
|
|
}),
|
|
),
|
|
withClientContextRenderOptions(matrixClient),
|
|
);
|
|
}
|
|
|
|
function renderWithoutEvent() {
|
|
return renderHook(() => useMediaVisible(), withClientContextRenderOptions(matrixClient));
|
|
}
|
|
|
|
beforeEach(() => {
|
|
matrixClient = createTestClient();
|
|
room = mkStubRoom(ROOM_ID, undefined, matrixClient);
|
|
matrixClient.getRoom = jest.fn().mockReturnValue(room);
|
|
const origFn = SettingsStore.getValue;
|
|
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting, ...args) => {
|
|
if (setting === "mediaPreviewConfig") {
|
|
return mediaPreviewConfig;
|
|
}
|
|
return origFn(setting, ...args);
|
|
});
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.restoreAllMocks();
|
|
});
|
|
|
|
it("should display media by default", () => {
|
|
const [visible] = render().result.current;
|
|
expect(visible).toEqual(true);
|
|
});
|
|
|
|
it("should use the global rule when no event is provided", () => {
|
|
mediaPreviewConfig.media_previews = MediaPreviewValue.Off;
|
|
expect(renderWithoutEvent().result.current[0]).toEqual(false);
|
|
|
|
mediaPreviewConfig.media_previews = MediaPreviewValue.On;
|
|
expect(renderWithoutEvent().result.current[0]).toEqual(true);
|
|
});
|
|
|
|
it("should hide media when media previews are Off", () => {
|
|
mediaPreviewConfig.media_previews = MediaPreviewValue.Off;
|
|
const [visible] = render().result.current;
|
|
expect(visible).toEqual(false);
|
|
});
|
|
|
|
it("should always show media sent by us", () => {
|
|
mediaPreviewConfig.media_previews = MediaPreviewValue.Off;
|
|
const [visible] = render({ sender: matrixClient.getUserId()! }).result.current;
|
|
expect(visible).toEqual(true);
|
|
});
|
|
|
|
it.each([[JoinRule.Invite], [JoinRule.Knock], [JoinRule.Restricted]])(
|
|
"should display media when media previews are Private and the join rule is %s",
|
|
(rule) => {
|
|
mediaPreviewConfig.media_previews = MediaPreviewValue.Private;
|
|
room.currentState.getJoinRule = jest.fn().mockReturnValue(rule);
|
|
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",
|
|
(rule) => {
|
|
mediaPreviewConfig.media_previews = MediaPreviewValue.Private;
|
|
room.currentState.getJoinRule = jest.fn().mockReturnValue(rule);
|
|
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);
|
|
});
|
|
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);
|
|
});
|
|
await waitFor(() => {
|
|
expect(result.current[0]).toEqual(true);
|
|
});
|
|
});
|
|
});
|