Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
457
gaia/apps/homescreen/test/unit/datastore_test.js
Executable file
457
gaia/apps/homescreen/test/unit/datastore_test.js
Executable file
|
|
@ -0,0 +1,457 @@
|
|||
/* global MockIndexedDB, MockNavigatorDatastore, mockLocalStorage, Datastore */
|
||||
'use strict';
|
||||
|
||||
require('/shared/test/unit/mocks/mock_indexedDB.js');
|
||||
require('/shared/test/unit/mocks/mock_navigator_datastore.js');
|
||||
require('mocks/mock_localStorage.js');
|
||||
require('/js/datastore.js');
|
||||
|
||||
suite('Datastore', () => {
|
||||
var mockIndexedDB;
|
||||
var realNavigatorDatastores;
|
||||
var realLocalStorage;
|
||||
var datastoreName = 'datastore_name_example';
|
||||
var bookmarks;
|
||||
|
||||
setup(() => {
|
||||
mockIndexedDB = new MockIndexedDB();
|
||||
mockLocalStorage.mSetup();
|
||||
Object.defineProperty(window, 'localStorage', {
|
||||
configurable: true,
|
||||
get: () => mockLocalStorage
|
||||
});
|
||||
realNavigatorDatastores = navigator.getDataStores;
|
||||
navigator.getDataStores = MockNavigatorDatastore.getDataStores;
|
||||
|
||||
bookmarks = new Datastore(datastoreName);
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
mockIndexedDB.mTearDown();
|
||||
Object.defineProperty(window, 'localStorage', {
|
||||
configurable: true,
|
||||
get: () => realLocalStorage
|
||||
});
|
||||
navigator.getDataStores = realNavigatorDatastores;
|
||||
|
||||
bookmarks = null;
|
||||
});
|
||||
|
||||
suite('Datastore constructor', () => {
|
||||
test('should store the name of the datastore', () => {
|
||||
assert.equal(bookmarks.name, datastoreName);
|
||||
assert.isTrue(bookmarks.revisionName.includes(datastoreName));
|
||||
assert.isTrue(bookmarks.idbName.includes(datastoreName));
|
||||
assert.isTrue(bookmarks.storeName.includes(datastoreName));
|
||||
});
|
||||
});
|
||||
|
||||
suite('Datastore#init()', () => {
|
||||
test('should open indexedDB and Datastore instances', done => {
|
||||
assert.isNull(bookmarks.db);
|
||||
assert.isNull(bookmarks.datastore);
|
||||
bookmarks.init().then(() => {
|
||||
assert.isObject(bookmarks.db);
|
||||
assert.isObject(bookmarks.datastore);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('Datastore#upgradeSchema()', () => {
|
||||
var names = [];
|
||||
var onUpgradeNeededEvent = version => {
|
||||
return {
|
||||
target: {
|
||||
result: {
|
||||
createObjectStore: (name, options) => {
|
||||
names.push(name);
|
||||
return {
|
||||
createIndex: (name, keyPath, options) => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
oldVersion: version
|
||||
};
|
||||
};
|
||||
|
||||
setup(() => {
|
||||
names = [];
|
||||
});
|
||||
|
||||
test('should create an object store with older versions', () => {
|
||||
bookmarks.upgradeSchema(onUpgradeNeededEvent(0));
|
||||
assert.deepEqual(names, [bookmarks.storeName]);
|
||||
});
|
||||
|
||||
test('should not create object stores with newer versions', () => {
|
||||
bookmarks.upgradeSchema(onUpgradeNeededEvent(2));
|
||||
assert.equal(names.length, 0);
|
||||
});
|
||||
});
|
||||
|
||||
suite('Datastore#synchronise()', () => {
|
||||
var stub;
|
||||
|
||||
setup(done => {
|
||||
// Bookmarks calls synchronise once the datastore is open and the
|
||||
// event handler is registered.
|
||||
stub = sinon.stub(bookmarks, 'synchronise', () => {
|
||||
stub.restore();
|
||||
done();
|
||||
});
|
||||
|
||||
bookmarks.init();
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
stub.restore();
|
||||
});
|
||||
|
||||
test('should call set() on update', done => {
|
||||
stub = sinon.stub(bookmarks, 'set');
|
||||
bookmarks.datastore._tasks[0] = {
|
||||
operation: 'update',
|
||||
id: 0,
|
||||
data: {}
|
||||
};
|
||||
bookmarks.synchronise().then(() => {
|
||||
assert.isTrue(stub.calledOnce);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('should call set() on add', done => {
|
||||
stub = sinon.stub(bookmarks, 'set');
|
||||
bookmarks.datastore._tasks[0] = {
|
||||
operation: 'add',
|
||||
id: 0,
|
||||
data: {}
|
||||
};
|
||||
bookmarks.synchronise().then(() => {
|
||||
assert.isTrue(stub.calledOnce);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('should call remove() on remove', done => {
|
||||
stub = sinon.stub(bookmarks, 'remove');
|
||||
bookmarks.datastore._tasks[0] = {
|
||||
operation: 'remove',
|
||||
id: 0,
|
||||
data: {}
|
||||
};
|
||||
bookmarks.synchronise().then(() => {
|
||||
assert.isTrue(stub.calledOnce);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('should call clear() on clear', done => {
|
||||
stub = sinon.stub(bookmarks, 'clear');
|
||||
bookmarks.datastore._tasks[0] = {
|
||||
operation: 'clear',
|
||||
id: 0,
|
||||
data: {}
|
||||
};
|
||||
bookmarks.synchronise().then(() => {
|
||||
assert.isTrue(stub.calledOnce);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('should call updateRevision() when done', done => {
|
||||
stub = sinon.stub(bookmarks, 'updateRevision');
|
||||
bookmarks.datastore._tasks = [{
|
||||
operation: 'done',
|
||||
id: 0,
|
||||
data: null
|
||||
}];
|
||||
bookmarks.synchronise().then(() => {
|
||||
assert.isTrue(stub.calledOnce);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('indexedDB backed methods', () => {
|
||||
var objectStores = {};
|
||||
var deletedValues = [];
|
||||
var attachDBTransaction = objectStoreName => {
|
||||
objectStores = {};
|
||||
deletedValues = [];
|
||||
bookmarks.db.transaction = (objectStoreNames, IDBTransactionMode) => {
|
||||
var oncomplete = null;
|
||||
return {
|
||||
objectStore: name => {
|
||||
return {
|
||||
put: value => {
|
||||
if (name !== objectStoreName) {
|
||||
return;
|
||||
}
|
||||
objectStores[name] = value;
|
||||
if (oncomplete) {
|
||||
oncomplete();
|
||||
oncomplete = null;
|
||||
}
|
||||
},
|
||||
delete: value => {
|
||||
if (name !== objectStoreName) {
|
||||
return;
|
||||
}
|
||||
deletedValues.push(value);
|
||||
if (oncomplete) {
|
||||
oncomplete();
|
||||
oncomplete = null;
|
||||
}
|
||||
},
|
||||
clear: () => {
|
||||
if (name !== objectStoreName) {
|
||||
return;
|
||||
}
|
||||
if (oncomplete) {
|
||||
oncomplete();
|
||||
oncomplete = null;
|
||||
}
|
||||
},
|
||||
get: () => {
|
||||
if (name !== objectStoreName) {
|
||||
return;
|
||||
}
|
||||
return {
|
||||
set onsuccess(cb) {
|
||||
cb({
|
||||
target: {
|
||||
result: { id: 'abc/', data: {} }
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
},
|
||||
openCursor: () => {
|
||||
return {
|
||||
set onsuccess(cb) {
|
||||
if (objectStoreNames.indexOf(name) === -1) {
|
||||
return;
|
||||
}
|
||||
cb({
|
||||
target: {
|
||||
result: {
|
||||
value: { id: 'abc/', data: {} },
|
||||
continue: () => {
|
||||
cb({
|
||||
target: {
|
||||
result: {
|
||||
value: { id: 'def/', data: {} },
|
||||
continue: () => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
if (oncomplete) {
|
||||
oncomplete();
|
||||
oncomplete = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
},
|
||||
set oncomplete(cb) {
|
||||
oncomplete = cb;
|
||||
},
|
||||
onerror: () => {}
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
setup(() => {
|
||||
bookmarks.db = {};
|
||||
});
|
||||
|
||||
suite('Datastore#set()', () => {
|
||||
var data = {
|
||||
id: 'abc/',
|
||||
misc: 'def'
|
||||
};
|
||||
|
||||
setup(() => {
|
||||
attachDBTransaction(bookmarks.storeName);
|
||||
});
|
||||
|
||||
test('should store data', done => {
|
||||
bookmarks.set(data)
|
||||
.then(() => {
|
||||
assert.equal(Object.keys(objectStores).length, 1);
|
||||
assert.equal(objectStores[bookmarks.storeName].id, data.id);
|
||||
assert.equal(objectStores[bookmarks.storeName].data, data);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('should emit an event', done => {
|
||||
document.addEventListener(bookmarks.name + '-set', evt => {
|
||||
assert.equal(evt.detail.id, data.id);
|
||||
done();
|
||||
});
|
||||
bookmarks.set(data);
|
||||
});
|
||||
|
||||
test('handles exception', done => {
|
||||
var realTransaction = bookmarks.db.transaction;
|
||||
bookmarks.db.transaction = (objectStoreNames, IDBTransactionMode) => {
|
||||
var txn = realTransaction(objectStores, IDBTransactionMode);
|
||||
var realObjectStore = txn.objectStore;
|
||||
txn.objectStore = objectStoreName => {
|
||||
var objectStore = realObjectStore(objectStoreName);
|
||||
sinon.stub(objectStore, 'put', () => {
|
||||
throw 'this exception should be caught';
|
||||
});
|
||||
return objectStore;
|
||||
};
|
||||
return txn;
|
||||
};
|
||||
bookmarks.set(data).then(done, done);
|
||||
});
|
||||
});
|
||||
|
||||
suite('Datastore#remove()', () => {
|
||||
var id = 'abc/';
|
||||
|
||||
setup(() => {
|
||||
attachDBTransaction(bookmarks.storeName);
|
||||
});
|
||||
|
||||
test('should remove data from object store', done => {
|
||||
bookmarks.remove(id)
|
||||
.then(() => {
|
||||
assert.deepEqual(deletedValues, [id]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('should emit an event', done => {
|
||||
document.addEventListener(bookmarks.name + '-removed', evt => {
|
||||
assert.equal(evt.detail.id, id);
|
||||
done();
|
||||
});
|
||||
bookmarks.remove(id);
|
||||
});
|
||||
|
||||
test('handles exception', done => {
|
||||
var realTransaction = bookmarks.db.transaction;
|
||||
bookmarks.db.transaction = (objectStoreNames, IDBTransactionMode) => {
|
||||
var txn = realTransaction(objectStores, IDBTransactionMode);
|
||||
var realObjectStore = txn.objectStore;
|
||||
txn.objectStore = objectStoreName => {
|
||||
var objectStore = realObjectStore(objectStoreName);
|
||||
sinon.stub(objectStore, 'delete', () => {
|
||||
throw 'this exception should be caught';
|
||||
});
|
||||
return objectStore;
|
||||
};
|
||||
return txn;
|
||||
};
|
||||
bookmarks.remove(id).then(done, done);
|
||||
});
|
||||
});
|
||||
|
||||
suite('Datastore#clear()', () => {
|
||||
test('should remove all data from object store', done => {
|
||||
attachDBTransaction(bookmarks.storeName);
|
||||
bookmarks.clear()
|
||||
.then(() => {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('should emit an event', done => {
|
||||
attachDBTransaction(bookmarks.storeName);
|
||||
document.addEventListener(bookmarks.name + '-cleared', () => {
|
||||
done();
|
||||
});
|
||||
bookmarks.clear();
|
||||
});
|
||||
});
|
||||
|
||||
suite('Datastore#get()', () => {
|
||||
test('should retrieve data from object store', done => {
|
||||
attachDBTransaction(bookmarks.storeName);
|
||||
bookmarks.get('abc/')
|
||||
.then(results => {
|
||||
assert.deepEqual(results, { id: 'abc/', data: {} });
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('Datastore#getAll()', () => {
|
||||
test('should retrieve data from object store', done => {
|
||||
attachDBTransaction(bookmarks.storeName);
|
||||
bookmarks.getAll()
|
||||
.then(results => {
|
||||
assert.equal(results.length, 2);
|
||||
assert.deepEqual(results[0], { id: 'abc/', data: {} });
|
||||
assert.deepEqual(results[1], { id: 'def/', data: {} });
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('should accept a filtering function as argument', done => {
|
||||
attachDBTransaction(bookmarks.storeName);
|
||||
bookmarks.getAll(entry => entry.id.includes('def/'))
|
||||
.then(results => {
|
||||
assert.equal(results.length, 1);
|
||||
assert.deepEqual(results[0], { id: 'def/', data: {} });
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('Datastore#updateRevision()', () => {
|
||||
setup(done => {
|
||||
bookmarks.init().then(done);
|
||||
});
|
||||
|
||||
test('should set the datastore revision ID in lastRevision', () => {
|
||||
assert.isNull(bookmarks.lastRevision);
|
||||
bookmarks.updateRevision();
|
||||
assert.equal(bookmarks.lastRevision, bookmarks.datastore.revisionId);
|
||||
});
|
||||
|
||||
test('should update the datastore revision ID in lastRevision', done => {
|
||||
var newRevisionId = 'xxx-zzz';
|
||||
bookmarks.datastore._tasks = [{
|
||||
operation: 'done',
|
||||
id: 0,
|
||||
data: null
|
||||
}];
|
||||
|
||||
bookmarks.datastore.revisionId = newRevisionId;
|
||||
|
||||
bookmarks.synchronise().then(() => {
|
||||
bookmarks.init().then(() => {
|
||||
assert.equal(bookmarks.lastRevision, newRevisionId);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('Datastore#onChange()', () => {
|
||||
test('should call synchronise()', done => {
|
||||
var synchroniseStub = sinon.stub(bookmarks, 'synchronise',
|
||||
() => Promise.resolve());
|
||||
bookmarks.onChange();
|
||||
setTimeout(() => {
|
||||
assert.isTrue(synchroniseStub.calledOnce);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Reference in a new issue