This repository has been archived on 2020-08-24. You can view files and clone it, but cannot push or open issues or pull requests.

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();
});
});
});