Skip to content

Commit

Permalink
Add helper functions to export all loaded annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
acelaya committed Jul 21, 2023
1 parent 1bfb577 commit 72b9d6b
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 0 deletions.
31 changes: 31 additions & 0 deletions src/shared/download-json-file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Provided an object and a filename, allows to generate a downloadable file
* containing a JSON-serialized version of that object
*
* @param _document - Test seam
* @return The contents of the downloaded file
* @throws {Error} If provided data cannot be JSON-serialized
*/
export function downloadJSONFile(
data: object,
filename: string,
/* istanbul ignore next */
_document = document
): string {
const link = _document.createElement('a');
const fileContent = JSON.stringify(data, null, 2);
const blob = new Blob([fileContent], {
type: 'application/json',
});
const url = URL.createObjectURL(blob);

link.setAttribute('href', url);
link.setAttribute('download', filename);
link.style.visibility = 'hidden';

_document.body.appendChild(link);
link.click();
_document.body.removeChild(link);

return fileContent;
}
43 changes: 43 additions & 0 deletions src/shared/test/download-json-file-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { downloadJSONFile } from '../download-json-file';

describe('download-json-file', () => {
let fakeLink;
let fakeDocument;

beforeEach(() => {
fakeLink = {
setAttribute: sinon.stub(),
click: sinon.stub(),
style: {},
};

fakeDocument = {
createElement: sinon.stub().returns(fakeLink),
body: {
appendChild: sinon.stub(),
removeChild: sinon.stub(),
},
};
});

it('generates export file with provided annotations', () => {
const filename = 'my-file.json';
const data = { foo: ['bar', 'baz'] };

const fileContent = downloadJSONFile(data, filename, fakeDocument);

assert.equal(fileContent, JSON.stringify(data, null, 2));

assert.calledWith(fakeDocument.createElement, 'a');
assert.calledWith(fakeDocument.body.appendChild, fakeLink);
assert.calledWith(fakeDocument.body.removeChild, fakeLink);

assert.calledWith(
fakeLink.setAttribute.firstCall,
'href',
sinon.match.string
);
assert.calledWith(fakeLink.setAttribute.secondCall, 'download', filename);
assert.equal('hidden', fakeLink.style.visibility);
});
});
2 changes: 2 additions & 0 deletions src/sidebar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
import { ServiceContext } from './service-context';
import { AnnotationActivityService } from './services/annotation-activity';
import { AnnotationsService } from './services/annotations';
import { AnnotationsExporter } from './services/annotations-exporter';
import { APIService } from './services/api';
import { APIRoutesService } from './services/api-routes';
import { AuthService } from './services/auth';
Expand Down Expand Up @@ -119,6 +120,7 @@ function startApp(settings: SidebarSettings, appEl: HTMLElement) {

// Register services.
container
.register('annotationsExporter', AnnotationsExporter)
.register('annotationsService', AnnotationsService)
.register('annotationActivity', AnnotationActivityService)
.register('api', APIService)
Expand Down
39 changes: 39 additions & 0 deletions src/sidebar/services/annotations-exporter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { Annotation } from '../../types/api';
import { VersionData } from '../helpers/version-data';
import type { SidebarStore } from '../store';

export type ExportContent = {
export_date: string;
export_userid: string;
client_version: string;
annotations: Annotation[];
};

/**
* Generates annotations exports
*
* @inject
*/
export class AnnotationsExporter {
private _store: SidebarStore;

constructor(store: SidebarStore) {
this._store = store;
}

/**
* @param now - Test seam
*/
buildExportContent(now = new Date()): ExportContent {
const profile = this._store.profile();
const annotations = this._store.allAnnotations();
const versionData = new VersionData(profile, []);

return {
export_date: now.toISOString(),
export_userid: profile.userid ?? '',
client_version: versionData.version,
annotations,
};
}
}
29 changes: 29 additions & 0 deletions src/sidebar/services/test/annotations-exporter-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { AnnotationsExporter } from '../annotations-exporter';

describe('AnnotationsExporter', () => {
let fakeStore;
let exporter;

beforeEach(() => {
fakeStore = {
profile: sinon.stub().returns({ userid: 'userId' }),
allAnnotations: sinon.stub(),
};
exporter = new AnnotationsExporter(fakeStore);
});

it('generates export content with provided annotations', () => {
const now = new Date();
const annotations = [{}, {}];
fakeStore.allAnnotations.returns(annotations);

const result = exporter.buildExportContent(now);

assert.deepEqual(result, {
export_date: now.toISOString(),
export_userid: 'userId',
client_version: '__VERSION__',
annotations,
});
});
});

0 comments on commit 72b9d6b

Please sign in to comment.