Skip to content

Commit

Permalink
feature: updated downloadFile function and unit tests to cover new …
Browse files Browse the repository at this point in the history
…functionality
  • Loading branch information
= authored and Zlaylink committed Aug 29, 2024
1 parent 7e5aa1f commit 5d42341
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 17 deletions.
77 changes: 63 additions & 14 deletions packages/common/src/download-file.function.spec.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,72 @@
import { blobMock, jsonMock, nameMock } from '@bimeister/utilities.internal';
import { downloadFile } from './download-file.function';

describe('download-file.function.ts', () => {
const fileNameSample: string = nameMock;
const originalCreateObjectURL: (obj: Blob | MediaSource) => string = URL.createObjectURL;
const originalRevokeObjectURL: (url: string) => void = URL.revokeObjectURL;
let anchorClickSpy: jest.SpyInstance;

document.body.innerHTML = ``;
window.URL.createObjectURL = (): string => nameMock;
beforeEach(() => {
URL.createObjectURL = jest.fn(() => 'blob:http://localhost/sample');
URL.revokeObjectURL = jest.fn();

it('should create new DOM-element if data is Blob', () => {
const fileSample: Blob = blobMock;
downloadFile(fileNameSample, fileSample);
const aElement: HTMLAnchorElement | null = document.querySelector('a');
expect(aElement).toBeDefined();
anchorClickSpy = jest.spyOn(HTMLAnchorElement.prototype, 'click').mockImplementation();

document.body.innerHTML = '';
});

afterEach(() => {
URL.createObjectURL = originalCreateObjectURL;
URL.revokeObjectURL = originalRevokeObjectURL;
anchorClickSpy.mockRestore();
});

it('should create new DOM-element if data is string', () => {
const fileSample: string = jsonMock;
downloadFile(fileNameSample, fileSample);
const aElement: HTMLAnchorElement | null = document.querySelector('a');
expect(aElement).toBeDefined();
it('should create an anchor element and trigger download using a presigned URL', () => {
const presignedUrl: string = 'https://example.com/path/to/file';

downloadFile(presignedUrl);

const anchor: HTMLAnchorElement | null = document.querySelector('a');
expect(anchor).toBeNull();
expect(anchorClickSpy).toHaveBeenCalledTimes(1);
});

it('should create an anchor element and download a file from a Blob', () => {
const filename: string = 'example.txt';
const blobData: Blob = new Blob(['Hello, world!'], { type: 'text/plain' });

downloadFile(filename, blobData);

const anchor: HTMLAnchorElement | null = document.querySelector('a');
expect(anchor).toBeNull();
expect(URL.createObjectURL).toHaveBeenCalledWith(blobData);
expect(URL.revokeObjectURL).toHaveBeenCalledWith('blob:http://localhost/sample');
expect(anchorClickSpy).toHaveBeenCalledTimes(1);
});

it('should create an anchor element and download a file from a string', () => {
const filename: string = 'example.txt';
const stringData: string = 'Sample data content';

downloadFile(filename, stringData);

const anchor: HTMLAnchorElement | null = document.querySelector('a');
expect(anchor).toBeNull();
expect(URL.createObjectURL).toHaveBeenCalledTimes(1);
expect(URL.revokeObjectURL).toHaveBeenCalledWith('blob:http://localhost/sample');
expect(anchorClickSpy).toHaveBeenCalledTimes(1);
});

it('should create an anchor element and download a file from a BlobPart (typed array)', () => {
const filename: string = 'example.bin';
const typedArray: Uint8Array = new Uint8Array([72, 101, 108, 108, 111]); // "Hello" in ASCII

downloadFile(filename, typedArray);

const anchor: HTMLAnchorElement | null = document.querySelector('a');
expect(anchor).toBeNull();
const expectedBlob: Blob = new Blob([typedArray]);
expect(URL.createObjectURL).toHaveBeenCalledWith(expectedBlob);
expect(URL.revokeObjectURL).toHaveBeenCalledWith('blob:http://localhost/sample');
expect(anchorClickSpy).toHaveBeenCalledTimes(1);
});
});
47 changes: 44 additions & 3 deletions packages/common/src/download-file.function.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,49 @@
export function downloadFile(filename: string, data: Blob | string): void {
const dataBlob: Blob = data instanceof Blob ? data : new Blob([data]);
/* eslint-disable @typescript-eslint/unified-signatures */
import { isNil } from './is-nil.function';

/**
* Initiates a file download using a pre-signed URL.
*
* @param presignedUrl - The pre-signed URL from which the file will be downloaded.
*
* @example
* Download a file from a pre-signed URL:
* downloadFile('https://example.com/path/to/file');
*/
export function downloadFile(presignedUrl: string): void;

/**
* Creates and downloads a file from the provided data.
*
* @param filename - The name under which the file will be saved.
* @param data - The data to be downloaded, provided as BlobPart.
*
* @example
* Download a file from Blob data:
* const data = new Blob(['Hello, world!'], { type: 'text/plain' });
* downloadFile('example.txt', data);
*
* @example
* Download a file from string data:
* const dataString = "Sample data content";
* downloadFile('example.txt', dataString);
*/
export function downloadFile(filename: string, data: BlobPart): void;

export function downloadFile(filenameOrPresignedUrl: string, data?: BlobPart): void {
if (isNil(data)) {
const anchor: HTMLAnchorElement = document.createElement('a');
anchor.href = filenameOrPresignedUrl;
anchor.click();
anchor.remove();
return;
}

const dataBlob: Blob = data instanceof Blob ? data : new Blob([data]);
const anchor: HTMLAnchorElement = document.createElement('a');
anchor.href = URL.createObjectURL(dataBlob);
anchor.download = filename;
anchor.download = filenameOrPresignedUrl;
anchor.click();
URL.revokeObjectURL(anchor.href);
anchor.remove();
}

0 comments on commit 5d42341

Please sign in to comment.