Refactor and move MVideoBody to shared components (#32849)

* init MVideoBody to shared components, including test, stories and view

* fix prettier and other warnings

* move video message body to shared view + app viewmodel

* Fix prettier warnings and masking spinner for tests

* stabilize VideoBodyView screenshots with local media asset

* Disable spinner from changing image all the time

* Added mask over video spinner to prevent issues with new generated images on playwright tests

* Update prettier fix

* Update snapshot

* Add tests to cover different states of Video

* Update code to prevent the previous component Hack fix regarding jumps on the timeline.

* Update snapshot

* Update code to improve code quality for Sonar + update snapshot

* adde documentation snippets

* refactor: move m.video rendering into body factory

* docs: add tsdoc for video body view model

* docs: add thumbnail tsdoc for video body view model

* docs: add content-url tsdoc for video body view model

* docs: add dimensions tsdoc for video body view model

* docs: add aspect-ratio tsdoc for video body view model

* docs: add tsdoc for video body view state

* refactor: replace video body view state enum

* refactor: remove duplicate video body state init

* refactor: drop unused video body view state attribute

* Fix Prettier

* Update snapshot screenshot

* test: restore video story screenshot mask

* chore: refresh PR head

* Add mask to screenshot to pass CI tests

* test: narrow video story mask hook

* Fix easy Sonar warnings in video body components

* Move shared message body views into event-tile layout

* Move shared message body visual baselines

* Revert unrelated shared message body moves
This commit is contained in:
Zack
2026-04-01 09:48:22 +00:00
committed by GitHub
parent 3e04b24d1e
commit 0391543bbc
27 changed files with 1763 additions and 524 deletions
@@ -23,7 +23,7 @@ import {
mockClientMethodsUser,
withClientContextRenderOptions,
} from "../../../../test-utils";
import MVideoBody from "../../../../../src/components/views/messages/MVideoBody";
import { VideoBodyFactory } from "../../../../../src/components/views/messages/MBodyFactory";
import type { IBodyProps } from "../../../../../src/components/views/messages/IBodyProps";
import SettingsStore from "../../../../../src/settings/SettingsStore";
import { MediaPreviewValue } from "../../../../../src/@types/media_preview";
@@ -33,7 +33,7 @@ jest.mock("matrix-encrypt-attachment", () => ({
decryptAttachment: jest.fn(),
}));
describe("MVideoBody", () => {
describe("VideoBodyFactory", () => {
const ourUserId = "@user:server";
const senderUserId = "@other_use:server";
const deviceId = "DEADB33F";
@@ -122,23 +122,25 @@ describe("MVideoBody", () => {
mediaEventHelper: { media: { isEncrypted: false } } as MediaEventHelper,
};
const { asFragment } = render(
const { container } = render(
<MatrixClientContext.Provider value={cli}>
<MVideoBody {...defaultProps} />
<VideoBodyFactory {...defaultProps} />
</MatrixClientContext.Provider>,
withClientContextRenderOptions(cli),
);
expect(asFragment()).toMatchSnapshot();
// If we get here, we did not crash.
expect(container.querySelector("video")).not.toBeNull();
});
it("should show poster for encrypted media before downloading it", async () => {
fetchMock.getOnce(thumbUrl, { status: 200 });
const { asFragment } = render(
<MVideoBody mxEvent={encryptedMediaEvent} mediaEventHelper={new MediaEventHelper(encryptedMediaEvent)} />,
render(
<VideoBodyFactory
mxEvent={encryptedMediaEvent}
mediaEventHelper={new MediaEventHelper(encryptedMediaEvent)}
/>,
withClientContextRenderOptions(cli),
);
expect(asFragment()).toMatchSnapshot();
expect(await screen.findByLabelText("alt for a test video")).toHaveAttribute("poster");
});
describe("with video previews/thumbnails disabled", () => {
@@ -161,7 +163,7 @@ describe("MVideoBody", () => {
fetchMock.getOnce(thumbUrl, { status: 200 });
render(
<MVideoBody
<VideoBodyFactory
mxEvent={encryptedMediaEvent}
mediaEventHelper={new MediaEventHelper(encryptedMediaEvent)}
/>,
@@ -177,7 +179,7 @@ describe("MVideoBody", () => {
fetchMock.getOnce(thumbUrl, { status: 200 });
render(
<MVideoBody
<VideoBodyFactory
mxEvent={encryptedMediaEvent}
mediaEventHelper={new MediaEventHelper(encryptedMediaEvent)}
/>,
@@ -189,6 +191,7 @@ describe("MVideoBody", () => {
expect(placeholderButton).toBeInTheDocument();
fireEvent.click(placeholderButton);
await screen.findByLabelText("alt for a test video");
expect(fetchMock).toHaveFetched(thumbUrl);
});
@@ -214,16 +217,16 @@ describe("MVideoBody", () => {
},
},
});
const { asFragment } = render(
<MVideoBody
render(
<VideoBodyFactory
mxEvent={ourEncryptedMediaEvent}
mediaEventHelper={new MediaEventHelper(ourEncryptedMediaEvent)}
/>,
withClientContextRenderOptions(cli),
);
expect(await screen.findByLabelText("alt for a test video")).toBeInTheDocument();
expect(fetchMock).toHaveFetched(thumbUrl);
expect(asFragment()).toMatchSnapshot();
});
});
});