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:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View file

@ -0,0 +1,933 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
/* global
asyncStorage,
BOOKMARKS_COLLECTION_MTIME,
BOOKMARKS_LAST_REVISIONID,
BOOKMARKS_SYNCTOID_PREFIX,
BookmarksHelper,
DataAdapters,
ERROR_SYNC_APP_RACE_CONDITION,
MockasyncStorage,
MockDatastore,
MockLazyLoader,
MockNavigatorDatastore
*/
require('/shared/js/sync/errors.js');
require('/shared/test/unit/mocks/mock_lazy_loader.js');
require('/shared/test/unit/mocks/mock_navigator_datastore.js');
require('/apps/system/test/unit/mock_asyncStorage.js');
requireApp('sync/js/adapters/bookmarks.js');
window.DataAdapters = {};
suite('sync/adapters/bookmarks >', function() {
var realDatastore, realLazyLoader, realAsyncStorage, testCollectionData;
var kintoCollection = {
list() {
return Promise.resolve({
data: testCollectionData
});
}
};
function getBookmarksStore() {
return navigator.getDataStores().then(stores => {
return Promise.resolve(stores[0]);
});
}
function verifyBookmarks(collectionItem, bookmarksItem) {
var payload = collectionItem.payload;
var keys = [
'id',
'type',
'iconable',
'icon',
'createdLocally',
'fxsyncRecords'
];
if (payload.type !== 'separator') {
keys.push('name');
}
if (['bookmark', 'query'].indexOf(payload.type) !== -1) {
keys.push('url');
}
assert.equal(Object.keys(bookmarksItem).length, keys.length);
keys.forEach(key => assert.equal(bookmarksItem.hasOwnProperty(key), true));
switch (payload.type) {
case 'bookmark':
assert.equal(payload.bmkUri, bookmarksItem.id);
assert.equal(payload.bmkUri, bookmarksItem.url);
assert.equal(payload.title, bookmarksItem.name);
assert.deepEqual(payload, bookmarksItem.fxsyncRecords[payload.id]);
assert.equal('url', bookmarksItem.type);
break;
case 'query':
assert.equal(payload.type + '|' + payload.id, bookmarksItem.id);
assert.equal(payload.bmkUri, bookmarksItem.url);
assert.equal(payload.title, bookmarksItem.name);
assert.deepEqual(payload, bookmarksItem.fxsyncRecords[payload.id]);
assert.equal('others', bookmarksItem.type);
break;
case 'folder':
assert.equal(payload.type + '|' + payload.id, bookmarksItem.id);
assert.equal(payload.title, bookmarksItem.name);
assert.deepEqual(payload, bookmarksItem.fxsyncRecords[payload.id]);
assert.equal('others', bookmarksItem.type);
break;
case 'livemark':
assert.equal(payload.type + '|' + payload.id, bookmarksItem.id);
assert.equal(payload.title, bookmarksItem.name);
assert.deepEqual(payload, bookmarksItem.fxsyncRecords[payload.id]);
assert.equal('others', bookmarksItem.type);
break;
case 'separator':
assert.equal(payload.type + '|' + payload.id, bookmarksItem.id);
assert.deepEqual(payload, bookmarksItem.fxsyncRecords[payload.id]);
assert.equal('others', bookmarksItem.type);
break;
case 'microsummary':
console.warn('microsummary is OBSOLETED ', payload);
break;
default:
assert.ok(false, 'Unknown type');
}
}
function testDataGenerator(initIndex, initDate, count) {
var list = [];
for (var i = initIndex; i < initIndex + count; i++) {
var visits = [];
var startData = initDate + i * 100;
for (var j = 0; j < 3; j++) {
visits.push({
date: (startData + j * 10) * 1000, type: 3
});
}
list.unshift({
id: 'UNIQUE_ID_' + i,
last_modified: initDate + i * 10,
payload: {
id: 'UNIQUE_ID_' + i,
bmkUri: 'http://example' + i + '.com/',
title: 'Example ' + i + ' Title',
type: 'bookmark'
}
});
}
return list;
}
suiteSetup(() => {
realDatastore = navigator.getDataStores;
realAsyncStorage = window.asyncStorage;
window.asyncStorage = MockasyncStorage;
realLazyLoader = window.LazyLoader;
window.LazyLoader = MockLazyLoader;
});
suiteTeardown(() => {
navigator.getDataStores = realDatastore;
window.LazyLoader = realLazyLoader;
window.asyncStorage = realAsyncStorage;
});
setup(() => {
navigator.getDataStores = MockNavigatorDatastore.getDataStores;
testCollectionData = [];
MockDatastore._tasks[1].revisionId = 'latest-not-cleared';
});
teardown(() => {
MockDatastore._inError = false;
MockDatastore._records = Object.create(null);
window.asyncStorage.mTeardown();
});
test('update - empty records', function(done) {
var bookmarksAdapter = DataAdapters.bookmarks;
bookmarksAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
.then(result => {
assert.equal(result, false);
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
null);
assert.equal(asyncStorage.mItems[BOOKMARKS_LAST_REVISIONID], null);
}).then(done, reason => {
done(reason || new Error('Rejected by undefined reason.'));
});
});
['clear', 'remove'].forEach(task => {
suite(`after a DataStore ${task}`, function() {
suiteSetup(function() {
MockDatastore._taskCounter = 0;
MockDatastore._tasks = [
{
operation: 'clear',
id: 0,
data: {}
},
{
operation: 'add',
id: 0,
data: {}
},
{
operation: task,
id: 0,
data: {}
},
{
operation: 'done',
id: 0,
revisionId: `latest-after-${task}`,
data: null
}
];
});
suiteTeardown(function() {
MockDatastore._taskCounter = 0;
MockDatastore._tasks = [
{
operation: 'update',
id: 0,
data: {}
},
{
operation: 'done',
id: 0,
data: null,
revisionId: 'latest-not-cleared'
}
];
});
test('update - refills the DataStore', function(done) {
var bookmarksAdapter = DataAdapters.bookmarks;
testCollectionData = testDataGenerator(1, 1440000000, 5);
asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME] =
testCollectionData[0].last_modified;
bookmarksAdapter.update(kintoCollection,
{ readonly: true, userid: 'foo' })
.then(() => {
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
testCollectionData[0].last_modified);
getBookmarksStore().then(bookmarksStore => {
var ids = testCollectionData.map(item => {
return item.payload.bmkUri;
});
bookmarksStore.get.apply(bookmarksStore, ids).then(list => {
for (var i = 0; i < ids.length; i++) {
verifyBookmarks(testCollectionData[i], list[i]);
assert.equal(
asyncStorage.mItems['foo' + BOOKMARKS_SYNCTOID_PREFIX +
testCollectionData[i].id],
testCollectionData[i].payload.bmkUri);
}
assert.equal(asyncStorage.mItems[
'foo' + BOOKMARKS_LAST_REVISIONID], `latest-after-${task}`);
done();
});
});
});
});
});
});
test('update - does not refill the DataStore if nothing removed locally',
function(done) {
var bookmarksAdapter = DataAdapters.bookmarks;
testCollectionData = testDataGenerator(1, 1440000000, 5);
asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME] =
testCollectionData[0].last_modified;
bookmarksAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
.then(() => {
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
testCollectionData[0].last_modified);
getBookmarksStore().then(bookmarksStore => {
var ids = testCollectionData.map(item => {
return item.payload.bmkUri;
});
bookmarksStore.get.apply(bookmarksStore, ids).then(list => {
for (var i = 0; i < ids.length; i++) {
assert.equal(list[i], null);
}
assert.equal(asyncStorage.mItems[
'foo' + BOOKMARKS_LAST_REVISIONID], 'latest-not-cleared');
done();
});
});
});
});
suite('if a DataStore race condition occurs', function() {
setup(function() {
MockDatastore._raceCondition = true;
});
teardown(function() {
delete MockDatastore._raceCondition;
});
test('update - rejects its promise', function(done) {
var bookmarksAdapter = DataAdapters.bookmarks;
var lazyLoaderSpy = this.sinon.spy(MockLazyLoader, 'load');
testCollectionData = testDataGenerator(1, 1440000000, 5);
bookmarksAdapter.update(kintoCollection,
{ readonly: true, userid: 'foo' }).catch(error => {
assert.equal(lazyLoaderSpy.calledWith(['shared/js/sync/errors.js']),
true);
assert.equal(error.message, ERROR_SYNC_APP_RACE_CONDITION);
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
null);
done();
});
});
});
test('update - 1 sync request with 5 new records', function(done) {
var bookmarksAdapter = DataAdapters.bookmarks;
var lazyLoaderSpy = this.sinon.spy(MockLazyLoader, 'load');
testCollectionData = testDataGenerator(1, 1440000000, 5);
bookmarksAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
.then(result => {
var mTime = testCollectionData[0].last_modified;
assert.equal(result, false);
assert.equal(lazyLoaderSpy.calledWith(['shared/js/async_storage.js']),
true);
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
mTime);
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
'latest-not-cleared');
return Promise.resolve();
}).then(getBookmarksStore).then(bookmarksStore => {
var ids = testCollectionData.map(item => {
return item.payload.bmkUri;
});
return bookmarksStore.get.apply(bookmarksStore, ids).then(list => {
for (var i = 0; i < ids.length; i++) {
verifyBookmarks(testCollectionData[i], list[i]);
assert.equal(
asyncStorage.mItems['foo' + BOOKMARKS_SYNCTOID_PREFIX +
testCollectionData[i].id],
testCollectionData[i].payload.bmkUri);
}
});
}).then(done, reason => {
done(reason || new Error('Rejected by undefined reason.'));
});
});
test('update - 2 sync requests', function(done) {
var bookmarksAdapter = DataAdapters.bookmarks;
Promise.resolve().then(() => {
testCollectionData = testDataGenerator(1, 100, 5)
.concat(testCollectionData);
return bookmarksAdapter.update(kintoCollection,
{ readonly: true, userid: 'foo' });
}).then(result => {
assert.equal(result, false);
var mTime = testCollectionData[0].last_modified;
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
mTime);
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
'latest-not-cleared');
return Promise.resolve();
}).then(() => {
testCollectionData = testDataGenerator(6, 500, 5)
.concat(testCollectionData);
return bookmarksAdapter.update(kintoCollection,
{ readonly: true, userid: 'foo' });
}).then(result => {
assert.equal(result, false);
var mTime = testCollectionData[0].last_modified;
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
mTime);
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
'latest-not-cleared');
return Promise.resolve();
}).then(getBookmarksStore).then(bookmarksStore => {
var ids = testCollectionData.map(item => {
return item.payload.bmkUri;
});
return bookmarksStore.get.apply(bookmarksStore, ids).then(list => {
for (var i = 0; i < ids.length; i++) {
verifyBookmarks(testCollectionData[i], list[i]);
assert.equal(
asyncStorage.mItems['foo' + BOOKMARKS_SYNCTOID_PREFIX +
testCollectionData[i].id],
testCollectionData[i].payload.bmkUri);
}
});
}).then(done, reason => {
done(reason || new Error('Rejected by undefined reason.'));
});
});
test('update - 2 sync requests with 2 deleted: true records', function(done) {
var bookmarksAdapter = DataAdapters.bookmarks, store;
var deletedQueue = ['UNIQUE_ID_1', 'UNIQUE_ID_4'];
Promise.resolve().then(() => {
testCollectionData = testDataGenerator(1, 100, 5)
.concat(testCollectionData);
return bookmarksAdapter.update(kintoCollection,
{ readonly: true, userid: 'foo' });
}).then(result => {
assert.equal(result, false);
var mTime = testCollectionData[0].last_modified;
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
mTime);
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
'latest-not-cleared');
return Promise.resolve();
}).then(() => {
testCollectionData = testDataGenerator(6, 500, 5)
.concat(testCollectionData);
var latestModified = testCollectionData[0].last_modified + 10000;
var deletedRecords = [];
deletedQueue.forEach((synctoId, i) => {
deletedRecords.push({
id: synctoId,
last_modified: latestModified + 10000 * i,
payload: {
deleted: true,
id: synctoId
}
});
});
testCollectionData = deletedRecords.concat(testCollectionData);
return bookmarksAdapter.update(kintoCollection,
{ readonly: true, userid: 'foo' });
}).then(result => {
assert.equal(result, false);
var mTime = testCollectionData[0].last_modified;
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
mTime);
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
'latest-not-cleared');
return Promise.resolve();
}).then(getBookmarksStore).then(bookmarksStore => {
store = bookmarksStore;
var ids = testCollectionData.map(item => {
return item.payload.bmkUri;
});
return store.get.apply(store, ids).then(list => {
for (var i = 0; i < list.length; i++) {
if (list[i]) {
verifyBookmarks(testCollectionData[i], list[i]);
assert.equal(
asyncStorage.mItems['foo' + BOOKMARKS_SYNCTOID_PREFIX +
testCollectionData[i].id],
testCollectionData[i].payload.bmkUri);
} else {
assert.notEqual(deletedQueue.indexOf(testCollectionData[i].id), -1);
}
}
});
}).then(done, reason => {
done(reason || new Error('Rejected by undefined reason.'));
});
});
test('update - Add three records with the same URL and delete one',
function(done) {
var bookmarksAdapter = DataAdapters.bookmarks, store;
Promise.resolve().then(() => {
for (var i = 1; i <= 3; i++) {
testCollectionData.unshift({
id: 'UNIQUE_ID_' + i,
last_modified: 100 + i * 10,
payload: {
id: 'UNIQUE_ID_' + i,
type: 'bookmark',
bmkUri: 'http://example.com/',
title: 'Example ' + i + ' Title'
}
});
}
return bookmarksAdapter.update(kintoCollection,
{ readonly: true, userid: 'foo' });
}).then(result => {
assert.equal(result, false);
var mTime = testCollectionData[0].last_modified;
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
mTime);
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
'latest-not-cleared');
return Promise.resolve();
}).then(() => {
testCollectionData = [
{
id: 'UNIQUE_ID_2',
last_modified: testCollectionData[0].last_modified + 10000,
payload: {
deleted: true,
id: 'UNIQUE_ID_2'
}
},
{
id: 'UNIQUE_ID_3',
last_modified: 130,
payload: {
id: 'UNIQUE_ID_3',
type: 'bookmark',
bmkUri: 'http://example.com/',
title: 'Example 3 Title'
}
},
{
id: 'UNIQUE_ID_1',
last_modified: 110,
payload: {
id: 'UNIQUE_ID_1',
type: 'bookmark',
bmkUri: 'http://example.com/',
title: 'Example 1 Title'
}
}
];
return bookmarksAdapter.update(kintoCollection,
{ readonly: true, userid: 'foo' });
}).then(result => {
assert.equal(result, false);
var mTime = testCollectionData[0].last_modified;
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
mTime);
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
'latest-not-cleared');
return Promise.resolve();
}).then(getBookmarksStore).then(bookmarksStore => {
store = bookmarksStore;
return store.get.apply(store, ['http://example.com/']).then(item => {
var expectedBookmark = {
id: 'http://example.com/',
url: 'http://example.com/',
name: 'Example 1 Title',
type: 'url',
iconable: false,
icon: '',
createdLocally: false,
fxsyncRecords: {
UNIQUE_ID_1: {
id: 'UNIQUE_ID_1',
type: 'bookmark',
bmkUri: 'http://example.com/',
title: 'Example 1 Title',
timestamp: 110
},
UNIQUE_ID_2: {
id: 'UNIQUE_ID_2',
deleted: true
},
UNIQUE_ID_3: {
id: 'UNIQUE_ID_3',
type: 'bookmark',
bmkUri: 'http://example.com/',
title: 'Example 3 Title',
timestamp: 130
}
}
};
for(var i=1; i <= 3; i++) {
assert.equal(
asyncStorage.mItems[
'foo' + BOOKMARKS_SYNCTOID_PREFIX + 'UNIQUE_ID_' + i],
item.url);
}
assert.deepEqual(item, expectedBookmark);
});
}).then(done, reason => {
done(reason || new Error('Rejected by undefined reason.'));
});
});
test('update - Add two records and add one, all with the same URL',
function(done) {
var bookmarksAdapter = DataAdapters.bookmarks, store;
Promise.resolve().then(() => {
for (var i = 1; i <= 2; i++) {
testCollectionData.unshift({
id: 'UNIQUE_ID_' + i,
last_modified: 100 + i * 10,
payload: {
id: 'UNIQUE_ID_' + i,
type: 'bookmark',
bmkUri: 'http://example.com/',
title: 'Example ' + i + ' Title'
}
});
}
return bookmarksAdapter.update(kintoCollection,
{ readonly: true, userid: 'foo' });
}).then(result => {
assert.equal(result, false);
var mTime = testCollectionData[0].last_modified;
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
mTime);
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
'latest-not-cleared');
return Promise.resolve();
}).then(() => {
testCollectionData.unshift({
id: 'UNIQUE_ID_3',
last_modified: 130,
payload: {
id: 'UNIQUE_ID_3',
type: 'bookmark',
bmkUri: 'http://example.com/',
title: 'Example 3 Title'
}
});
return bookmarksAdapter.update(kintoCollection,
{ readonly: true, userid: 'foo' });
}).then(result => {
assert.equal(result, false);
var mTime = testCollectionData[0].last_modified;
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
mTime);
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
'latest-not-cleared');
return Promise.resolve();
}).then(getBookmarksStore).then(bookmarksStore => {
store = bookmarksStore;
return store.get.apply(store, ['http://example.com/']).then(item => {
var expectedBookmark = {
id: 'http://example.com/',
url: 'http://example.com/',
name: 'Example 3 Title',
type: 'url',
iconable: false,
icon: '',
createdLocally: false,
fxsyncRecords: {
UNIQUE_ID_1: {
id: 'UNIQUE_ID_1',
type: 'bookmark',
bmkUri: 'http://example.com/',
title: 'Example 1 Title',
timestamp: 110
},
UNIQUE_ID_2: {
id: 'UNIQUE_ID_2',
type: 'bookmark',
bmkUri: 'http://example.com/',
title: 'Example 2 Title',
timestamp: 120
},
UNIQUE_ID_3: {
id: 'UNIQUE_ID_3',
type: 'bookmark',
bmkUri: 'http://example.com/',
title: 'Example 3 Title',
timestamp: 130
}
}
};
for(var i=1; i <= 3; i++) {
assert.equal(
asyncStorage.mItems[
'foo' + BOOKMARKS_SYNCTOID_PREFIX + 'UNIQUE_ID_' + i],
item.url);
}
assert.deepEqual(item, expectedBookmark);
});
}).then(done, reason => {
done(reason || new Error('Rejected by undefined reason.'));
});
});
test('update - query, folder, livemark, and separator record',
function(done) {
var bookmarksAdapter = DataAdapters.bookmarks, store;
var i = 1;
testCollectionData.unshift({
id: 'UNIQUE_ID_' + i,
last_modified: 100 + i * 10,
payload: {
id: 'UNIQUE_ID_' + i,
type: 'query',
bmkUri: 'place:type=3&sort=4',
title: 'Example ' + i + ' Title'
}
});
i++;
testCollectionData.unshift({
id: 'UNIQUE_ID_' + i,
last_modified: 100 + i * 10,
payload: {
id: 'UNIQUE_ID_' + i,
type: 'folder',
title: 'Example ' + i + ' Title'
}
});
i++;
testCollectionData.unshift({
id: 'UNIQUE_ID_' + i,
last_modified: 100 + i * 10,
payload: {
id: 'UNIQUE_ID_' + i,
type: 'livemark',
title: 'Example ' + i + ' Title'
}
});
i++;
testCollectionData.unshift({
id: 'UNIQUE_ID_' + i,
last_modified: 100 + i * 10,
payload: {
id: 'UNIQUE_ID_' + i,
type: 'separator'
}
});
bookmarksAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
.then(result => {
assert.equal(result, false);
var mTime = testCollectionData[0].last_modified;
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
mTime);
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
'latest-not-cleared');
return Promise.resolve();
}).then(getBookmarksStore).then(bookmarksStore => {
store = bookmarksStore;
var ids = testCollectionData.map(item => {
return item.payload.type + '|' + item.payload.id;
});
return store.get.apply(store, ids).then(list => {
for (var i = 0; i < list.length; i++) {
if (list[i]) {
verifyBookmarks(testCollectionData[i], list[i]);
for (var fxsyncId in testCollectionData[i].fxsyncRecords) {
assert.equal(asyncStorage.mItems[
'foo' + BOOKMARKS_SYNCTOID_PREFIX + fxsyncId],list[i].id);
}
} else {
assert.ok(false, 'Empty Record!');
}
}
});
}).then(done, reason => {
done(reason || new Error('Rejected by undefined reason.'));
});
});
test('update - empty bookmarks-uri record', function(done) {
var bookmarksAdapter = DataAdapters.bookmarks;
var i = 1;
testCollectionData.unshift({
id: 'UNIQUE_ID_' + i,
last_modified: 100 + i * 10,
payload: {
id: 'UNIQUE_ID_' + i,
type: 'bookmark',
bmkUri: '',
title: 'Example ' + i + ' Title'
}
});
bookmarksAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
.then(result => {
assert.equal(result, false);
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
110);
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
'latest-not-cleared');
return Promise.resolve();
}).then(done, reason => {
done(reason || new Error('Rejected by undefined reason.'));
});
});
test('update - empty query-uri record', function(done) {
var bookmarksAdapter = DataAdapters.bookmarks;
var i = 1;
testCollectionData.unshift({
id: 'UNIQUE_ID_' + i,
last_modified: 100 + i * 10,
payload: {
id: 'UNIQUE_ID_' + i,
type: 'query',
bmkUri: '',
title: 'Example ' + i + ' Title'
}
});
bookmarksAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
.then(result => {
assert.equal(result, false);
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
110);
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
'latest-not-cleared');
return Promise.resolve();
}).then(done, reason => {
done(reason || new Error('Rejected by undefined reason.'));
});
});
test('update - empty last_modified record', function(done) {
var bookmarksAdapter = DataAdapters.bookmarks;
var i = 1;
testCollectionData.unshift({
id: 'UNIQUE_ID_' + i,
last_modified: null,
payload: {
id: 'UNIQUE_ID_' + i,
type: 'bookmark',
bmkUri: '',
title: 'Example ' + i + ' Title'
}
});
bookmarksAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
.then(result => {
assert.equal(result, false);
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
null);
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
'latest-not-cleared');
return Promise.resolve();
}).then(done, reason => {
done(reason || new Error('Rejected by undefined reason.'));
});
});
test('update - unknown type record', function(done) {
var bookmarksAdapter = DataAdapters.bookmarks;
var i = 1;
testCollectionData.unshift({
id: 'UNIQUE_ID_' + i,
last_modified: 1000,
payload: {
id: 'UNIQUE_ID_' + i,
type: 'unknown',
bmkUri: null,
title: 'Example ' + i + ' Title'
}
});
bookmarksAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
.then(result => {
assert.equal(result, false);
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_COLLECTION_MTIME],
1000);
assert.equal(asyncStorage.mItems['foo' + BOOKMARKS_LAST_REVISIONID],
'latest-not-cleared');
return Promise.resolve();
}).then(done, reason => {
done(reason || new Error('Rejected by undefined reason.'));
});
});
test('BookmarksHelper - merge remote record into local record',
function(done) {
var bookmark1 = {
url: 'http://www.mozilla.org/en-US/',
name: '',
type: 'url'
};
var bookmark2 = {
url: 'http://www.mozilla.org/en-US/',
name: 'Mozilla',
type: 'url',
fxsyncRecords: {
'XXXXX_ID_XXXXX': {}
}
};
var result = BookmarksHelper.mergeRecordsToDataStore(bookmark1, bookmark2,
'XXXXX_ID_XXXXX');
var expectedBookmark = {
url: 'http://www.mozilla.org/en-US/',
name: 'Mozilla',
type: 'url',
createdLocally: true,
fxsyncRecords: {
'XXXXX_ID_XXXXX': {}
}
};
assert.equal(result.name, expectedBookmark.name);
assert.equal(result.url, expectedBookmark.url);
assert.deepEqual(result, expectedBookmark);
done();
});
test('BookmarksHelper - merge two records with incorrect URL',
function(done) {
var bookmark1 = {
url: 'dummy',
name: '',
type: 'url'
};
var bookmark2 = {
url: 'http://www.mozilla.org/en-US/',
name: 'Mozilla',
type: 'url'
};
assert.throws(() => {
BookmarksHelper.mergeRecordsToDataStore(bookmark1, bookmark2,
'XXXXX_ID_XXXXX');
});
done();
});
test('BookmarksHelper - merge two records with fxsyncRecords',
function(done) {
var bookmark1 = {
url: 'http://www.mozilla.org/en-US/',
name: '',
type: 'url',
createdLocally: false,
fxsyncRecords: {
'XXXXX_ID_XXXXX_A': {
id: 'XXXXX_ID_XXXXX_A'
}
}
};
var bookmark2 = {
url: 'http://www.mozilla.org/en-US/',
name: 'Mozilla',
type: 'url',
fxsyncRecords: {
'XXXXX_ID_XXXXX_B': {
id: 'XXXXX_ID_XXXXX_B'
}
}
};
var result = BookmarksHelper.mergeRecordsToDataStore(bookmark1, bookmark2,
'XXXXX_ID_XXXXX_B');
var expectedBookmark = {
url: 'http://www.mozilla.org/en-US/',
name: 'Mozilla',
type: 'url',
createdLocally: false,
fxsyncRecords: {
'XXXXX_ID_XXXXX_A': {
id: 'XXXXX_ID_XXXXX_A'
},
'XXXXX_ID_XXXXX_B': {
id: 'XXXXX_ID_XXXXX_B'
}
}
};
assert.equal(result.name, expectedBookmark.name);
assert.equal(result.url, expectedBookmark.url);
assert.deepEqual(result, expectedBookmark);
done();
});
});

