fix: preserve video extensions on AI design downloads

This commit is contained in:
2026-08-18 02:31:17 +08:00
parent 13bdc0c9ba
commit 43e8a6051a
2 changed files with 94 additions and 8 deletions

View File

@@ -427,6 +427,79 @@ describe('AI design Main route boundary', () => {
await expect(readFile(savedPath, 'utf8')).resolves.toBe('image-bytes');
});
it.each([
['mp4', 'video/mp4'],
['mov', 'video/quicktime'],
['webm', 'video/webm'],
])('streams a private %s asset into a video save location', async (extension, mimeType) => {
temporaryDirectory = await mkdtemp(join(tmpdir(), 'makelore-design-download-'));
const savedPath = join(temporaryDirectory, `animation.${extension}`);
electronMocks.showSaveDialog.mockResolvedValue({ canceled: false, filePath: savedPath });
const expectedBytes = `video-${extension}-bytes`;
const content = new Response(expectedBytes, {
status: 200,
headers: { 'Content-Type': mimeType },
});
const getContentType = vi.spyOn(content.headers, 'get');
const openAssetContent = vi.fn().mockResolvedValue(content);
const response = createResponse();
await handleImageWorkspaceRoutes(
createRequest('POST', { defaultFileName: `Ocean animation.${extension}` }),
response.res,
new URL(
'http://127.0.0.1/api/works/image-workspace/workspaces/workspace-one/assets/asset-one/download',
),
{ imageWorkspace: { openAssetContent } } as unknown as HostApiContext,
);
expect(electronMocks.showSaveDialog).toHaveBeenCalledWith(expect.objectContaining({
defaultPath: expect.stringContaining(`Ocean animation.${extension}`),
filters: [
{ name: '设计资产', extensions: [extension] },
{ name: '所有文件', extensions: ['*'] },
],
}));
expect(getContentType).toHaveBeenCalledWith('content-type');
expect(content.headers.get('content-type')).toBe(mimeType);
expect(openAssetContent).toHaveBeenCalledWith('workspace-one', 'asset-one');
expect(response.json()).toMatchObject({
success: true,
data: { status: 'saved' },
});
await expect(readFile(savedPath, 'utf8')).resolves.toBe(expectedBytes);
});
it('rejects a private download response that is not an image or video', async () => {
temporaryDirectory = await mkdtemp(join(tmpdir(), 'makelore-design-download-'));
const savedPath = join(temporaryDirectory, 'payload.mp4');
electronMocks.showSaveDialog.mockResolvedValue({ canceled: false, filePath: savedPath });
const response = createResponse();
await handleImageWorkspaceRoutes(
createRequest('POST', { defaultFileName: 'payload.mp4' }),
response.res,
new URL(
'http://127.0.0.1/api/works/image-workspace/workspaces/workspace-one/assets/asset-one/download',
),
{
imageWorkspace: {
openAssetContent: vi.fn().mockResolvedValue(new Response('untrusted', {
status: 200,
headers: { 'Content-Type': 'application/octet-stream' },
})),
},
} as unknown as HostApiContext,
);
expect(response.json()).toMatchObject({
success: false,
code: 'DESIGN_ASSET_DOWNLOAD_FAILED',
error: '生成资产暂时无法下载,请稍后重试',
});
await expect(readFile(savedPath)).rejects.toMatchObject({ code: 'ENOENT' });
});
it('preserves an existing destination when the private image stream fails', async () => {
temporaryDirectory = await mkdtemp(join(tmpdir(), 'makelore-design-download-'));
const savedPath = join(temporaryDirectory, 'existing.png');