Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
540 lines
16 KiB
JavaScript
Executable file
540 lines
16 KiB
JavaScript
Executable file
/* global MocksHelper, MockNavigatorDatastore, MockDatastore, BaseModule */
|
|
/* global asyncStorage, MockService */
|
|
|
|
'use strict';
|
|
|
|
requireApp('system/shared/test/unit/mocks/mock_settings_listener.js');
|
|
require('/shared/test/unit/mocks/mock_async_storage.js');
|
|
require('/shared/test/unit/mocks/mock_service.js');
|
|
require('/shared/test/unit/mocks/mock_navigator_datastore.js');
|
|
require('/shared/test/unit/mocks/mock_lazy_loader.js');
|
|
|
|
requireApp('system/js/service.js');
|
|
requireApp('system/js/base_module.js');
|
|
requireApp('system/js/places.js');
|
|
|
|
var mocksHelperForPlaces = new MocksHelper([
|
|
'asyncStorage',
|
|
'SettingsListener',
|
|
'Datastore',
|
|
'LazyLoader'
|
|
]).init();
|
|
|
|
suite('system/Places', function() {
|
|
|
|
var realDatastores;
|
|
var subject;
|
|
|
|
mocksHelperForPlaces.attachTestHelpers();
|
|
|
|
suiteSetup(function(done) {
|
|
window.BrowserSettings = {
|
|
start: function() {}
|
|
};
|
|
asyncStorage.getItem = function(key, callback) {
|
|
callback(null);
|
|
};
|
|
|
|
realDatastores = navigator.getDataStores;
|
|
navigator.getDataStores = MockNavigatorDatastore.getDataStores;
|
|
|
|
subject = BaseModule.instantiate('Places');
|
|
subject.service = MockService;
|
|
subject.start().then(done);
|
|
});
|
|
|
|
suiteTeardown(function() {
|
|
delete window.BrowserSettings;
|
|
navigator.getDataStores = realDatastores;
|
|
});
|
|
|
|
setup(function() {
|
|
this.sinon.useFakeTimers();
|
|
});
|
|
|
|
var url1 = 'http://example.org';
|
|
|
|
var oneIcon = {
|
|
'windows.ico': {
|
|
sizes: ['32x32 48x48']
|
|
},
|
|
};
|
|
|
|
suite('Private Browsing', function() {
|
|
|
|
function sendPrivateBrowserEvent(event, url) {
|
|
window.dispatchEvent(new CustomEvent(event, {
|
|
detail: {
|
|
isBrowser: function() { return true; },
|
|
isPrivateBrowser: function() { return true; },
|
|
config: {
|
|
url: url
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
|
|
test('Does not process events for private browsers', function() {
|
|
var locationStub = this.sinon.stub(subject, 'onLocationChange');
|
|
var debounceStub = this.sinon.stub(subject, 'debouncePlaceChanges');
|
|
|
|
sendPrivateBrowserEvent('applocationchange', url1);
|
|
sendPrivateBrowserEvent('apploaded', url1);
|
|
assert.isFalse(locationStub.called);
|
|
assert.isFalse(debounceStub.called);
|
|
});
|
|
});
|
|
|
|
suite('Test places event handling', function() {
|
|
|
|
teardown(function() {
|
|
MockDatastore.clear();
|
|
});
|
|
|
|
function sendEvent(event, url) {
|
|
window.dispatchEvent(new CustomEvent(event, {
|
|
detail: {
|
|
isBrowser: function() { return true; },
|
|
isPrivateBrowser: function() { return false; },
|
|
config: {
|
|
url: url
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
|
|
test('Test visit', function(done) {
|
|
var screenshotStub = sinon.stub(subject, 'screenshotRequested');
|
|
MockDatastore.addEventListener('change', function() {
|
|
assert.ok(url1 in MockDatastore._records);
|
|
assert.equal(MockDatastore._records[url1].frecency, 1);
|
|
MockDatastore.removeEventListener();
|
|
screenshotStub.restore();
|
|
done();
|
|
});
|
|
sendEvent('applocationchange', url1);
|
|
sendEvent('apploaded', url1);
|
|
});
|
|
|
|
test('Test title event', function(done) {
|
|
var title = 'New Title!';
|
|
|
|
MockDatastore.addEventListener('change', function() {
|
|
assert.ok(url1 in MockDatastore._records);
|
|
assert.equal(MockDatastore._records[url1].title, title);
|
|
MockDatastore.removeEventListener();
|
|
done();
|
|
});
|
|
|
|
sendEvent('applocationchange', url1);
|
|
window.dispatchEvent(new CustomEvent('apptitlechange', {
|
|
detail: {
|
|
isBrowser: function() { return true; },
|
|
isPrivateBrowser: function() { return false; },
|
|
title: title,
|
|
config: {
|
|
url: url1
|
|
}
|
|
}
|
|
}));
|
|
sendEvent('apploaded', url1);
|
|
});
|
|
|
|
test('titlechange event while writeInProgress', function(done) {
|
|
var title = 'New Title!';
|
|
var originalEditPlace = subject.editPlace;
|
|
var firstCall = true;
|
|
this.sinon.stub(subject, 'editPlace', function(url, func) {
|
|
if (firstCall) {
|
|
// Is writeInProgress during the first call
|
|
firstCall = false;
|
|
return originalEditPlace.bind(subject)(url, func);
|
|
}
|
|
// On the second call, we allow to write
|
|
subject.writeInProgress = false;
|
|
return originalEditPlace.bind(subject)(url, func);
|
|
});
|
|
MockDatastore.addEventListener('change', function() {
|
|
assert.ok(url1 in MockDatastore._records);
|
|
assert.equal(MockDatastore._records[url1].title, title);
|
|
MockDatastore.removeEventListener();
|
|
done();
|
|
});
|
|
subject.writeInProgress = true;
|
|
window.dispatchEvent(new CustomEvent('apptitlechange', {
|
|
detail: {
|
|
isBrowser: function() { return true; },
|
|
isPrivateBrowser: function() { return false; },
|
|
title: title,
|
|
config: {
|
|
url: url1
|
|
}
|
|
}
|
|
}));
|
|
this.sinon.clock.tick(2000);
|
|
});
|
|
|
|
test('Test icon event', function(done) {
|
|
|
|
MockDatastore.addEventListener('change', function() {
|
|
assert.ok(url1 in MockDatastore._records);
|
|
var icons = MockDatastore._records[url1].icons;
|
|
assert.ok('windows.ico' in icons);
|
|
assert.deepEqual(icons['windows.ico'].sizes, ['32x32 48x48']);
|
|
MockDatastore.removeEventListener();
|
|
done();
|
|
});
|
|
|
|
sendEvent('applocationchange', url1);
|
|
window.dispatchEvent(new CustomEvent('appiconchange', {
|
|
detail: {
|
|
isBrowser: function() { return true; },
|
|
isPrivateBrowser: function() { return false; },
|
|
favicons: oneIcon,
|
|
config: {
|
|
url: url1
|
|
}
|
|
}
|
|
}));
|
|
sendEvent('apploaded', url1);
|
|
});
|
|
|
|
test('Test meta event', function(done) {
|
|
var meta = {
|
|
name: 'content'
|
|
};
|
|
MockDatastore.addEventListener('change', function() {
|
|
assert.ok(url1 in MockDatastore._records);
|
|
var newMeta = MockDatastore._records[url1].meta;
|
|
assert.deepEqual(newMeta, meta);
|
|
MockDatastore.removeEventListener();
|
|
done();
|
|
});
|
|
|
|
sendEvent('applocationchange', url1);
|
|
window.dispatchEvent(new CustomEvent('appmetachange', {
|
|
detail: {
|
|
isBrowser: function() { return true; },
|
|
isPrivateBrowser: function() { return false; },
|
|
meta: meta,
|
|
config: {
|
|
url: url1
|
|
}
|
|
}
|
|
}));
|
|
sendEvent('apploaded', url1);
|
|
});
|
|
|
|
test('Test screenshots', function(done) {
|
|
|
|
subject.topSites = [];
|
|
var screenshotStub = sinon.stub(subject, 'screenshotRequested');
|
|
var changes = 0;
|
|
|
|
MockDatastore.addEventListener('change', function() {
|
|
changes++;
|
|
|
|
// First url should request a screenshot
|
|
if (changes === 1) {
|
|
assert.ok(screenshotStub.calledOnce);
|
|
sendEvent('applocationchange', url1 + '/1');
|
|
sendEvent('apploaded', url1 + '/1');
|
|
return;
|
|
}
|
|
|
|
// We send 2 requests for /0 through /5 two times each
|
|
if (changes > 1 && changes < 12) {
|
|
sendEvent('applocationchange', url1 + '/' + (changes % 6));
|
|
sendEvent('apploaded', url1 + '/' + (changes % 6));
|
|
return;
|
|
}
|
|
|
|
// There are 6 urls so all are top sites
|
|
if (changes === 12) {
|
|
assert.equal(screenshotStub.callCount, 12);
|
|
sendEvent('applocationchange', url1 + '/new');
|
|
sendEvent('apploaded', url1 + '/new');
|
|
return;
|
|
}
|
|
|
|
// The last url is only visited once (rest have 2) so it should
|
|
// not request a screenshot
|
|
if (changes === 13) {
|
|
assert.equal(screenshotStub.callCount, 12);
|
|
screenshotStub.restore();
|
|
MockDatastore.removeEventListener();
|
|
done();
|
|
}
|
|
});
|
|
|
|
sendEvent('applocationchange', url1 + '/0');
|
|
sendEvent('apploaded', url1 + '/0');
|
|
});
|
|
|
|
test('Test screenshots for loading sites', function() {
|
|
var takeScreenshotStub = sinon.stub(subject, 'takeScreenshot');
|
|
subject.screenshotRequested('http://example.org');
|
|
assert.ok(takeScreenshotStub.notCalled);
|
|
this.sinon.clock.tick(6000);
|
|
assert.ok(takeScreenshotStub.calledOnce);
|
|
takeScreenshotStub.restore();
|
|
});
|
|
|
|
test('Receive icon update after apploaded saves place', function(done) {
|
|
sendEvent('applocationchange', url1);
|
|
sendEvent('apploaded', url1);
|
|
MockDatastore.addEventListener('change', function() {
|
|
// Exit after we get a save event for the icon update.
|
|
done();
|
|
});
|
|
sendEvent('appiconchange', url1);
|
|
this.sinon.clock.tick(10000);
|
|
});
|
|
|
|
test('Receive title update after apploaded saves place', function(done) {
|
|
sendEvent('applocationchange', url1);
|
|
sendEvent('apploaded', url1);
|
|
MockDatastore.addEventListener('change', function() {
|
|
// Exit after we get a save event for the icon update.
|
|
done();
|
|
});
|
|
sendEvent('apptitlechange', url1);
|
|
this.sinon.clock.tick(10000);
|
|
});
|
|
|
|
test('Correctly set visits', function(done) {
|
|
var url = 'http://example.org';
|
|
MockDatastore.addEventListener('change', function() {
|
|
assert.equal(MockDatastore._records[url].visits.length, 3);
|
|
done();
|
|
});
|
|
subject.setVisits(url, [1, 2, 3]);
|
|
});
|
|
|
|
test('Correctly set pinned status', function(done) {
|
|
var url = 'http://example.org';
|
|
MockDatastore.addEventListener('change', function() {
|
|
assert.equal(MockDatastore._records[url].pinned, true);
|
|
done();
|
|
});
|
|
subject.setPinned(url, true);
|
|
});
|
|
|
|
test('Ensure place without icon doesnt bail', function(done) {
|
|
var url = 'http://example.org';
|
|
|
|
MockDatastore.put({
|
|
url: url,
|
|
tile: 'a tile',
|
|
frecency: 1
|
|
}, url);
|
|
|
|
MockDatastore.addEventListener('change', function() {
|
|
assert.equal(MockDatastore._records[url].frecency, 2);
|
|
done();
|
|
});
|
|
|
|
sendEvent('applocationchange', url);
|
|
window.dispatchEvent(new CustomEvent('appiconchange', {
|
|
detail: {
|
|
isBrowser: function() { return true; },
|
|
isPrivateBrowser: function() { return false; },
|
|
favicons: oneIcon,
|
|
config: {url: url }
|
|
}
|
|
}));
|
|
this.sinon.clock.tick(10000);
|
|
});
|
|
|
|
suite('isPinned', function() {
|
|
setup(function() {
|
|
MockDatastore.put({
|
|
url: 'http://example.com/index.html',
|
|
tile: 'a tile',
|
|
frecency: 1
|
|
}, 'http://example.com/index.html');
|
|
|
|
MockDatastore.put({
|
|
url: 'http://example.org',
|
|
tile: 'a tile',
|
|
frecency: 1,
|
|
pinned: true,
|
|
pinTime: 1444829881365
|
|
}, 'http://example.org');
|
|
});
|
|
|
|
teardown(function() {
|
|
});
|
|
|
|
test('should return false for unpinned pages', function(done) {
|
|
subject.isPinned('http://example.com/index.html')
|
|
.then((isPinned) => {
|
|
assert.isFalse(isPinned);
|
|
done();
|
|
});
|
|
});
|
|
|
|
test('should return true for pinned pages', function(done) {
|
|
subject.isPinned('http://example.org')
|
|
.then((isPinned) => {
|
|
assert.isTrue(isPinned);
|
|
done();
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
suite('Clear history', function() {
|
|
var syncSpy;
|
|
|
|
setup(function() {
|
|
syncSpy = this.sinon.spy(MockDatastore, 'sync');
|
|
});
|
|
|
|
teardown(function() {
|
|
syncSpy.restore();
|
|
});
|
|
|
|
test('should escape prematurely when empty', function(done) {
|
|
subject.clearHistory()
|
|
.then(() => {
|
|
assert.isFalse(syncSpy.called);
|
|
done();
|
|
});
|
|
});
|
|
|
|
test('should not remove pinned pages', function(done) {
|
|
var url = 'http://example.org';
|
|
|
|
MockDatastore.put({
|
|
url: 'http://example.com/index.html',
|
|
tile: 'a tile',
|
|
frecency: 1
|
|
}, url);
|
|
|
|
MockDatastore.put({
|
|
url: url,
|
|
tile: 'a tile',
|
|
frecency: 1,
|
|
pinned: true,
|
|
pinTime: 1444829881365
|
|
}, url);
|
|
|
|
subject.clearHistory()
|
|
.then(() => {
|
|
assert.isObject(MockDatastore._records[url]);
|
|
assert.isTrue(syncSpy.called);
|
|
done();
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
suite('Clean dupes', function() {
|
|
var removeSpy, setItemStub;
|
|
var topSitesWithDupes = [
|
|
{ url: 'http://website1/', frecency: 10},
|
|
{ url: 'http://website1/', frecency: 8},
|
|
{ url: 'http://website1/', frecency: 6},
|
|
{ url: 'http://website2/', frecency: 5},
|
|
{ url: 'http://website2/', frecency: 4},
|
|
{ url: 'http://website3/', frecency: 3},
|
|
];
|
|
|
|
var topSitesWithoutDupes = [
|
|
{ url: 'http://website1/', frecency: 10},
|
|
{ url: 'http://website2/', frecency: 5},
|
|
{ url: 'http://website3/', frecency: 3},
|
|
{ url: 'http://website4/', frecency: 2},
|
|
{ url: 'http://website5/', frecency: 2},
|
|
{ url: 'http://website6/', frecency: 2},
|
|
];
|
|
|
|
setup(function() {
|
|
removeSpy = this.sinon.spy(subject, '_removeDupes');
|
|
setItemStub = this.sinon.stub(asyncStorage, 'setItem');
|
|
});
|
|
|
|
test('_start() calls _removeDupes()', function(done) {
|
|
subject._start().then(() => {
|
|
sinon.assert.calledOnce(removeSpy);
|
|
done();
|
|
});
|
|
});
|
|
|
|
suite('Duplicates removal', function() {
|
|
test('empty top sites', function() {
|
|
var result = subject._removeDupes([]);
|
|
assert.equal(result.length, 0);
|
|
});
|
|
|
|
test('removes duplicated top sites', function() {
|
|
var result = subject._removeDupes(topSitesWithDupes);
|
|
assert.equal(result.length, 3);
|
|
assert.deepEqual(result[0], topSitesWithoutDupes[0]);
|
|
assert.deepEqual(result[1], topSitesWithoutDupes[1]);
|
|
assert.deepEqual(result[2], topSitesWithoutDupes[2]);
|
|
});
|
|
|
|
test('nothing on non duplicated top sites', function() {
|
|
var result = subject._removeDupes(topSitesWithoutDupes);
|
|
assert.equal(result.length, 6);
|
|
assert.deepEqual(result[0], topSitesWithoutDupes[0]);
|
|
assert.deepEqual(result[1], topSitesWithoutDupes[1]);
|
|
assert.deepEqual(result[2], topSitesWithoutDupes[2]);
|
|
});
|
|
});
|
|
|
|
suite('checkTopSites should not add dupes', function() {
|
|
setup(function() {
|
|
subject.topSites = topSitesWithoutDupes.slice(0);
|
|
});
|
|
|
|
test('checking new place, higher frecency', function() {
|
|
var newPlace = { url: 'http://website7/', frecency: 7 };
|
|
subject.checkTopSites(newPlace);
|
|
assert.equal(subject.topSites.length, 6);
|
|
assert.deepEqual(topSitesWithoutDupes[0], subject.topSites[0]);
|
|
assert.deepEqual(newPlace, subject.topSites[1]);
|
|
assert.deepEqual(topSitesWithoutDupes[1], subject.topSites[2]);
|
|
assert.deepEqual(topSitesWithoutDupes[2], subject.topSites[3]);
|
|
assert.deepEqual(topSitesWithoutDupes[3], subject.topSites[4]);
|
|
assert.deepEqual(topSitesWithoutDupes[4], subject.topSites[5]);
|
|
});
|
|
|
|
test('checking new place, lower frecency', function() {
|
|
var newPlace = { url: 'http://website7/', frecency: 1 };
|
|
subject.checkTopSites(newPlace);
|
|
assert.equal(subject.topSites.length, 6);
|
|
for (var i = 0; i < 6; i++) {
|
|
assert.notDeepEqual(newPlace, subject.topSites[i]);
|
|
}
|
|
});
|
|
|
|
test('checking existing place, higher frecency', function() {
|
|
var existPlace = { url: 'http://website3/', frecency: 7 };
|
|
subject.checkTopSites(existPlace);
|
|
assert.equal(subject.topSites.length, 6);
|
|
assert.deepEqual(topSitesWithoutDupes[0], subject.topSites[0]);
|
|
assert.deepEqual(existPlace, subject.topSites[1]);
|
|
assert.deepEqual(topSitesWithoutDupes[1], subject.topSites[2]);
|
|
assert.notDeepEqual(topSitesWithoutDupes[2], subject.topSites[3]);
|
|
assert.deepEqual(topSitesWithoutDupes[3], subject.topSites[3]);
|
|
assert.deepEqual(topSitesWithoutDupes[4], subject.topSites[4]);
|
|
assert.deepEqual(topSitesWithoutDupes[5], subject.topSites[5]);
|
|
});
|
|
|
|
test('checking existing place, lower frecency', function() {
|
|
var existPlace = { url: 'http://website3/', frecency: 1 };
|
|
subject.checkTopSites(existPlace);
|
|
assert.equal(subject.topSites.length, 6);
|
|
for (var i = 0; i < 6; i++) {
|
|
assert.notDeepEqual(existPlace, subject.topSites[i]);
|
|
}
|
|
});
|
|
|
|
});
|
|
});
|
|
});
|
|
|
|
});
|