View file

@ -0,0 +1,671 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
/* global
asyncStorage,
DataAdapters,
ERROR_SYNC_APP_RACE_CONDITION,
HISTORY_COLLECTION_MTIME,
HISTORY_LAST_REVISIONID,
HISTORY_SYNCTOID_PREFIX,
HistoryHelper,
MockasyncStorage,
MockDatastore,
MockLazyLoader,
MockNavigatorDatastore
*/
require('/shared/js/sync/errors.js');
require('/shared/test/unit/mocks/mock_lazy_loader.js');
require('/shared/test/unit/mocks/mock_navigator_datastore.js');
require('/apps/system/test/unit/mock_asyncStorage.js');
requireApp('sync/js/adapters/history.js');
window.DataAdapters = {};
suite('sync/adapters/history >', function() {
var realDatastore, realLazyLoader, realAsyncStorage, testCollectionData;
var dataStoreRemoveSpy;
var kintoCollection = {
list() {
return Promise.resolve({
data: testCollectionData
});
}
};
function getPlacesStore() {
return navigator.getDataStores().then(stores => {
return Promise.resolve(stores[0]);
});
}
function verifyPlaces(collectionItem, placesItem) {
var payload = collectionItem.payload;
assert.equal(payload.histUri, placesItem.url);
assert.equal(payload.title, placesItem.title);
for (var i = 0; i < payload.visits.length; i++) {
assert.equal(payload.visits[i].date, placesItem.visits[i] * 1000);
}
assert.equal(payload.id, placesItem.fxsyncId);
}
function testDataGenerator(initIndex, initDate, count) {
var list = [];
for (var i = initIndex; i < initIndex + count; i++) {
var visits = [];
var startData = initDate + i * 100;
for (var j = 0; j < 3; j++) {
// Visits from FxSync will be in anti-chronological order
visits.unshift({
date: (startData + j * 10) * 1000, type: 3
});
}
list.unshift({
id: 'UNIQUE_ID_' + i,
last_modified: initDate + i * 10,
payload: {
id: 'UNIQUE_ID_' + i,
histUri: 'http://example' + i + '.com/',
title: 'Example ' + i + ' Title',
visits: visits
}
});
}
return list;
}
suiteSetup(() => {
realDatastore = navigator.getDataStores;
realAsyncStorage = window.asyncStorage;
window.asyncStorage = MockasyncStorage;
realLazyLoader = window.LazyLoader;
window.LazyLoader = MockLazyLoader;
});
suiteTeardown(() => {
navigator.getDataStores = realDatastore;
window.LazyLoader = realLazyLoader;
window.asyncStorage = realAsyncStorage;
});
setup(() => {
navigator.getDataStores = MockNavigatorDatastore.getDataStores;
dataStoreRemoveSpy = sinon.spy(MockDatastore, 'remove');
testCollectionData = [];
MockDatastore._tasks[1].revisionId = 'latest-not-cleared';
});
teardown(() => {
dataStoreRemoveSpy.restore();
MockDatastore._inError = false;
MockDatastore._records = Object.create(null);
window.asyncStorage.mTeardown();
});
test('update - empty records', function(done) {
var historyAdapter = DataAdapters.history;
historyAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
.then((result) => {
assert.equal(result, false);
assert.equal(asyncStorage.mItems['foo' + HISTORY_LAST_REVISIONID],
'latest-not-cleared');
}).then(done, reason => {
assert.ok(false, reason);
});
});
['clear', 'remove'].forEach(task => {
suite(`after a DataStore ${task}`, function() {
suiteSetup(function() {
MockDatastore._taskCounter = 0;
MockDatastore._tasks = [
{
operation: 'clear',
id: 0,
data: {}
},
{
operation: 'add',
id: 0,
data: {}
},
{
operation: task,
id: 0,
data: {}
},
{
operation: 'done',
id: 0,
revisionId: `latest-after-${task}`,
data: null
}
];
});
suiteTeardown(function() {
MockDatastore._taskCounter = 0;
MockDatastore._tasks = [
{
operation: 'update',
id: 0,
data: {}
},
{
operation: 'done',
id: 0,
data: null,
revisionId: 'latest-not-cleared'
}
];
});
test('update - refills the DataStore', function(done) {
var historyAdapter = DataAdapters.history;
testCollectionData = testDataGenerator(1, 1440000000, 5);
asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME] =
testCollectionData[0].last_modified;
historyAdapter.update(kintoCollection,
{ readonly: true, userid: 'foo' })
.then(() => {
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME],
testCollectionData[0].last_modified);
getPlacesStore().then(placesStore => {
var ids = testCollectionData.map(item => {
return item.payload.histUri;
});
placesStore.get.apply(placesStore, ids).then(list => {
for (var i = 0; i < ids.length; i++) {
verifyPlaces(testCollectionData[i], list[i]);
assert.equal(
asyncStorage.mItems[
'foo' + HISTORY_SYNCTOID_PREFIX + list[i].fxsyncId],
list[i].url);
}
assert.equal(asyncStorage.mItems[
'foo' + HISTORY_LAST_REVISIONID], `latest-after-${task}`);
done();
});
});
});
});
});
});
test('update - does not refill the DataStore if nothing removed locally',
function(done) {
var historyAdapter = DataAdapters.history;
testCollectionData = testDataGenerator(1, 1440000000, 5);
asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME] =
testCollectionData[0].last_modified;
historyAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
.then(() => {
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME],
testCollectionData[0].last_modified);
getPlacesStore().then(placesStore => {
var ids = testCollectionData.map(item => {
return item.payload.histUri;
});
placesStore.get.apply(placesStore, ids).then(list => {
for (var i = 0; i < ids.length; i++) {
assert.equal(list[i], null);
}
assert.equal(asyncStorage.mItems[
'foo' + HISTORY_LAST_REVISIONID], 'latest-not-cleared');
done();
});
});
});
});
test('update - 1 sync request with 5 new records', function(done) {
var historyAdapter = DataAdapters.history;
var lazyLoaderSpy = this.sinon.spy(MockLazyLoader, 'load');
testCollectionData = testDataGenerator(1, 1440000000, 5);
historyAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
.then((result) => {
var mTime = testCollectionData[0].last_modified;
assert.equal(lazyLoaderSpy.calledWith(['shared/js/async_storage.js']),
true);
assert.equal(result, false);
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME],
mTime);
return Promise.resolve();
}).then(getPlacesStore).then(placesStore => {
var ids = testCollectionData.map(item => {
return item.payload.histUri;
});
return placesStore.get.apply(placesStore, ids).then(list => {
for (var i = 0; i < ids.length; i++) {
verifyPlaces(testCollectionData[i], list[i]);
assert.equal(
asyncStorage.mItems[
'foo' + HISTORY_SYNCTOID_PREFIX + list[i].fxsyncId],
list[i].url);
}
});
}).then(done, reason => {
assert.ok(false, reason);
});
});
suite('if a DataStore race condition occurs', function() {
setup(function() {
MockDatastore._raceCondition = true;
});
teardown(function() {
delete MockDatastore._raceCondition;
});
test('update - rejects its promise', function(done) {
var historyAdapter = DataAdapters.history;
var lazyLoaderSpy = this.sinon.spy(MockLazyLoader, 'load');
testCollectionData = testDataGenerator(1, 1440000000, 5);
historyAdapter.update(kintoCollection, { readonly: true, userid: 'foo' })
.catch(error => {
assert.equal(lazyLoaderSpy.calledWith(['shared/js/sync/errors.js']),
true);
assert.equal(error.message, ERROR_SYNC_APP_RACE_CONDITION);
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME],
null);
done();
});
});
});
test('update - 1 sync request with 5 pre-existing records', function(done) {
var historyAdapter = DataAdapters.history;
getPlacesStore().then(store => {
for (var i=1; i<=5; i++) {
store._records['http://example' + i + '.com/'] = {
url: 'http://example' + i + '.com/',
title: 'old',
visits: []
};
}
}).then(() => {
testCollectionData = testDataGenerator(1, 1440000000, 5);
return historyAdapter.update(kintoCollection,
{ readonly: true, userid: 'foo' });
}).then((result) => {
assert.equal(result, false);
var mTime = testCollectionData[0].last_modified;
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME],
mTime);
return Promise.resolve();
}).then(getPlacesStore).then(placesStore => {
var ids = testCollectionData.map(item => {
return item.payload.histUri;
});
return placesStore.get.apply(placesStore, ids).then(list => {
for (var i = 0; i < ids.length; i++) {
verifyPlaces(testCollectionData[i], list[i]);
assert.equal(
asyncStorage.mItems[
'foo' + HISTORY_SYNCTOID_PREFIX + list[i].fxsyncId],
list[i].url);
}
});
}).then(done, reason => {
assert.ok(false, reason);
});
});
test('update - 2 sync requests', function(done) {
var historyAdapter = DataAdapters.history;
Promise.resolve().then(() => {
testCollectionData = testDataGenerator(1, 100, 5)
.concat(testCollectionData);
return historyAdapter.update(kintoCollection,
{ readonly: true, userid: 'foo' });
}).then((result) => {
assert.equal(result, false);
var mTime = testCollectionData[0].last_modified;
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME],
mTime);
return Promise.resolve();
}).then(() => {
testCollectionData = testDataGenerator(6, 500, 5)
.concat(testCollectionData);
return historyAdapter.update(kintoCollection,
{ readonly: true, userid: 'foo' });
}).then((result) => {
assert.equal(result, false);
var mTime = testCollectionData[0].last_modified;
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME],
mTime);
return Promise.resolve();
}).then(getPlacesStore).then(placesStore => {
var ids = testCollectionData.map(item => {
return item.payload.histUri;
});
return placesStore.get.apply(placesStore, ids).then(list => {
for (var i = 0; i < ids.length; i++) {
verifyPlaces(testCollectionData[i], list[i]);
assert.equal(
asyncStorage.mItems[
'foo' + HISTORY_SYNCTOID_PREFIX + list[i].fxsyncId],
list[i].url);
}
});
}).then(done, reason => {
assert.ok(false, reason);
});
});
test('update - 2 sync requests with 2 deleted: true records', function(done) {
var historyAdapter = DataAdapters.history, store;
var deletedQueue = ['UNIQUE_ID_1', 'UNIQUE_ID_4'];
Promise.resolve().then(() => {
testCollectionData = testDataGenerator(1, 100, 5)
.concat(testCollectionData);
return historyAdapter.update(kintoCollection,
{ readonly: true, userid: 'foo' });
}).then((result) => {
assert.equal(result, false);
var mTime = testCollectionData[0].last_modified;
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME],
mTime);
return Promise.resolve();
}).then(() => {
testCollectionData = testDataGenerator(6, 500, 5)
.concat(testCollectionData);
var latestModified = testCollectionData[0].last_modified + 10000;
var deletedRecords = [];
deletedQueue.forEach((synctoId, i) => {
deletedRecords.push({
id: synctoId,
last_modified: latestModified + 10000 * i,
payload: {
deleted: true,
id: synctoId
}
});
});
testCollectionData = deletedRecords.concat(testCollectionData);
return historyAdapter.update(kintoCollection,
{ readonly: true, userid: 'foo' });
}).then((result) => {
assert.equal(result, false);
var mTime = testCollectionData[0].last_modified;
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME],
mTime);
assert.equal(asyncStorage.mItems['foo' + HISTORY_LAST_REVISIONID],
'latest-not-cleared');
return Promise.resolve();
}).then(getPlacesStore).then(placesStore => {
store = placesStore;
var ids = testCollectionData.map(item => {
return item.payload.histUri;
});
return store.get.apply(store, ids).then(list => {
for (var i = 0; i < list.length; i++) {
if (list[i]) {
verifyPlaces(testCollectionData[i], list[i]);
assert.equal(
asyncStorage.mItems[
'foo' + HISTORY_SYNCTOID_PREFIX + list[i].fxsyncId],
list[i].url);
} else {
assert.notEqual(deletedQueue.indexOf(testCollectionData[i].id), -1);
}
}
});
}).then(done, reason => {
assert.ok(false, reason);
});
});
test('update - non-array visits record', function(done) {
var historyAdapter = DataAdapters.history;
var i = 1;
testCollectionData.unshift({
id: 'UNIQUE_ID_' + i,
last_modified: 100 + i * 10,
payload: {
id: 'UNIQUE_ID_' + i,
histUri: 'http://example' + i + '.com/',
title: 'Example ' + i + ' Title',
visits: null
}
});
historyAdapter.update(kintoCollection,
{ readonly: true, userid: 'foo' }).then((result) => {
assert.equal(result, false);
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME], 110);
assert.equal(asyncStorage.mItems['foo' + HISTORY_LAST_REVISIONID],
'latest-not-cleared');
return Promise.resolve();
}).then(done, reason => {
assert.ok(false, reason);
});
});
test('update - empty visits array record (not created locally)',
function(done) {
var historyAdapter = DataAdapters.history;
var i = 1;
testCollectionData.unshift({
id: 'UNIQUE_ID_' + i,
last_modified: 100 + i * 10,
payload: {
id: 'UNIQUE_ID_' + i,
histUri: 'http://example' + i + '.com/',
title: 'Example ' + i + ' Title',
visits: []
}
});
MockDatastore._records = {
'http://example1.com/': {}
};
historyAdapter.update(kintoCollection,
{ readonly: true, userid: 'foo' }).then((result) => {
assert.equal(result, false);
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME], 110);
assert.equal(dataStoreRemoveSpy.callCount, 1);
assert.equal(dataStoreRemoveSpy.args[0][0], 'http://example1.com/');
return Promise.resolve();
}).then(done, reason => {
assert.ok(false, reason);
});
});
test('update - empty visits array record (created locally)', function(done) {
var historyAdapter = DataAdapters.history;
var i = 1;
testCollectionData.unshift({
id: 'UNIQUE_ID_' + i,
last_modified: 100 + i * 10,
payload: {
id: 'UNIQUE_ID_' + i,
histUri: 'http://example' + i + '.com/',
title: 'Example ' + i + ' Title',
visits: []
}
});
MockDatastore._records = {
'http://example1.com/': {
createdLocally: true
}
};
historyAdapter.update(kintoCollection,
{ readonly: true, userid: 'foo' }).then((result) => {
assert.equal(result, false);
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME], 110);
assert.equal(dataStoreRemoveSpy.callCount, 0);
return Promise.resolve();
}).then(done, reason => {
assert.ok(false, reason);
});
});
test('update - empty history-uri record', function(done) {
var historyAdapter = DataAdapters.history;
var i = 1;
testCollectionData.unshift({
id: 'UNIQUE_ID_' + i,
last_modified: 100 + i * 10,
payload: {
id: 'UNIQUE_ID_' + i,
histUri: '',
title: 'Example ' + i + ' Title',
visits: [10000, 20000]
}
});
historyAdapter.update(kintoCollection,
{ readonly: true, userid: 'foo' }).then((result) => {
assert.equal(result, false);
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME], 110);
assert.equal(asyncStorage.mItems['foo' + HISTORY_LAST_REVISIONID],
'latest-not-cleared');
return Promise.resolve();
}).then(done, reason => {
assert.ok(false, reason);
});
});
test('update - empty last_modified record', function(done) {
var historyAdapter = DataAdapters.history;
var i = 1;
testCollectionData.unshift({
id: 'UNIQUE_ID_' + i,
last_modified: null,
payload: {
id: 'UNIQUE_ID_' + i,
histUri: 'http://example' + i + '.com/',
title: 'Example ' + i + ' Title',
visits: [10000, 20000]
}
});
historyAdapter.update(kintoCollection,
{ readonly: true, userid: 'foo' }).then((result) => {
assert.equal(result, false);
assert.equal(asyncStorage.mItems['foo' + HISTORY_COLLECTION_MTIME], null);
assert.equal(asyncStorage.mItems['foo' + HISTORY_LAST_REVISIONID],
'latest-not-cleared');
return Promise.resolve();
}).then(done, reason => {
assert.ok(false, reason);
});
});
test('HistoryHelper - merge two remote records', function(done) {
var place1 = {
url: 'http://www.mozilla.org/en-US/',
title: '',
fxsyncId: '',
createdLocally: false,
visits: [ 1501000000000, 1502000000000 ]
};
var place2 = {
url: 'http://www.mozilla.org/en-US/',
title: 'Mozilla',
fxsyncId: 'XXXXX_ID_XXXXX',
visits: [ 1502000000000, 1503000000000 ]
};
var result = HistoryHelper.mergeRecordsToDataStore(place1, place2);
var expectedPlace = {
url: 'http://www.mozilla.org/en-US/',
title: 'Mozilla',
fxsyncId: 'XXXXX_ID_XXXXX',
createdLocally: false,
visits: [1503000000000, 1502000000000, 1501000000000]
};
assert.equal(result.title, expectedPlace.title);
assert.equal(result.url, expectedPlace.url);
assert.equal(result.visits.length, expectedPlace.visits.length);
for(var i = 0; i < result.visits.length; i++){
assert.equal(result.visits[i], expectedPlace.visits[i]);
}
done();
});
test('HistoryHelper - merge remote record into local record', function(done) {
var place1 = {
url: 'http://www.mozilla.org/en-US/',
title: '',
fxsyncId: '',
visits: [ 1501000000000, 1502000000000 ]
};
var place2 = {
url: 'http://www.mozilla.org/en-US/',
title: 'Mozilla',
fxsyncId: 'XXXXX_ID_XXXXX',
visits: [ 1502000000000, 1503000000000 ]
};
var result = HistoryHelper.mergeRecordsToDataStore(place1, place2);
var expectedPlace = {
url: 'http://www.mozilla.org/en-US/',
title: 'Mozilla',
fxsyncId: 'XXXXX_ID_XXXXX',
createdLocally: true,
visits: [1503000000000, 1502000000000, 1501000000000]
};
assert.equal(result.title, expectedPlace.title);
assert.equal(result.url, expectedPlace.url);
assert.equal(result.visits.length, expectedPlace.visits.length);
for(var i = 0; i < result.visits.length; i++){
assert.equal(result.visits[i], expectedPlace.visits[i]);
}
done();
});
test('HistoryHelper - merge two records with incorrect URL', function(done) {
var place1 = {
url: 'dummy',
title: '',
fxsyncId: '',
visits: [ 1501000000000, 1502000000000 ]
};
var place2 = {
url: 'http://www.mozilla.org/en-US/',
title: 'Mozilla',
fxsyncId: 'XXXXX_ID_XXXXX',
visits: [ 1502000000000, 1503000000000 ]
};
assert.throws(() => {
HistoryHelper.mergeRecordsToDataStore(place1, place2);
});
done();
});
test('HistoryHelper - merge two records with incorrect fxsyncId',
function(done) {
var place1 = {
url: 'http://www.mozilla.org/en-US/',
title: '',
fxsyncId: 'dummy',
visits: [ 1501000000000, 1502000000000 ]
};
var place2 = {
url: 'http://www.mozilla.org/en-US/',
title: 'Mozilla',
fxsyncId: 'XXXXX_ID_XXXXX',
visits: [ 1502000000000, 1503000000000 ]
};
assert.throws(() => {
HistoryHelper.mergeRecordsToDataStore(place1, place2);
});
done();
});
});