diff --git a/desktop/src/features/messages/lib/backgroundMediaUploadStore.test.mjs b/desktop/src/features/messages/lib/backgroundMediaUploadStore.test.mjs index 2a4366be5..da13cb70d 100644 --- a/desktop/src/features/messages/lib/backgroundMediaUploadStore.test.mjs +++ b/desktop/src/features/messages/lib/backgroundMediaUploadStore.test.mjs @@ -4,6 +4,7 @@ import test from "node:test"; import { cancelStartedMediaUploads, dispatchTrackedMediaUpload, + prepareBackgroundMediaUpload, } from "./backgroundMediaUploadStore.ts"; const descriptor = { @@ -22,6 +23,27 @@ function deferred() { return { promise, resolve }; } +test("reports cancellation before a prepared upload starts", () => { + const prepared = prepareBackgroundMediaUpload([ + { + file: new File(["video"], "large-video.mp4", { type: "video/mp4" }), + id: 1, + spoilered: false, + }, + ]); + + assert.equal(prepared.isCanceled(), false); + prepared.cancel(); + assert.equal(prepared.isCanceled(), true); + assert.equal( + prepared.start({ + onComplete: async () => {}, + onError: () => {}, + }), + false, + ); +}); + test("cancels only uploads whose native commands were dispatched", async () => { const releaseUpload = deferred(); const startedProgressIds = new Map(); diff --git a/desktop/src/features/messages/lib/backgroundMediaUploadStore.ts b/desktop/src/features/messages/lib/backgroundMediaUploadStore.ts index 806692606..3f7bd5a91 100644 --- a/desktop/src/features/messages/lib/backgroundMediaUploadStore.ts +++ b/desktop/src/features/messages/lib/backgroundMediaUploadStore.ts @@ -54,6 +54,7 @@ type StartBackgroundUploadOptions = Omit< export type PreparedBackgroundMediaUpload = { cancel: () => void; + isCanceled: () => boolean; start: (options: StartBackgroundUploadOptions) => boolean; }; @@ -243,6 +244,7 @@ export function prepareBackgroundMediaUpload( let started = false; return { cancel: () => undefined, + isCanceled: () => false, start: ({ onComplete, onError }) => { if (started) return false; started = true; @@ -274,6 +276,7 @@ export function prepareBackgroundMediaUpload( cancel: () => { cancelTask(task); }, + isCanceled: () => task.canceled, start: ({ onCancel, onComplete, onError }) => { if (started || task.canceled) return false; started = true; diff --git a/desktop/src/features/messages/ui/useMentionSendFlow.ts b/desktop/src/features/messages/ui/useMentionSendFlow.ts index 5842ad42c..e17ee66f3 100644 --- a/desktop/src/features/messages/ui/useMentionSendFlow.ts +++ b/desktop/src/features/messages/ui/useMentionSendFlow.ts @@ -572,7 +572,7 @@ export function useMentionSendFlow({ ); } }; - if (!optimisticId && sendChannelId) { + if (!optimisticId && sendChannelId && !preparedUpload?.isCanceled()) { const initialMessage = buildOutgoingMessage( draft.trimmed, draft.savedImeta, @@ -621,9 +621,7 @@ export function useMentionSendFlow({ restoreComposerAfterFailure(); }, }); - if (!uploadStarted) { - return; - } + if (!uploadStarted) return removePendingSend(); } if ( draft.capturedChannelId === channelIdRef.current || diff --git a/desktop/tests/e2e/file-attachment.spec.ts b/desktop/tests/e2e/file-attachment.spec.ts index 93ae28054..b2ecef5a0 100644 --- a/desktop/tests/e2e/file-attachment.spec.ts +++ b/desktop/tests/e2e/file-attachment.spec.ts @@ -265,6 +265,12 @@ test("sends immediately and keeps upload progress across channels", async ({ await expect(queuedSpoiler).toHaveCSS("opacity", "1"); await page.getByTestId("send-message").click(); + const pendingRow = page.getByTestId("message-row").last(); + await expect( + pendingRow.getByTestId("message-preparation-status"), + ).toContainText("Preparing large-video.mp4…"); + const pendingMessageId = await pendingRow.getAttribute("data-message-id"); + expect(pendingMessageId).not.toBeNull(); await expect(page.getByTestId("message-composer")).not.toContainText( "large-video.mp4", ); @@ -278,6 +284,9 @@ test("sends immediately and keeps upload progress across channels", async ({ }); await page.getByTestId("channel-general").click(); + await expect( + page.locator(`[data-message-id="${pendingMessageId}"]`), + ).toHaveCount(1); await expect(page.getByTestId("file-card").last()).toContainText( "quarterly-report.pdf", );