231 lines
5.9 KiB
JavaScript
231 lines
5.9 KiB
JavaScript
import PouchDB from 'pouchdb';
|
|
import memory from 'pouchdb-adapter-memory';
|
|
import {
|
|
PouchDBAttachmentProxy,
|
|
SENTRY_MIMETYPE,
|
|
blobToString,
|
|
stringToBlob
|
|
} from '../src/index.js';
|
|
|
|
const notDesignDocs = d => !d.id.startsWith('_design');
|
|
|
|
const dataUrlToBlob = data => {
|
|
const [header, b64str, ...nothing] = data.split(';base64,');
|
|
const byteCharacters = atob(b64str);
|
|
const byteNumbers = new Array(byteCharacters.length);
|
|
for (var i = 0; i < byteCharacters.length; i++) {
|
|
byteNumbers[i] = byteCharacters.charCodeAt(i);
|
|
}
|
|
const byteArray = new Uint8Array(byteNumbers);
|
|
return new Blob([byteArray], { type: header.substr(5) });
|
|
};
|
|
|
|
describe('PouchDB Attachment Proxy', () => {
|
|
let db;
|
|
let wrap = true;
|
|
|
|
const LocalStorageExampleAdapter = PouchDBAttachmentProxy({
|
|
getFn: async function getAttachment(blob) {
|
|
if (!wrap) {
|
|
return blob;
|
|
}
|
|
const id = await blobToString(blob);
|
|
return dataUrlToBlob(localStorage[id]);
|
|
},
|
|
remove: async function removeAttachment(blob) {
|
|
if (!wrap) {
|
|
return blob;
|
|
}
|
|
const id = await blobToString(blob);
|
|
delete localStorage[id];
|
|
},
|
|
save: async function saveAttachment(blob) {
|
|
if (!wrap) {
|
|
return blob;
|
|
}
|
|
let id;
|
|
while (!id || localStorage[id] !== undefined) {
|
|
id = '' + Math.ceil(Math.random() * 100000);
|
|
}
|
|
localStorage[id] = true; // placeholder to prevent a race condition while the FileReader reads the blob.
|
|
|
|
return new Promise(resolve => {
|
|
const reader = new FileReader();
|
|
|
|
reader.onloadend = function() {
|
|
localStorage[id] = reader.result;
|
|
resolve(stringToBlob(id));
|
|
};
|
|
reader.readAsDataURL(blob);
|
|
});
|
|
}
|
|
});
|
|
const PDB = PouchDB.plugin(memory).plugin(LocalStorageExampleAdapter);
|
|
|
|
beforeEach(() => {
|
|
db = new PDB('pouchdb-test', { adapter: 'memory' });
|
|
wrap = true;
|
|
});
|
|
|
|
afterEach(async () => {
|
|
const res = await db.allDocs();
|
|
await Promise.all(res.rows.filter(notDesignDocs).map(d => db.remove(d.id, d.value.rev))).catch(
|
|
() => {}
|
|
);
|
|
await db.compact();
|
|
});
|
|
|
|
async function checkBlob(blob, data) {
|
|
const blobData = await blobToString(blob);
|
|
expect(blobData).toEqual(data);
|
|
}
|
|
|
|
async function checkDocument(id, attName, mime_type, data) {
|
|
wrap = false;
|
|
const placeholderBlob = await db.getAttachment(id, attName);
|
|
wrap = true;
|
|
|
|
const placeholder = await blobToString(placeholderBlob);
|
|
|
|
expect(placeholderBlob.type).toEqual(SENTRY_MIMETYPE);
|
|
|
|
const resultDataStr = localStorage[placeholder];
|
|
const [header, b64str, ...nothing] = resultDataStr.split(';base64,');
|
|
expect(header.substr(5)).toEqual(mime_type);
|
|
expect(b64str).toEqual(btoa(data));
|
|
return resultDataStr;
|
|
}
|
|
|
|
describe('getFn()', () => {
|
|
it('returns attachments when PouchDB.getAttachment() is called', async () => {
|
|
const id = 'abc123';
|
|
localStorage['abc123'] = `data:text/plain;base64,${btoa('Test3 document')}`;
|
|
|
|
wrap = false;
|
|
await db.bulkDocs([
|
|
{
|
|
_id: 'test3',
|
|
_attachments: {
|
|
test3: {
|
|
content_type: SENTRY_MIMETYPE,
|
|
data: new Blob(['abc123'], { type: SENTRY_MIMETYPE })
|
|
}
|
|
}
|
|
}
|
|
]);
|
|
wrap = true;
|
|
|
|
const blob = await db.getAttachment('test3', 'test3');
|
|
checkBlob(blob, 'Test3 document');
|
|
expect(blob.type).toEqual('text/plain');
|
|
});
|
|
});
|
|
|
|
describe('save()', () => {
|
|
it('writes attachments in documents saved with PouchDB.put()', async () => {
|
|
await db.put({
|
|
_id: 'test1',
|
|
_attachments: {
|
|
test: {
|
|
content_type: 'text/plain',
|
|
data: new Blob(['Test document'], { type: 'text/plain' })
|
|
}
|
|
}
|
|
});
|
|
await checkDocument('test1', 'test', 'text/plain', 'Test document');
|
|
});
|
|
|
|
it('writes attachments in documents saved with PouchDB.bulkDocs()', async () => {
|
|
await db.bulkDocs([
|
|
{
|
|
_id: 'test2',
|
|
_attachments: {
|
|
test2: {
|
|
content_type: 'text/plain',
|
|
data: new Blob(['Test2 document'], { type: 'text/plain' })
|
|
}
|
|
}
|
|
}
|
|
]);
|
|
await checkDocument('test2', 'test2', 'text/plain', 'Test2 document');
|
|
});
|
|
|
|
it('writes attachments saved with PouchDB.putAttachment() ', async () => {
|
|
const res = await db.put({
|
|
_id: 'test5',
|
|
hi: 'there'
|
|
});
|
|
|
|
const res2 = await db.putAttachment(
|
|
res.id,
|
|
'test5',
|
|
res.rev,
|
|
new Blob(['Test5 document'], { type: 'text/plain' }),
|
|
'text/plain'
|
|
);
|
|
await checkDocument('test5', 'test5', 'text/plain', 'Test5 document');
|
|
});
|
|
});
|
|
|
|
describe('remove()', () => {
|
|
it('is called after PouchDB.removeAttachment()', async () => {
|
|
await db.bulkDocs([
|
|
{
|
|
_id: 'test4',
|
|
_attachments: {
|
|
test4: {
|
|
content_type: 'text/plain',
|
|
data: new Blob(['Test4 document'], { type: 'text/plain' })
|
|
}
|
|
}
|
|
}
|
|
]);
|
|
|
|
const doc = await db.get('test4', { attachments: true });
|
|
expect(doc && doc._attachments && doc._attachments.test4).toBeTruthy();
|
|
|
|
wrap = false;
|
|
const placeholderBlob = await db.getAttachment('test4', 'test4');
|
|
wrap = true;
|
|
|
|
const placeholder = await blobToString(placeholderBlob);
|
|
expect(placeholderBlob.type).toEqual(SENTRY_MIMETYPE);
|
|
expect(localStorage[placeholder]).toBeTruthy();
|
|
|
|
await db.removeAttachment(doc._id, 'test4', doc._rev);
|
|
|
|
const doc2 = await db.get('test4', { attachments: true });
|
|
expect(doc2._attachments).toBeFalsy();
|
|
|
|
expect(localStorage[placeholder]).toBeUndefined();
|
|
});
|
|
|
|
it('is called for attachments of deleted documents', async () => {
|
|
await db.bulkDocs([
|
|
{
|
|
_id: 'test6',
|
|
_attachments: {
|
|
test6: {
|
|
content_type: 'text/plain',
|
|
data: new Blob(['Test6 document'], { type: 'text/plain' })
|
|
}
|
|
}
|
|
}
|
|
]);
|
|
|
|
await checkDocument('test6', 'test6', 'text/plain', 'Test6 document');
|
|
|
|
wrap = false;
|
|
const placeholderBlob = await db.getAttachment('test6', 'test6');
|
|
wrap = true;
|
|
const placeholder = await blobToString(placeholderBlob);
|
|
|
|
const doc = await db.get('test6');
|
|
|
|
await db.remove(doc._id, doc._rev);
|
|
|
|
expect(localStorage[placeholder]).toBeUndefined();
|
|
});
|
|
});
|
|
});
|