mirror of
https://github.com/langgenius/dify.git
synced 2026-02-09 23:20:12 -05:00
refactor(web): consolidate download helpers (#31664)
This commit is contained in:
75
web/utils/download.spec.ts
Normal file
75
web/utils/download.spec.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { downloadBlob, downloadUrl } from './download'
|
||||
|
||||
describe('downloadUrl', () => {
|
||||
let mockAnchor: HTMLAnchorElement
|
||||
|
||||
beforeEach(() => {
|
||||
mockAnchor = {
|
||||
href: '',
|
||||
download: '',
|
||||
rel: '',
|
||||
target: '',
|
||||
style: { display: '' },
|
||||
click: vi.fn(),
|
||||
remove: vi.fn(),
|
||||
} as unknown as HTMLAnchorElement
|
||||
|
||||
vi.spyOn(document, 'createElement').mockReturnValue(mockAnchor)
|
||||
vi.spyOn(document.body, 'appendChild').mockImplementation((node: Node) => node)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks()
|
||||
})
|
||||
|
||||
it('should create a link and trigger a download correctly', () => {
|
||||
downloadUrl({ url: 'https://example.com/file.txt', fileName: 'file.txt', target: '_blank' })
|
||||
|
||||
expect(mockAnchor.href).toBe('https://example.com/file.txt')
|
||||
expect(mockAnchor.download).toBe('file.txt')
|
||||
expect(mockAnchor.rel).toBe('noopener noreferrer')
|
||||
expect(mockAnchor.target).toBe('_blank')
|
||||
expect(mockAnchor.style.display).toBe('none')
|
||||
expect(mockAnchor.click).toHaveBeenCalled()
|
||||
expect(mockAnchor.remove).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should skip when url is empty', () => {
|
||||
downloadUrl({ url: '' })
|
||||
expect(document.createElement).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('downloadBlob', () => {
|
||||
it('should create a blob url, trigger download, and revoke url', () => {
|
||||
const blob = new Blob(['test'], { type: 'text/plain' })
|
||||
const mockUrl = 'blob:mock-url'
|
||||
const createObjectURLMock = vi.spyOn(window.URL, 'createObjectURL').mockReturnValue(mockUrl)
|
||||
const revokeObjectURLMock = vi.spyOn(window.URL, 'revokeObjectURL').mockImplementation(() => {})
|
||||
|
||||
const mockAnchor = {
|
||||
href: '',
|
||||
download: '',
|
||||
rel: '',
|
||||
target: '',
|
||||
style: { display: '' },
|
||||
click: vi.fn(),
|
||||
remove: vi.fn(),
|
||||
} as unknown as HTMLAnchorElement
|
||||
|
||||
vi.spyOn(document, 'createElement').mockReturnValue(mockAnchor)
|
||||
vi.spyOn(document.body, 'appendChild').mockImplementation((node: Node) => node)
|
||||
|
||||
downloadBlob({ data: blob, fileName: 'file.txt' })
|
||||
|
||||
expect(createObjectURLMock).toHaveBeenCalledWith(blob)
|
||||
expect(mockAnchor.href).toBe(mockUrl)
|
||||
expect(mockAnchor.download).toBe('file.txt')
|
||||
expect(mockAnchor.rel).toBe('noopener noreferrer')
|
||||
expect(mockAnchor.click).toHaveBeenCalled()
|
||||
expect(mockAnchor.remove).toHaveBeenCalled()
|
||||
expect(revokeObjectURLMock).toHaveBeenCalledWith(mockUrl)
|
||||
|
||||
vi.restoreAllMocks()
|
||||
})
|
||||
})
|
||||
@@ -1,4 +1,4 @@
|
||||
import { downloadFile, formatFileSize, formatNumber, formatNumberAbbreviated, formatTime } from './format'
|
||||
import { formatFileSize, formatNumber, formatNumberAbbreviated, formatTime } from './format'
|
||||
|
||||
describe('formatNumber', () => {
|
||||
it('should correctly format integers', () => {
|
||||
@@ -82,49 +82,6 @@ describe('formatTime', () => {
|
||||
expect(formatTime(7200)).toBe('2.00 h')
|
||||
})
|
||||
})
|
||||
describe('downloadFile', () => {
|
||||
it('should create a link and trigger a download correctly', () => {
|
||||
// Mock data
|
||||
const blob = new Blob(['test content'], { type: 'text/plain' })
|
||||
const fileName = 'test-file.txt'
|
||||
const mockUrl = 'blob:mockUrl'
|
||||
|
||||
// Mock URL.createObjectURL
|
||||
const createObjectURLMock = vi.fn().mockReturnValue(mockUrl)
|
||||
const revokeObjectURLMock = vi.fn()
|
||||
Object.defineProperty(window.URL, 'createObjectURL', { value: createObjectURLMock })
|
||||
Object.defineProperty(window.URL, 'revokeObjectURL', { value: revokeObjectURLMock })
|
||||
|
||||
// Mock createElement and appendChild
|
||||
const mockLink = {
|
||||
href: '',
|
||||
download: '',
|
||||
click: vi.fn(),
|
||||
remove: vi.fn(),
|
||||
}
|
||||
const createElementMock = vi.spyOn(document, 'createElement').mockReturnValue(mockLink as any)
|
||||
const appendChildMock = vi.spyOn(document.body, 'appendChild').mockImplementation((node: Node) => {
|
||||
return node
|
||||
})
|
||||
|
||||
// Call the function
|
||||
downloadFile({ data: blob, fileName })
|
||||
|
||||
// Assertions
|
||||
expect(createObjectURLMock).toHaveBeenCalledWith(blob)
|
||||
expect(createElementMock).toHaveBeenCalledWith('a')
|
||||
expect(mockLink.href).toBe(mockUrl)
|
||||
expect(mockLink.download).toBe(fileName)
|
||||
expect(appendChildMock).toHaveBeenCalledWith(mockLink)
|
||||
expect(mockLink.click).toHaveBeenCalled()
|
||||
expect(mockLink.remove).toHaveBeenCalled()
|
||||
expect(revokeObjectURLMock).toHaveBeenCalledWith(mockUrl)
|
||||
|
||||
// Clean up mocks
|
||||
vi.restoreAllMocks()
|
||||
})
|
||||
})
|
||||
|
||||
describe('formatNumberAbbreviated', () => {
|
||||
it('should return number as string when less than 1000', () => {
|
||||
expect(formatNumberAbbreviated(0)).toBe('0')
|
||||
|
||||
@@ -100,17 +100,6 @@ export const formatTime = (seconds: number) => {
|
||||
return `${seconds.toFixed(2)} ${units[index]}`
|
||||
}
|
||||
|
||||
export const downloadFile = ({ data, fileName }: { data: Blob, fileName: string }) => {
|
||||
const url = window.URL.createObjectURL(data)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = fileName
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
a.remove()
|
||||
window.URL.revokeObjectURL(url)
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a number into a readable string using "k", "M", or "B" suffix.
|
||||
* @example
|
||||
|
||||
Reference in New Issue
Block a user