fix(web): download media outputs with the forced-download artifact URL

The media card's download link uses artifactUrl's download option so a video
or audio output is saved rather than opened inline, and the E2E seeds the
thread snapshot with fresh response headers so the patched body is read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u
This commit is contained in:
Claude 2026-10-03 13:54:11 +00:00
parent 7491b38e8c
commit cc85ba7195
No known key found for this signature in database
3 changed files with 19 additions and 5 deletions

View File

@ -4,7 +4,6 @@ import {
captureScreenshot,
completeOnboarding,
fetchRpcEnvelope,
fulfillFetchedRpc,
rpc,
signup,
} from "./helpers";
@ -77,7 +76,12 @@ async function seedMediaMessage(page: Page, botId: string, block: () => MediaBlo
createdAt: new Date().toISOString(),
});
}
await fulfillFetchedRpc(route, fetched);
// Fresh headers: the original content length no longer matches the patched body.
await route.fulfill({
status: fetched.status,
contentType: "application/json",
body: JSON.stringify(fetched.body),
});
});
}
@ -139,7 +143,16 @@ test("renders a media job card while it runs and when it is done", async ({ page
],
},
);
page.on("console", (message) => {
if (message.type() === "error") console.log(`browser: ${message.text()}`);
});
const seeded = page.waitForResponse(
async (response) =>
response.url().includes("/rpc/threads/get") &&
(await response.text()).includes("media-job-1"),
);
await page.reload();
await seeded;
const card = page.getByTestId("media-card");
await expect(card).toBeVisible({ timeout: 30_000 });

View File

@ -22,7 +22,8 @@ vi.mock("./MediaPlayer", () => ({
),
}));
vi.mock("../../lib/artifact-url", () => ({
artifactUrl: (artifactId: string) => `/artifact/${artifactId}`,
artifactUrl: (artifactId: string, options?: { download?: boolean }) =>
`/artifact/${artifactId}${options?.download ? "?download=1" : ""}`,
}));
import { exportPresetsFor, isActiveMediaStatus, MediaCardView } from "./MediaCard";
@ -103,7 +104,7 @@ describe("media card", () => {
/>,
);
expect(html).toContain('data-player="video"');
expect(html).toContain('href="/artifact/video-1"');
expect(html).toContain('href="/artifact/video-1?download=1"');
expect(html).toContain('download="clip.mp4"');
expect(html).toContain('aria-label="Download clip.mp4"');
expect(html).toContain("Export");

View File

@ -125,7 +125,7 @@ function OutputActions({
return (
<div className="flex flex-wrap items-center gap-1.5">
<a
href={artifactUrl(output.artifactId)}
href={artifactUrl(output.artifactId, { download: true })}
download={name}
aria-label={t`Download ${name}`}
title={t`Download ${name}`}