From d42d60d64e983c13c7dd2c0ed5af7ca3af8ea79a Mon Sep 17 00:00:00 2001 From: iroiro147 Date: Thu, 6 Aug 2026 03:46:32 +0530 Subject: [PATCH] fix(desktop): rename generic attachment action from 'Attach image' to 'Attach file' (#2381) (#4304) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #2381. ## What was broken The message composer's paperclip accepts generic attachments — images, videos, PDFs, archives, and any other supported file — but its tooltip and accessible name still read **"Attach image"**. Sighted users might reasonably believe the control is image-only, and screen-reader users get an incomplete description of what the button does. ## The fix Rename the accessible name and tooltip text on the generic composer paperclip in `MessageComposerToolbar.tsx`: - `aria-label` — `"Attach image"` → `"Attach file"` - `` — `"Attach image"` → `"Attach file"` Plus update the 12 affected Desktop e2e selectors across five spec files to reference the new accessible name: - `desktop/tests/e2e/file-attachment.spec.ts` (2 selectors) - `desktop/tests/e2e/spoiler.spec.ts` (2) - `desktop/tests/e2e/composer-image-draw.spec.ts` (2) - `desktop/tests/e2e/image-attachment-gallery.spec.ts` (4) - `desktop/tests/e2e/video-attachment.spec.ts` (2) ## Scope (per the issue) The feedback screenshot dialog (`desktop/src/features/settings/ui/SendFeedbackDialog.tsx`) is **unchanged** — that dialog itself is image-only, so its "Attach image" wording is accurate. This PR only touches the generic composer control. ## Test plan - All **105** unit tests in `desktop/src/features/messages/ui/*.test.mjs` pass locally. - Verified no remaining `"Attach image"` string outside the intentionally preserved feedback dialog: ```sh grep -rn '"Attach image"' desktop/ # → only hits in SendFeedbackDialog.tsx ``` - The six e2e specs are only exercised in CI; the selector updates are mechanical and verified by grep to reference the new a11y name. ## Blast radius - **Files touched**: `MessageComposerToolbar.tsx` (two strings); five e2e spec files (12 selector updates). - **User-facing behaviour**: one tooltip + one screen-reader name change; no functional or visual changes otherwise. - **No API or state change.** ## Out of scope - The feedback dialog's "Attach image" wording — kept per the issue's own "Scope" guidance. - Any i18n plumbing — Buzz Desktop doesn't currently localize these strings. Signed-off-by: Sarthak Singh Signed-off-by: Ravneet Arora Co-authored-by: Ravneet Arora Co-authored-by: Cursor --- .../src/features/messages/ui/MessageComposerToolbar.tsx | 4 ++-- desktop/tests/e2e/composer-image-draw.spec.ts | 6 +++--- desktop/tests/e2e/file-attachment.spec.ts | 8 ++++---- desktop/tests/e2e/image-attachment-gallery.spec.ts | 8 ++++---- desktop/tests/e2e/spoiler.spec.ts | 4 ++-- desktop/tests/e2e/video-attachment.spec.ts | 4 ++-- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/desktop/src/features/messages/ui/MessageComposerToolbar.tsx b/desktop/src/features/messages/ui/MessageComposerToolbar.tsx index 1c8087e99..efb0d3b3b 100644 --- a/desktop/src/features/messages/ui/MessageComposerToolbar.tsx +++ b/desktop/src/features/messages/ui/MessageComposerToolbar.tsx @@ -179,7 +179,7 @@ export const MessageComposerToolbar = React.memo( - Attach image + Attach file { test("image annotation overlay and editor controls", async ({ page }) => { await page.goto("/"); await page.getByTestId("channel-general").click(); - await page.getByRole("button", { name: "Attach image" }).click(); + await page.getByRole("button", { name: "Attach file" }).click(); const composer = page.getByTestId("message-composer"); await expect(composer.getByAltText("Attachment aaaa")).toBeVisible(); @@ -102,7 +102,7 @@ test("draw on an uploaded image, save replaces it, revert restores in place", as await expect(page.getByTestId("chat-title")).toHaveText("general"); // Attach the original image via the mocked paperclip flow. - await page.getByRole("button", { name: "Attach image" }).click(); + await page.getByRole("button", { name: "Attach file" }).click(); const composer = page.getByTestId("message-composer"); await expect(composer.getByAltText("Attachment aaaa")).toBeVisible(); @@ -182,7 +182,7 @@ test("spoiler marking survives drawing on the attachment", async ({ page }) => { await page.getByTestId("channel-general").click(); await expect(page.getByTestId("chat-title")).toHaveText("general"); - await page.getByRole("button", { name: "Attach image" }).click(); + await page.getByRole("button", { name: "Attach file" }).click(); const composer = page.getByTestId("message-composer"); await expect(composer.getByAltText("Attachment aaaa")).toBeVisible(); diff --git a/desktop/tests/e2e/file-attachment.spec.ts b/desktop/tests/e2e/file-attachment.spec.ts index 21237f06b..0a79718e0 100644 --- a/desktop/tests/e2e/file-attachment.spec.ts +++ b/desktop/tests/e2e/file-attachment.spec.ts @@ -39,7 +39,7 @@ test.beforeEach(async ({ page }) => { async function chooseQuarterlyReport(page: Page) { const [chooser] = await Promise.all([ page.waitForEvent("filechooser"), - page.getByRole("button", { name: "Attach image" }).click(), + page.getByRole("button", { name: "Attach file" }).click(), ]); await chooser.setFiles({ buffer: Buffer.from("quarterly report"), @@ -51,7 +51,7 @@ async function chooseQuarterlyReport(page: Page) { async function chooseLargeVideo(page: Page) { const [chooser] = await Promise.all([ page.waitForEvent("filechooser"), - page.getByRole("button", { name: "Attach image" }).click(), + page.getByRole("button", { name: "Attach file" }).click(), ]); await chooser.setFiles({ buffer: Buffer.alloc(16 * 1024 * 1024, 1), @@ -63,7 +63,7 @@ async function chooseLargeVideo(page: Page) { async function choosePhoto(page: Page) { const [chooser] = await Promise.all([ page.waitForEvent("filechooser"), - page.getByRole("button", { name: "Attach image" }).click(), + page.getByRole("button", { name: "Attach file" }).click(), ]); await chooser.setFiles({ buffer: Buffer.from("photo"), @@ -542,7 +542,7 @@ test("forum posts emit a FileCard for generic attachments, not a broken image", await page.getByRole("button", { name: "Start a new post..." }).click(); // Paperclip → mocked pick_and_upload_media returns the PDF descriptor. - await page.getByRole("button", { name: "Attach image" }).click(); + await page.getByRole("button", { name: "Attach file" }).click(); // Submit the (attachment-only) forum post. await page.getByTestId("send-message").click(); diff --git a/desktop/tests/e2e/image-attachment-gallery.spec.ts b/desktop/tests/e2e/image-attachment-gallery.spec.ts index d5c81ceed..8c3602365 100644 --- a/desktop/tests/e2e/image-attachment-gallery.spec.ts +++ b/desktop/tests/e2e/image-attachment-gallery.spec.ts @@ -123,7 +123,7 @@ test("image bundle lightbox navigates as a gallery", async ({ page }) => { await expect(page.getByTestId("chat-title")).toHaveText("general"); await page.getByTestId("message-input").fill("gallery bundle"); - await page.getByRole("button", { name: "Attach image" }).click(); + await page.getByRole("button", { name: "Attach file" }).click(); await page.getByTestId("send-message").click(); await expect(page.getByText("Sending")).toHaveCount(0); @@ -667,7 +667,7 @@ test("mosaic image context menu is portaled outside the clipped gallery", async await expect(page.getByTestId("chat-title")).toHaveText("general"); await page.getByTestId("message-input").fill("mosaic context menu"); - await page.getByRole("button", { name: "Attach image" }).click(); + await page.getByRole("button", { name: "Attach file" }).click(); await page.getByTestId("send-message").click(); await expect(page.getByText("Sending")).toHaveCount(0); @@ -709,7 +709,7 @@ test("lightbox image context menu stays inside the dialog focus scope", async ({ await expect(page.getByTestId("chat-title")).toHaveText("general"); await page.getByTestId("message-input").fill("lightbox context menu"); - await page.getByRole("button", { name: "Attach image" }).click(); + await page.getByRole("button", { name: "Attach file" }).click(); await page.getByTestId("send-message").click(); await expect(page.getByText("Sending")).toHaveCount(0); @@ -751,7 +751,7 @@ test("right-click image shows Copy image and invokes copy command", async ({ await expect(page.getByTestId("chat-title")).toHaveText("general"); await page.getByTestId("message-input").fill("copy me"); - await page.getByRole("button", { name: "Attach image" }).click(); + await page.getByRole("button", { name: "Attach file" }).click(); await page.getByTestId("send-message").click(); await expect(page.getByText("Sending")).toHaveCount(0); diff --git a/desktop/tests/e2e/spoiler.spec.ts b/desktop/tests/e2e/spoiler.spec.ts index 4cf4ac671..433a7044a 100644 --- a/desktop/tests/e2e/spoiler.spec.ts +++ b/desktop/tests/e2e/spoiler.spec.ts @@ -96,7 +96,7 @@ test("image attachments can be marked and sent as hidden spoilers", async ({ await page.getByTestId("channel-general").click(); await expect(page.getByTestId("chat-title")).toHaveText("general"); - await page.getByRole("button", { name: "Attach image" }).click(); + await page.getByRole("button", { name: "Attach file" }).click(); const composer = page.getByTestId("message-composer"); await expect(composer.getByAltText("Attachment cccc")).toBeVisible(); @@ -138,7 +138,7 @@ test("text spoiler stays usable while attachment upload is pending", async ({ // Kick off the (delayed) upload first — the attach button lives in the // passive toolbar, which is replaced while formatting is expanded. - await page.getByRole("button", { name: "Attach image" }).click(); + await page.getByRole("button", { name: "Attach file" }).click(); await page.getByRole("button", { name: "Toggle formatting" }).click(); const spoilerButton = page.getByRole("button", { diff --git a/desktop/tests/e2e/video-attachment.spec.ts b/desktop/tests/e2e/video-attachment.spec.ts index 458689a5e..488485292 100644 --- a/desktop/tests/e2e/video-attachment.spec.ts +++ b/desktop/tests/e2e/video-attachment.spec.ts @@ -183,7 +183,7 @@ async function openReviewWithPostedTimecode( await expect(page.getByTestId("chat-title")).toHaveText("general"); await waitForMockLiveSubscription(page, "general"); - await page.getByRole("button", { name: "Attach image" }).click(); + await page.getByRole("button", { name: "Attach file" }).click(); await expect( page.getByTestId("message-composer").getByAltText("Video attachment bbbb"), ).toBeVisible(); @@ -238,7 +238,7 @@ test("video upload previews use poster frames and inline videos open review mode await expect(page.getByTestId("chat-title")).toHaveText("general"); await waitForMockLiveSubscription(page, "general"); - await page.getByRole("button", { name: "Attach image" }).click(); + await page.getByRole("button", { name: "Attach file" }).click(); const composer = page.getByTestId("message-composer"); const composerPoster = composer.getByAltText("Video attachment bbbb");