Commit 683fde6a authored by Alejandro Celaya's avatar Alejandro Celaya Committed by Alejandro Celaya

Add helper functions to export all loaded annotations

parent 6f82c0ec
/**
* Download a file containing JSON-serialized `object` as `filename`
*
* @param data - JSON-serializable 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;
}
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);
});
});
...@@ -19,6 +19,7 @@ import { ...@@ -19,6 +19,7 @@ import {
import { ServiceContext } from './service-context'; import { ServiceContext } from './service-context';
import { AnnotationActivityService } from './services/annotation-activity'; import { AnnotationActivityService } from './services/annotation-activity';
import { AnnotationsService } from './services/annotations'; import { AnnotationsService } from './services/annotations';
import { AnnotationsExporter } from './services/annotations-exporter';
import { APIService } from './services/api'; import { APIService } from './services/api';
import { APIRoutesService } from './services/api-routes'; import { APIRoutesService } from './services/api-routes';
import { AuthService } from './services/auth'; import { AuthService } from './services/auth';
...@@ -119,6 +120,7 @@ function startApp(settings: SidebarSettings, appEl: HTMLElement) { ...@@ -119,6 +120,7 @@ function startApp(settings: SidebarSettings, appEl: HTMLElement) {
// Register services. // Register services.
container container
.register('annotationsExporter', AnnotationsExporter)
.register('annotationsService', AnnotationsService) .register('annotationsService', AnnotationsService)
.register('annotationActivity', AnnotationActivityService) .register('annotationActivity', AnnotationActivityService)
.register('api', APIService) .register('api', APIService)
......
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,
};
}
}
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,
});
});
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment