Skip to content

Commit

Permalink
Inrease coverage for file downloading
Browse files Browse the repository at this point in the history
  • Loading branch information
ipasic-softserve committed Nov 14, 2024
1 parent 3da892b commit be9f586
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 19 deletions.
6 changes: 5 additions & 1 deletion src/containers/course-section/resource-item/ResourceItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
} from '~/types'
import { getFormattedDate } from '~/utils/helper-functions'
import TitleWithDescription from '~/components/title-with-description/TitleWithDescription'
import { downloadFile } from '~/utils/download-file'

interface ResourceItemProps {
resource: CourseResource
Expand Down Expand Up @@ -210,7 +211,10 @@ const ResourceItem: FC<ResourceItemProps> = ({

if (type === ResourceType.Attachment) {
const fileName = (resource as Attachment).fileName
void ResourceService.downloadAttachment(resource._id, fileName)
void downloadFile(
ResourceService.downloadAttachment(resource._id),
fileName
)
return
}

Expand Down
14 changes: 2 additions & 12 deletions src/services/resource-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,21 +76,11 @@ export const ResourceService = {
headers: { 'Content-Type': 'multipart/form-data' }
})
},
downloadAttachment: async (id: string, fileName: string): Promise<void> => {
const response = await axiosClient.get(
downloadAttachment: async (id: string) => {
return axiosClient.get(
createUrlPath(URLs.resources.attachments.download, id),
{ responseType: 'blob' }
)

const url = window.URL.createObjectURL(new Blob([response.data]))
const link = document.createElement('a')
link.href = url
link.setAttribute('download', fileName)
document.body.appendChild(link)
link.click()
document.body.removeChild(link)

setTimeout(() => window.URL.revokeObjectURL(url), 100)
},
getQuestions: (
params?: GetResourcesParams
Expand Down
17 changes: 17 additions & 0 deletions src/utils/download-file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { AxiosResponse } from 'axios'

export async function downloadFile(
response: Promise<AxiosResponse>,
fileName: string
) {
const blobResponse = await response
const url = window.URL.createObjectURL(new Blob([blobResponse.data]))
const link = document.createElement('a')
link.href = url
link.setAttribute('download', fileName)
document.body.appendChild(link)
link.click()
document.body.removeChild(link)

setTimeout(() => window.URL.revokeObjectURL(url), 100)
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,16 @@ import {
} from '~tests/unit/containers/course-section/resource-item/ResourceItem.spec.constants'
import { ResourceService } from '~/services/resource-service'
import ResourceItem from '~/containers/course-section/resource-item/ResourceItem'
import { downloadFile } from '~/utils/download-file'

const mockDeleteResource = vi.fn()
const mockEditResource = vi.fn()
const mockUpdateAvailability = vi.fn()

vi.mock('~/utils/download-file', () => ({
downloadFile: vi.fn()
}))

vi.mock('@mui/x-date-pickers/LocalizationProvider', async () => {
const actual = await vi.importActual(
'@mui/x-date-pickers/LocalizationProvider'
Expand Down Expand Up @@ -310,13 +315,13 @@ describe('ResourceItem component', () => {
})
})

it('calls downloadAttachment if resource type is Attachment', () => {
it('calls downloadFile if resource type is Attachment', () => {
renderWithProviders(
<ResourceItem
resource={{
...mockResource,
resourceType: ResourceType.Attachment,
fileName: 'example.pdf'
fileName: 'example.png'
}}
resourceType={ResourceType.Attachment}
isView={true}
Expand All @@ -325,9 +330,6 @@ describe('ResourceItem component', () => {
)

fireEvent.click(screen.getByTestId('resourceItem'))
expect(ResourceService.downloadAttachment).toHaveBeenCalledWith(
'123',
'example.pdf'
)
expect(downloadFile).toHaveBeenCalled()
})
})
53 changes: 53 additions & 0 deletions tests/unit/utils/download-file.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { describe, it, vi, expect } from 'vitest'
import { downloadFile } from '~/utils/download-file'

describe('downloadFile', () => {
beforeEach(() => {
global.URL.createObjectURL = vi.fn(() => 'blob:http://localhost/test-url')
global.URL.revokeObjectURL = vi.fn(() => 'blob:http://localhost/test-url')
})

afterEach(() => {
vi.restoreAllMocks()
})

it('should download a file with the correct filename', async () => {
const mockData = 'test file content'
const mockResponse = Promise.resolve({
data: mockData
})

const mockUrl = 'blob:http://localhost/test-url'
const createObjectURLMock = vi
.spyOn(window.URL, 'createObjectURL')
.mockReturnValue(mockUrl)
const revokeObjectURLMock = vi.spyOn(window.URL, 'revokeObjectURL')

const link = {
href: '',
setAttribute: vi.fn(),
click: vi.fn()
}
const appendChildMock = vi
.spyOn(document.body, 'appendChild')
.mockImplementation(() => {})
const removeChildMock = vi
.spyOn(document.body, 'removeChild')
.mockImplementation(() => {})
vi.spyOn(document, 'createElement').mockReturnValue(link)

const fileName = 'test-file.txt'

await downloadFile(mockResponse, fileName)

expect(createObjectURLMock).toHaveBeenCalledOnce()
expect(createObjectURLMock).toHaveBeenCalledWith(new Blob([mockData]))
expect(link.setAttribute).toHaveBeenCalledWith('download', fileName)
expect(link.click).toHaveBeenCalledOnce()
expect(appendChildMock).toHaveBeenCalledWith(link)
expect(removeChildMock).toHaveBeenCalledWith(link)

await new Promise((resolve) => setTimeout(resolve, 150))
expect(revokeObjectURLMock).toHaveBeenCalledWith(mockUrl)
})
})

0 comments on commit be9f586

Please sign in to comment.