Phase 2 Refactor MImageBody to MVVM and remove legacy component (#33212)

* MVVMing of MImageBody and removing legacy component + css

* Fix Prettier

* update small image to large image in test

* Update test

* Preserve MImageBody legacy class names

* Click image in custom component download test

* Update snapshots

* Update MBodyFactory snapshots

* Added new tests to pass coverage

* Fix prettier

* Remove legacy import that was removed

* Add MImageReplayBody test for coverage

* Remove legacy MImageBody selectors from image view

* Update image body selectors in Playwright tests

* Keep file panel image body spacing compact

* Update apps/web/src/viewmodels/message-body/ImageBodyViewModel.ts

Co-authored-by: Florian Duros <florian.duros@ormaz.fr>

* added documentation to component

* Fix hidden media placeholder import

---------

Co-authored-by: Florian Duros <florian.duros@ormaz.fr>
This commit is contained in:
Zack
2026-05-13 08:03:43 +02:00
committed by GitHub
parent 13dd1a0b5e
commit 1e7c9f672a
26 changed files with 3389 additions and 1608 deletions
@@ -208,7 +208,7 @@ test.describe("Composer", () => {
});
await app.viewRoomByName("Bob");
await app.composerDragAndPasteFile("room", getSampleFilePath("riot.png"), "image/png");
await expect(page.locator(".mx_MImageBody")).toBeVisible();
await expect(page.locator(".mx_ImageBody")).toBeVisible();
});
});
});
+2 -2
View File
@@ -198,7 +198,7 @@ test.describe("Composer", () => {
test("can paste a file", async ({ page, bot, app }) => {
await app.composerDragAndPasteFile("room", getSampleFilePath("riot.png"), "image/png");
await expect(page.locator(".mx_MImageBody")).toBeVisible();
await expect(page.locator(".mx_ImageBody")).toBeVisible();
});
test("can paste a file in a thread", async ({ page, app }) => {
@@ -213,7 +213,7 @@ test.describe("Composer", () => {
await tile.getByRole("button", { name: "Reply in thread" }).click();
await app.composerDragAndPasteFile("thread", getSampleFilePath("riot.png"), "image/png");
await expect(page.locator(".mx_MImageBody")).toBeVisible();
await expect(page.locator(".mx_ImageBody")).toBeVisible();
});
test.describe("when Control+Enter is required to send", () => {
@@ -37,7 +37,7 @@ test.describe("Image Upload", () => {
test("should allow upload via drag and drop", { tag: "@screenshot" }, async ({ page, app }) => {
await app.composerDragAndUploadFiles("room", getSampleFilePath("riot.png"), "image/png");
await app.timeline.scrollToBottom();
const imgTile = page.locator(".mx_MImageBody").first();
const imgTile = page.locator(".mx_ImageBody").first();
await expect(imgTile).toBeVisible();
});
});
@@ -105,12 +105,16 @@ test.describe("Custom Component API", () => {
});
await app.timeline.scrollToBottom();
const imgTile = page.locator(".mx_MImageBody").first();
const imgTile = page.locator(".mx_ImageBody").first();
await expect(imgTile).toBeVisible();
const image = imgTile.getByRole("img", { name: "bad.png" });
await expect(image).toBeVisible();
await imgTile.hover();
await expect(page.getByRole("button", { name: "Download" })).not.toBeVisible();
await imgTile.click();
await expect(page.getByLabel("Image view").getByLabel("Download")).not.toBeVisible();
await image.click();
const imageView = page.getByLabel("Image view");
await expect(imageView).toBeVisible();
await expect(imageView.getByLabel("Download")).not.toBeVisible();
});
test("should allow downloading media when the allowDownloading hint is set to true", async ({
page,
@@ -127,12 +131,16 @@ test.describe("Custom Component API", () => {
});
await app.timeline.scrollToBottom();
const imgTile = page.locator(".mx_MImageBody").first();
const imgTile = page.locator(".mx_ImageBody").first();
await expect(imgTile).toBeVisible();
const image = imgTile.getByRole("img", { name: "good.png" });
await expect(image).toBeVisible();
await imgTile.hover();
await expect(page.getByRole("button", { name: "Download" })).toBeVisible();
await imgTile.click();
await expect(page.getByLabel("Image view").getByLabel("Download")).toBeVisible();
await image.click();
const imageView = page.getByLabel("Image view");
await expect(imageView).toBeVisible();
await expect(imageView.getByLabel("Download")).toBeVisible();
});
test(
"should render the next registered component if the filter function throws",
@@ -87,9 +87,9 @@ test.describe("FilePanel", () => {
await expect(filePanelMessageList.getByText(NAME)).toHaveCount(3);
// Detect the image file
const image = filePanelMessageList.locator(".mx_EventTile_mediaLine.mx_EventTile_image .mx_MImageBody");
const image = filePanelMessageList.locator(".mx_EventTile_mediaLine.mx_EventTile_image .mx_ImageBody");
// Assert that the image is specified as thumbnail and has the alt string
await expect(image.locator("img[class='mx_MImageBody_thumbnail']")).toBeVisible();
await expect(image.locator("img.mx_ImageBody_image")).toBeVisible();
await expect(image.locator("img[alt='riot.png']")).toBeVisible();
// Detect the audio file
@@ -113,7 +113,7 @@ test.describe("FilePanel", () => {
"flex-end",
);
// Assert that all of the file tiles are visible before taking a snapshot
await expect(filePanelMessageList.locator(".mx_MImageBody")).toBeVisible(); // top
await expect(filePanelMessageList.locator(".mx_ImageBody")).toBeVisible(); // top
await expect(filePanelMessageList.locator(".mx_MAudioBody")).toBeVisible(); // middle
const senderDetails = filePanelMessageList.locator(".mx_EventTile_last .mx_EventTile_senderDetails");
await expect(senderDetails.locator(".mx_DisambiguatedProfile")).toBeVisible();
@@ -184,7 +184,7 @@ test.describe("FilePanel", () => {
// Detect the image file on the panel
const imageBody = page.locator(
".mx_FilePanel .mx_RoomView_MessageList .mx_EventTile_mediaLine.mx_EventTile_image .mx_MImageBody",
".mx_FilePanel .mx_RoomView_MessageList .mx_EventTile_mediaLine.mx_EventTile_image .mx_ImageBody",
);
const link = imageBody.locator(".mx_MFileBody a");
@@ -907,7 +907,7 @@ test.describe("Timeline", () => {
await sendImage(bot, room.roomId, NEW_AVATAR);
await app.timeline.scrollToBottom();
const imgTile = page.locator(".mx_MImageBody").first();
const imgTile = page.locator(".mx_ImageBody").first();
await expect(imgTile).toBeVisible();
await imgTile.hover();
await page.getByRole("button", { name: "Hide" }).click();
@@ -1314,7 +1314,7 @@ test.describe("Timeline", () => {
await sendImage(app.client, room.roomId, NEW_AVATAR);
await app.timeline.scrollToBottom();
await expect(page.locator(".mx_MImageBody").first()).toBeVisible();
await expect(page.locator(".mx_ImageBody").first()).toBeVisible();
// Exclude timestamp and read marker from snapshot
const screenshotOptions = {