From ebeb28da757b2e757ad27b6d0e33e91451fe5879 Mon Sep 17 00:00:00 2001 From: iamsivin Date: Thu, 23 Jan 2025 10:58:47 +0530 Subject: [PATCH 1/2] fix: CORS issue with downloadFile helper --- package.json | 2 +- src/helpers.ts | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 886b18f..49ac93d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@chatwoot/utils", - "version": "0.0.31", + "version": "0.0.32", "description": "Chatwoot utils", "private": false, "license": "MIT", diff --git a/src/helpers.ts b/src/helpers.ts index d223878..4c7682e 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -211,10 +211,21 @@ export const downloadFile = async ({ type, extension = null, }: DownloadFileOptions): Promise => { - if (!url || !type) return; + if (!url || !type) { + throw new Error('Invalid download parameters'); + } try { - const response = await fetch(url); + const response = await fetch(url, { + method: 'GET', + credentials: 'omit', + mode: 'cors', + }); + + if (!response.ok) { + throw new Error(`Download failed: ${response.status}`); + } + const blobData = await response.blob(); const contentType = response.headers.get('content-type'); @@ -240,6 +251,6 @@ export const downloadFile = async ({ link.remove(); URL.revokeObjectURL(blobUrl); } catch (error) { - console.warn('Download failed:', error); + throw error instanceof Error ? error : new Error('Download failed'); } }; From bd1d082c15241286dc9215959f73049a8b4ba780 Mon Sep 17 00:00:00 2001 From: iamsivin Date: Thu, 23 Jan 2025 13:58:32 +0530 Subject: [PATCH 2/2] chore: Fix spec --- test/helpers.test.ts | 46 ++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/test/helpers.test.ts b/test/helpers.test.ts index 1651af6..bcc7fe8 100644 --- a/test/helpers.test.ts +++ b/test/helpers.test.ts @@ -151,6 +151,7 @@ describe('downloadFile', () => { remove: jest.fn(), href: '', download: '', + style: '', }; document.createElement = jest.fn().mockReturnValue(mockDOMElement); document.body.append = jest.fn(); @@ -159,7 +160,7 @@ describe('downloadFile', () => { afterEach(() => jest.clearAllMocks()); describe('successful downloads', () => { - it('should download PDF file', async () => { + it('should download PDF file with correct fetch options', async () => { const blob = new Blob(['test'], { type: 'application/pdf' }); mockFetch.mockResolvedValueOnce({ ok: true, @@ -173,12 +174,16 @@ describe('downloadFile', () => { extension: 'pdf', }); - expect(mockFetch).toHaveBeenCalledWith('test.com/doc.pdf'); + expect(mockFetch).toHaveBeenCalledWith('test.com/doc.pdf', { + method: 'GET', + credentials: 'omit', + mode: 'cors', + }); expect(mockCreateObjectURL).toHaveBeenCalledWith(blob); expect(mockDOMElement.click).toHaveBeenCalled(); }); - it('should download image file with content disposition', async () => { + it('should download file with content disposition filename', async () => { const blob = new Blob(['test'], { type: 'image/png' }); mockFetch.mockResolvedValueOnce({ ok: true, @@ -196,24 +201,41 @@ describe('downloadFile', () => { }); expect(mockDOMElement.download).toBe('test.png'); + expect(document.body.append).toHaveBeenCalled(); + expect(URL.revokeObjectURL).toHaveBeenCalledWith('blob:mock-url'); }); }); describe('error handling', () => { - it('should skip if url or type missing', async () => { - await downloadFile({ url: '', type: 'pdf' }); + it('should throw error if url or type missing', async () => { + await expect(downloadFile({ url: '', type: 'pdf' })).rejects.toThrow( + 'Invalid download parameters' + ); + + await expect(downloadFile({ url: 'test.com', type: '' })).rejects.toThrow( + 'Invalid download parameters' + ); + expect(mockFetch).not.toHaveBeenCalled(); }); - it('should handle network errors', async () => { - const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(); + it('should throw error on failed response', async () => { + mockFetch.mockResolvedValueOnce({ + ok: false, + status: 404, + }); + + await expect( + downloadFile({ url: 'test.com/file', type: 'pdf' }) + ).rejects.toThrow('Download failed: 404'); + }); + + it('should throw error on network failure', async () => { mockFetch.mockRejectedValueOnce(new Error('Network error')); - await downloadFile({ url: 'test.com/file', type: 'pdf' }); - expect(consoleSpy).toHaveBeenCalledWith( - 'Download failed:', - expect.any(Error) - ); + await expect( + downloadFile({ url: 'test.com/file', type: 'pdf' }) + ).rejects.toThrow('Network error'); }); }); });