VulpesOS/gaia/apps/system/test/unit/places_test.js
OverSu b38dea0597 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.
2026-09-30 23:13:03 +02:00

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