Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: download-file service #1236

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions src/app/services/download-file.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { FileFormat } from '@app/types/file.type';
import DownloadService from './download-file.service';

describe('download-file function', () => {
const service = new DownloadService();
const anchor = {
href: '',
download: '',
click: jest.fn()
};

const mockId = 1234;
const mockDate = '2024 01 01';

global.document.createElement = jest.fn().mockReturnValue(anchor);
global.URL.createObjectURL = jest.fn();

global.Date.prototype.getTime = jest.fn(() => mockId);
global.Date.prototype.toISOString = jest.fn(() => mockDate);

const name = 'settings';
const format: FileFormat = 'csv';

const data = JSON.stringify([1, 2, 3]);

it('should download the settings', () => {
service.downloadFile(data, name, format);
expect(anchor.download).toEqual(`${mockDate}-${mockId}-${name}.${format}`);
});

it('should download the settings with default configuration', () => {
service.downloadFile(data);
expect(anchor.download).toContain(`${mockDate}-${mockId}.json`);
});

it('should click the anchor', () => {
service.downloadFile(data);
expect(anchor.click).toHaveBeenCalled();
});
});
21 changes: 21 additions & 0 deletions src/app/services/download-file.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Injectable } from '@angular/core';
import { FileFormat } from '@app/types/file.type';

@Injectable()
export default class DownloadService {
/**
* Download data into a json or csv file. The file name will be as following: "date-id-name.format".
* the Id is the current time in seconds.
*/
downloadFile(data: BlobPart, name?: string, format?: FileFormat) {
const blob = new Blob([data], { type: `application/${format ?? 'json'}` });
const url = URL.createObjectURL(blob);
const date = new Date().toISOString().slice(0, 10);
const id = new Date().getTime();

const anchor = document.createElement('a');
anchor.href = url;
anchor.download = `${date}-${id}${name ? '-' + name : ''}.${format ?? 'json'}`;
anchor.click();
}
}
26 changes: 9 additions & 17 deletions src/app/settings/index.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { MatCheckboxChange } from '@angular/material/checkbox';
import { MatDialog } from '@angular/material/dialog';
import { Key } from '@app/types/config';
import { Sidebar, SidebarItem } from '@app/types/navigation';
import DownloadService from '@services/download-file.service';
import { IconsService } from '@services/icons.service';
import { NavigationService } from '@services/navigation.service';
import { NotificationService } from '@services/notification.service';
Expand Down Expand Up @@ -127,6 +128,10 @@ describe('IndexComponent', () => {
get: jest.fn()
};

const mockDownloadService = {
downloadFile: jest.fn()
};

beforeEach(() => {
component = TestBed.configureTestingModule({
providers: [
Expand All @@ -137,6 +142,7 @@ describe('IndexComponent', () => {
{ provide: StorageService, useValue: mockStorageService },
{ provide: MatDialog, useValue: mockDialog },
{ provide: HttpClient, useValue: mockHttpClient },
{ provide: DownloadService, useValue: mockDownloadService },
]
}).inject(IndexComponent);
component.ngOnInit();
Expand Down Expand Up @@ -306,27 +312,13 @@ describe('IndexComponent', () => {
});
});

describe('exportData', () => {
const anchor = {
href: '',
download: '',
click: jest.fn()
};

global.document.createElement = jest.fn().mockReturnValue(anchor);

global.URL.createObjectURL = jest.fn();

describe('exportData', () => {
beforeEach(() => {
component.exportData();
});

it('should download the settings', () => {
expect(anchor.download).toContain('settings.json');
});

it('should click the anchor', () => {
expect(anchor.click).toHaveBeenCalled();
it('should call downloadFile', () => {
expect(mockDownloadService.downloadFile).toHaveBeenCalled();
});

it('should notify on success', () => {
Expand Down
13 changes: 4 additions & 9 deletions src/app/settings/index.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { Sidebar, SidebarItem } from '@app/types/navigation';
import { PageHeaderComponent } from '@components/page-header.component';
import { PageSectionHeaderComponent } from '@components/page-section-header.component';
import { PageSectionComponent } from '@components/page-section.component';
import DownloadService from '@services/download-file.service';
import { IconsService } from '@services/icons.service';
import { NavigationService } from '@services/navigation.service';
import { NotificationService } from '@services/notification.service';
Expand Down Expand Up @@ -129,6 +130,7 @@ main {
providers: [
QueryParamsService,
NotificationService,
DownloadService,
],
imports: [
PageHeaderComponent,
Expand Down Expand Up @@ -159,6 +161,7 @@ export class IndexComponent implements OnInit {
private readonly navigationService = inject(NavigationService);
private readonly storageService = inject(StorageService);
private readonly httpClient = inject(HttpClient);
private readonly downloadService = inject(DownloadService);

ngOnInit(): void {
this.keys = this.sortKeys(this.storageService.restoreKeys());
Expand Down Expand Up @@ -271,15 +274,7 @@ export class IndexComponent implements OnInit {
exportData(): void {
const data = JSON.stringify(this.storageService.exportData());

const blob = new Blob([data], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const date = new Date().toISOString().slice(0, 10);
const id = new Date().getTime();

const anchor = document.createElement('a');
anchor.href = url;
anchor.download = `${date}-${id}-settings.json`;
anchor.click();
this.downloadService.downloadFile(data, 'settings', 'json');

this.notificationService.success('Settings exported');
}
Expand Down
1 change: 1 addition & 0 deletions src/app/types/file.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type FileFormat = 'json' | 'csv';
Loading