Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
414 lines
12 KiB
JavaScript
Executable file
414 lines
12 KiB
JavaScript
Executable file
/* jshint nonew: false */
|
|
/* global Pages, PagesStore */
|
|
'use strict';
|
|
|
|
require('/shared/test/unit/load_body_html_helper.js');
|
|
require('mocks/mock_datastore.js');
|
|
require('/js/pages.js');
|
|
|
|
suite('Pages', () => {
|
|
var pages;
|
|
|
|
setup(() => {
|
|
window.PagesStore = window.Datastore;
|
|
loadBodyHTML('_index.html');
|
|
pages = new Pages();
|
|
});
|
|
|
|
suite('Pages constructor', () => {
|
|
var stub;
|
|
|
|
teardown(() => {
|
|
stub.restore();
|
|
});
|
|
|
|
test('should initialise the pages store', done => {
|
|
stub = sinon.stub(PagesStore.prototype, 'init', () => {
|
|
done();
|
|
return Promise.reject();
|
|
});
|
|
new Pages();
|
|
});
|
|
|
|
test('should get the list of pinned pages', done => {
|
|
stub = sinon.stub(PagesStore.prototype, 'getAll', () => {
|
|
done();
|
|
return Promise.reject();
|
|
});
|
|
new Pages();
|
|
});
|
|
|
|
test('should mark the pages panel empty if no pages', done => {
|
|
stub = sinon.stub(PagesStore.prototype, 'getAll', () => {
|
|
return { then: callback => {
|
|
callback([]);
|
|
done(() => {
|
|
assert.isTrue(document.getElementById('pages-panel').classList.
|
|
contains('empty'));
|
|
});
|
|
}};
|
|
});
|
|
new Pages();
|
|
});
|
|
});
|
|
|
|
suite('Pages#addPinnedPage()', () => {
|
|
var pinCard;
|
|
var createElementStub;
|
|
var updatePinnedPageStub;
|
|
var appendChildStub;
|
|
|
|
setup(() => {
|
|
pinCard = document.createElement('div');
|
|
createElementStub = sinon.stub(document, 'createElement', () => pinCard);
|
|
updatePinnedPageStub = sinon.stub(pages, 'updatePinnedPage');
|
|
appendChildStub = sinon.stub(pages.pages, 'appendChild');
|
|
});
|
|
|
|
teardown(() => {
|
|
createElementStub.restore();
|
|
updatePinnedPageStub.restore();
|
|
appendChildStub.restore();
|
|
});
|
|
|
|
test('should remove .empty from the pages panel', () => {
|
|
var pagesPanel = document.getElementById('pages-panel');
|
|
assert.isTrue(pages.empty);
|
|
assert.isTrue(pagesPanel.classList.contains('empty'));
|
|
pages.addPinnedPage();
|
|
assert.isFalse(pages.empty);
|
|
assert.isFalse(pagesPanel.classList.contains('empty'));
|
|
});
|
|
|
|
test('should add a card to the pages list', () => {
|
|
pages.addPinnedPage();
|
|
assert.isTrue(createElementStub.calledWith('gaia-pin-card'));
|
|
assert.isTrue(updatePinnedPageStub.calledOnce);
|
|
assert.isTrue(appendChildStub.calledOnce);
|
|
});
|
|
|
|
test('should make card accessible', () => {
|
|
pages.addPinnedPage();
|
|
assert.equal(pinCard.tabIndex, 0);
|
|
assert.equal(pinCard.getAttribute('role'), 'link');
|
|
});
|
|
});
|
|
|
|
suite('Pages#updatePinnedPage()', () => {
|
|
var clock;
|
|
var createObjectURLStub;
|
|
|
|
var mockPinnedPage = {
|
|
title: 'Mock pinned page',
|
|
url: 'Mock URL',
|
|
pinTime: 4242,
|
|
screenshot: 'Mock screenshot',
|
|
meta: {
|
|
'theme-color': 'Mock color'
|
|
}
|
|
};
|
|
|
|
var mockCard = {
|
|
title: null,
|
|
dataset: { id: null },
|
|
style: { order: 0 },
|
|
background: null,
|
|
meta: null,
|
|
icon: null
|
|
};
|
|
|
|
var mockIconBlob = 'Mock icon blob';
|
|
|
|
setup(() => {
|
|
clock = sinon.useFakeTimers();
|
|
|
|
createObjectURLStub = sinon.stub(URL, 'createObjectURL', blob => blob);
|
|
});
|
|
|
|
teardown(() => {
|
|
clock.restore();
|
|
createObjectURLStub.restore();
|
|
});
|
|
|
|
test('should set title, url and order', () => {
|
|
pages.updatePinnedPage(mockCard, mockPinnedPage);
|
|
assert.equal(mockCard.title, mockPinnedPage.title);
|
|
assert.equal(mockCard.dataset.id, mockPinnedPage.url);
|
|
var pinTime = -Math.round(mockPinnedPage.pinTime / 1000);
|
|
assert.equal(mockCard.style.order, pinTime);
|
|
});
|
|
|
|
test('should set screenshot, themeColor and icon after timeout', done => {
|
|
window.IconsHelper = {
|
|
getIconBlob: (url, size, page) => {
|
|
return {
|
|
then: (callback) => {
|
|
callback({ blob: mockIconBlob });
|
|
assert.equal(mockCard.icon, 'url(' + mockIconBlob + ')');
|
|
done();
|
|
return { catch: () => {} };
|
|
}
|
|
};
|
|
}
|
|
};
|
|
|
|
pages.updatePinnedPage(mockCard, mockPinnedPage);
|
|
clock.tick();
|
|
var meta = mockCard.meta;
|
|
assert.equal(meta['theme-color'], mockPinnedPage.meta['theme-color']);
|
|
assert.equal(meta.screenshot, mockPinnedPage.screenshot);
|
|
});
|
|
});
|
|
|
|
suite('Pages#enterEditMode()', () => {
|
|
var mockCard;
|
|
setup(() => {
|
|
mockCard = document.createElement('div');
|
|
pages.enterEditMode(mockCard);
|
|
});
|
|
|
|
teardown(() => {
|
|
pages.exitEditMode();
|
|
});
|
|
|
|
test('card is marked as selected', () => {
|
|
assert.isTrue(mockCard.classList.contains('selected'));
|
|
});
|
|
|
|
test('document is marked as in edit-mode', () => {
|
|
assert.isTrue(document.body.classList.contains('edit-mode'));
|
|
});
|
|
|
|
test('delete button is activated', () => {
|
|
assert.isTrue(pages.remove.classList.contains('active'));
|
|
});
|
|
|
|
test('previous card is unselected', () => {
|
|
var mockCard2 = document.createElement('div');
|
|
pages.enterEditMode(mockCard2);
|
|
assert.isFalse(mockCard.classList.contains('selected'));
|
|
assert.isTrue(mockCard2.classList.contains('selected'));
|
|
});
|
|
});
|
|
|
|
suite('Pages#exitEditMode()', () => {
|
|
var mockCard;
|
|
setup(() => {
|
|
mockCard = document.createElement('div');
|
|
pages.enterEditMode(mockCard);
|
|
pages.exitEditMode();
|
|
});
|
|
|
|
test('card is not marked as selected', () => {
|
|
assert.isFalse(mockCard.classList.contains('selected'));
|
|
assert.equal(pages.selectedCard, null);
|
|
});
|
|
|
|
test('document is not marked as in edit-mode', () => {
|
|
assert.isFalse(document.body.classList.contains('edit-mode'));
|
|
});
|
|
|
|
test('delete button is not activated', () => {
|
|
assert.isFalse(pages.remove.classList.contains('active'));
|
|
});
|
|
});
|
|
|
|
suite('Pages#removeCard()', () => {
|
|
var mockCard;
|
|
setup(() => {
|
|
mockCard = document.createElement('div');
|
|
});
|
|
|
|
test('removes child from container', () => {
|
|
var removeStub = sinon.stub(pages.pages, 'removeChild');
|
|
pages.removeCard(mockCard);
|
|
assert.isTrue(removeStub.calledWith(mockCard));
|
|
});
|
|
|
|
test('deselects card if card is selected', () => {
|
|
pages.selectedCard = mockCard;
|
|
var removeStub = sinon.stub(pages.pages, 'removeChild');
|
|
pages.removeCard(mockCard);
|
|
assert.equal(pages.selectedCard, null);
|
|
removeStub.restore();
|
|
});
|
|
|
|
test('shows the empty pinned pages panel when removing last card', done => {
|
|
pages.empty = false;
|
|
Object.defineProperty(pages.pages, 'children', {
|
|
value: { length: 0 },
|
|
configurable: true
|
|
});
|
|
var removeChildStub = sinon.stub(pages.pages, 'removeChild',
|
|
(card, callback) => {
|
|
callback();
|
|
done(() => {
|
|
delete pages.pages.children;
|
|
removeChildStub.restore();
|
|
assert.isTrue(pages.empty);
|
|
assert.isTrue(pages.panel.classList.contains('empty'));
|
|
});
|
|
});
|
|
pages.removeCard(mockCard);
|
|
});
|
|
|
|
test('exits edit mode when removing last card', done => {
|
|
pages.empty = false;
|
|
pages.editMode = true;
|
|
Object.defineProperty(pages.pages, 'children', {
|
|
value: { length: 0 },
|
|
configurable: true
|
|
});
|
|
var removeChildStub = sinon.stub(pages.pages, 'removeChild',
|
|
(card, callback) => {
|
|
callback();
|
|
done(() => {
|
|
delete pages.pages.children;
|
|
removeChildStub.restore();
|
|
assert.isFalse(pages.editMode);
|
|
});
|
|
});
|
|
pages.removeCard(mockCard);
|
|
});
|
|
});
|
|
|
|
suite('Pages#unpinSelectedCard()', () => {
|
|
var removeCardStub, storeGetStub, storePutStub, mockEntry, callback;
|
|
var mockCard = {
|
|
dataset: {
|
|
id: 'abc'
|
|
}
|
|
};
|
|
|
|
setup(() => {
|
|
mockEntry = { data: { pinned: true } };
|
|
removeCardStub = sinon.stub(pages, 'removeCard');
|
|
storeGetStub =
|
|
sinon.stub(pages.pagesStore, 'get', () => {
|
|
return Promise.resolve(mockEntry);
|
|
});
|
|
storePutStub =
|
|
sinon.stub(pages.pagesStore.datastore, 'put', (data, id) => {
|
|
if (callback) {
|
|
callback(data, id);
|
|
}
|
|
return Promise.resolve();
|
|
});
|
|
pages.selectedCard = mockCard;
|
|
});
|
|
|
|
teardown(() => {
|
|
removeCardStub.restore();
|
|
storeGetStub.restore();
|
|
storePutStub.restore();
|
|
pages.selectedCard = null;
|
|
});
|
|
|
|
test('removes card from container', () => {
|
|
pages.unpinSelectedCard();
|
|
assert.isTrue(removeCardStub.calledWith(mockCard));
|
|
});
|
|
|
|
test('unpins card in datastore', done => {
|
|
callback = (data, id) => {
|
|
done(() => {
|
|
assert.equal(id, mockCard.dataset.id);
|
|
assert.isFalse(mockEntry.data.pinned);
|
|
});
|
|
};
|
|
pages.unpinSelectedCard();
|
|
});
|
|
});
|
|
|
|
suite('Pages#handleEvent()', () => {
|
|
var mockCard = {
|
|
nodeName: 'GAIA-PIN-CARD',
|
|
title: 'Mock title',
|
|
icon: 'Mock icon',
|
|
dataset: {
|
|
id: 'Mock URL'
|
|
}
|
|
};
|
|
|
|
var mockNotCard = {
|
|
nodeName: 'MOCK-NOT-CARD'
|
|
};
|
|
|
|
suite('click', () => {
|
|
test('clicking a card should launch a remote window', () => {
|
|
var windowOpenStub = sinon.stub(window, 'open',
|
|
(url, target, features) => {
|
|
assert.equal(url, mockCard.dataset.id);
|
|
assert.equal(target, '_blank');
|
|
|
|
var expectedFeatures = {
|
|
name: mockCard.title,
|
|
icon: mockCard.icon,
|
|
remote: true
|
|
};
|
|
expectedFeatures = Object.keys(expectedFeatures).
|
|
map(function eachFeature(key) {
|
|
return encodeURIComponent(key) + '=' +
|
|
encodeURIComponent(expectedFeatures[key]);
|
|
}).join(',');
|
|
|
|
assert.equal(features, expectedFeatures);
|
|
});
|
|
pages.handleEvent({ type: 'click', target: mockCard });
|
|
windowOpenStub.restore();
|
|
});
|
|
|
|
test('clicking outside a card should do nothing', () => {
|
|
var windowOpenStub = sinon.stub(window, 'open');
|
|
pages.handleEvent({ type: 'click', target: mockNotCard });
|
|
assert.isFalse(windowOpenStub.called);
|
|
windowOpenStub.restore();
|
|
});
|
|
|
|
test('pressing a card in edit mode selects it', () => {
|
|
var editModeStub = sinon.stub(pages, 'enterEditMode');
|
|
pages.editMode = true;
|
|
pages.handleEvent({ type: 'click', target: mockCard });
|
|
assert.isTrue(editModeStub.calledWith(mockCard));
|
|
editModeStub.restore();
|
|
});
|
|
|
|
test('pressing delete in edit mode unpins a card', () => {
|
|
var unpinStub = sinon.stub(pages, 'unpinSelectedCard');
|
|
pages.selectedCard = mockCard;
|
|
pages.remove.dispatchEvent(new CustomEvent('click'));
|
|
assert.isTrue(unpinStub.called);
|
|
});
|
|
});
|
|
|
|
suite('contextmenu', () => {
|
|
var editModeStub;
|
|
setup(() => {
|
|
editModeStub = sinon.stub(pages, 'enterEditMode');
|
|
});
|
|
|
|
teardown(() => {
|
|
editModeStub.restore();
|
|
});
|
|
|
|
test('long-pressing a card initiates edit mode', () => {
|
|
pages.handleEvent({ type: 'contextmenu', target: mockCard });
|
|
assert.isTrue(editModeStub.calledWith(mockCard));
|
|
});
|
|
|
|
test('long-pressing not on a card does nothing', () => {
|
|
pages.handleEvent({ type: 'contextmenu', target: mockNotCard });
|
|
assert.isFalse(editModeStub.called);
|
|
});
|
|
});
|
|
|
|
suite('resize', () => {
|
|
test('should call pages.synchronise()', () => {
|
|
var synchroniseCalled = false;
|
|
pages.pages.synchronise = () => { synchroniseCalled = true; };
|
|
pages.handleEvent(new CustomEvent('resize'));
|
|
assert.isTrue(synchroniseCalled);
|
|
});
|
|
});
|
|
});
|
|
});
|