Skip to content
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';