diff --git a/app/customize/components/ExportPanel.test.tsx b/app/customize/components/ExportPanel.test.tsx index f5471ddd2..9899d8f72 100644 --- a/app/customize/components/ExportPanel.test.tsx +++ b/app/customize/components/ExportPanel.test.tsx @@ -1,8 +1,16 @@ -import { render, screen, fireEvent } from '@testing-library/react'; -import { describe, it, expect, vi } from 'vitest'; +import { render, screen, fireEvent, act } from '@testing-library/react'; +import { describe, it, expect, vi, beforeEach } from 'vitest'; import { ExportPanel } from './ExportPanel'; describe('ExportPanel', () => { + beforeEach(() => { + // Mock URL methods for JSDOM download triggers + if (typeof window.URL.createObjectURL === 'undefined') { + window.URL.createObjectURL = vi.fn(() => 'blob:mock'); + window.URL.revokeObjectURL = vi.fn(); + } + }); + const renderPanel = (overrides?: Partial[0]>) => { const onFormatChange = vi.fn(); const onCopy = vi.fn(); @@ -147,4 +155,62 @@ describe('ExportPanel', () => { expect(webpBtn.disabled).toBe(true); expect(pdfBtn.disabled).toBe(true); }); + + it('extracts URL correctly and triggers download for TSX format', async () => { + const fetchSpy = vi + .spyOn(global, 'fetch') + .mockResolvedValue(new Response('', { status: 200 })); + + const { container } = render( + + ); + + const svgBtn = container.querySelector('#download-svg-btn') as HTMLButtonElement; + + await act(async () => { + fireEvent.click(svgBtn); + }); + + expect(fetchSpy).toHaveBeenCalledWith(expect.stringContaining('https://example.com/badge.svg')); + + fetchSpy.mockRestore(); + }); + + it('extracts URL correctly for HTML format', async () => { + const fetchSpy = vi + .spyOn(global, 'fetch') + .mockResolvedValue(new Response('', { status: 200 })); + + const { container } = render( + + ); + + const svgBtn = container.querySelector('#download-svg-btn') as HTMLButtonElement; + + await act(async () => { + fireEvent.click(svgBtn); + }); + + expect(fetchSpy).toHaveBeenCalledWith(expect.stringContaining('https://example.com/badge.svg')); + + fetchSpy.mockRestore(); + }); }); diff --git a/app/customize/components/ExportPanel.tsx b/app/customize/components/ExportPanel.tsx index fb4021315..558039468 100644 --- a/app/customize/components/ExportPanel.tsx +++ b/app/customize/components/ExportPanel.tsx @@ -125,7 +125,8 @@ export function ExportPanel({ setIsDownloading(true); // 1. Extract the API URL source string from the template snippet container - const urlMatch = snippet.match(/\((https?:\/\/[^)]+)\)/) || snippet.match(/src="([^"]+)"/); + // UPDATED:Supports Markdown,HTML,and TSX(curly braces/brackticks/quotes) + const urlMatch = snippet.match(/(?:src=["'`{]|\]\()(https?:\/\/[^\s"'`)}]+)/); let targetUrl = urlMatch ? urlMatch[1] : ''; if (!targetUrl) { @@ -222,7 +223,7 @@ export function ExportPanel({ return; } - const urlMatch = snippet.match(/\((https?:\/\/[^)]+)\)/) || snippet.match(/src="([^"]+)"/); + const urlMatch = snippet.match(/(?:src=["'`{]|\]\()(https?:\/\/[^\s"'`)}]+)/); let targetUrl = urlMatch ? urlMatch[1] : ''; if (!targetUrl) { @@ -304,7 +305,7 @@ export function ExportPanel({ let svgMarkup = target?.innerHTML || ''; if (!svgMarkup || !svgMarkup.includes('