From 2b82347fdc73b26c57dc9eff09833cfc4563946f Mon Sep 17 00:00:00 2001 From: Samyak Piya <76403666+samyakpiya@users.noreply.github.com> Date: Tue, 31 Dec 2024 08:08:22 -0500 Subject: [PATCH] Refactor File Download Logic and Streamline Test Suite (#9281) Closes #9277 ## Summary of Changes - Updated the file-download functionality to use the `saveAs` method from the `file-saver` library, ensuring a more reliable and consistent implementation. - Removed redundant tests to streamline the test suite and reduce maintenance overhead. ## Testing Performed - [x] Verified that exporting the view to a CSV file works as expected. --- .../activities/files/utils/downloadFile.ts | 10 +--- .../hooks/__tests__/useExportRecords.test.ts | 50 +------------------ .../export/hooks/useExportRecords.ts | 13 +---- 3 files changed, 5 insertions(+), 68 deletions(-) diff --git a/packages/twenty-front/src/modules/activities/files/utils/downloadFile.ts b/packages/twenty-front/src/modules/activities/files/utils/downloadFile.ts index 5dd7e6c00..af64fed4e 100644 --- a/packages/twenty-front/src/modules/activities/files/utils/downloadFile.ts +++ b/packages/twenty-front/src/modules/activities/files/utils/downloadFile.ts @@ -1,3 +1,4 @@ +import { saveAs } from 'file-saver'; import { getFileAbsoluteURI } from '~/utils/file/getFileAbsoluteURI'; export const downloadFile = (fullPath: string, fileName: string) => { @@ -8,13 +9,6 @@ export const downloadFile = (fullPath: string, fileName: string) => { : Promise.reject('Failed downloading file'), ) .then((blob) => { - const url = window.URL.createObjectURL(blob); - const a = document.createElement('a'); - a.style.display = 'none'; - a.href = url; - a.download = fileName; - document.body.appendChild(a); - a.click(); - window.URL.revokeObjectURL(url); + saveAs(blob, fileName); }); }; diff --git a/packages/twenty-front/src/modules/object-record/record-index/export/hooks/__tests__/useExportRecords.test.ts b/packages/twenty-front/src/modules/object-record/record-index/export/hooks/__tests__/useExportRecords.test.ts index 9c0c17294..2f1bf0e37 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/export/hooks/__tests__/useExportRecords.test.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/export/hooks/__tests__/useExportRecords.test.ts @@ -2,32 +2,10 @@ import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata' import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; import { RelationDefinitionType } from '~/generated-metadata/graphql'; -import { - csvDownloader, - displayedExportProgress, - download, - generateCsv, -} from '../useExportRecords'; +import { displayedExportProgress, generateCsv } from '../useExportRecords'; jest.useFakeTimers(); -describe('download', () => { - it('creates a download link and clicks it', () => { - const link = document.createElement('a'); - document.createElement = jest.fn().mockReturnValue(link); - const appendChild = jest.spyOn(document.body, 'appendChild'); - const click = jest.spyOn(link, 'click'); - - URL.createObjectURL = jest.fn().mockReturnValue('fake-url'); - download(new Blob(['test'], { type: 'text/plain' }), 'test.txt'); - - expect(appendChild).toHaveBeenCalledWith(link); - expect(link.href).toEqual('http://localhost/fake-url'); - expect(link.getAttribute('download')).toEqual('test.txt'); - expect(click).toHaveBeenCalledTimes(1); - }); -}); - describe('generateCsv', () => { it('generates a csv with formatted headers', async () => { const columns = [ @@ -58,32 +36,6 @@ describe('generateCsv', () => { }); }); -describe('csvDownloader', () => { - it('downloads a csv', () => { - const filename = 'test.csv'; - const data = { - rows: [ - { id: 1, name: 'John' }, - { id: 2, name: 'Alice' }, - ], - columns: [], - objectNameSingular: '', - }; - - const link = document.createElement('a'); - document.createElement = jest.fn().mockReturnValue(link); - const createObjectURL = jest.spyOn(URL, 'createObjectURL'); - - csvDownloader(filename, data); - - expect(link.getAttribute('download')).toEqual('test.csv'); - expect(createObjectURL).toHaveBeenCalledWith(expect.any(Blob)); - expect(createObjectURL).toHaveBeenCalledWith( - expect.objectContaining({ type: 'text/csv' }), - ); - }); -}); - describe('displayedExportProgress', () => { it.each([ [undefined, undefined, 'percentage', 'Export'], diff --git a/packages/twenty-front/src/modules/object-record/record-index/export/hooks/useExportRecords.ts b/packages/twenty-front/src/modules/object-record/record-index/export/hooks/useExportRecords.ts index 8053db0c0..4094adb1d 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/export/hooks/useExportRecords.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/export/hooks/useExportRecords.ts @@ -10,21 +10,12 @@ import { } from '@/object-record/record-index/export/hooks/useExportFetchRecords'; import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { saveAs } from 'file-saver'; import { RelationDefinitionType } from '~/generated-metadata/graphql'; import { FieldMetadataType } from '~/generated/graphql'; import { isDefined } from '~/utils/isDefined'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; -export const download = (blob: Blob, filename: string) => { - const url = URL.createObjectURL(blob); - const link = document.createElement('a'); - link.href = url; - link.setAttribute('download', filename); - document.body.appendChild(link); - link.click(); - link.parentNode?.removeChild(link); -}; - type GenerateExportOptions = { columns: ColumnDefinition[]; rows: object[]; @@ -128,7 +119,7 @@ export const displayedExportProgress = (progress?: ExportProgress): string => { const downloader = (mimeType: string, generator: GenerateExport) => { return (filename: string, data: GenerateExportOptions) => { const blob = new Blob([generator(data)], { type: mimeType }); - download(blob, filename); + saveAs(blob, filename); }; };