import { buildValidateDownloadUrl, validateAndTriggerDownload, } from '@/lib/client-download' describe('client-download', () => { beforeEach(() => { jest.restoreAllMocks() document.body.innerHTML = '' }) test('buildValidateDownloadUrl 应在原 URL 上追加 validate=1', () => { const url = '/api/materials/download?id=abc&type=all' const result = buildValidateDownloadUrl(url) expect(result).toBe('/api/materials/download?id=abc&type=all&validate=1') }) test('validate 成功后应触发直连下载', async () => { jest.useFakeTimers() const fetchMock = jest.fn().mockResolvedValue({ ok: true, json: async () => ({ success: true }), }) global.fetch = fetchMock as any const clickSpy = jest .spyOn(HTMLAnchorElement.prototype, 'click') .mockImplementation(() => {}) await validateAndTriggerDownload('/api/materials/download?id=mid-1') expect(fetchMock).toHaveBeenCalledWith( '/api/materials/download?id=mid-1&validate=1', expect.objectContaining({ method: 'GET', cache: 'no-store', }) ) expect(clickSpy).toHaveBeenCalledTimes(1) jest.runAllTimers() jest.useRealTimers() }) test('validate 失败时不应触发下载,并抛出后端错误', async () => { const fetchMock = jest.fn().mockResolvedValue({ ok: false, json: async () => ({ code: 'FORBIDDEN', error: '无权限下载该素材' }), }) global.fetch = fetchMock as any const clickSpy = jest .spyOn(HTMLAnchorElement.prototype, 'click') .mockImplementation(() => {}) await expect( validateAndTriggerDownload('/api/materials/download?id=mid-2') ).rejects.toMatchObject({ code: 'FORBIDDEN' }) expect(clickSpy).not.toHaveBeenCalled() }) })