Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
359 lines
12 KiB
JavaScript
Executable file
359 lines
12 KiB
JavaScript
Executable file
'use strict';
|
|
/* global Folder, navigator, MockL10n, document, MocksHelper,
|
|
XScrollable, MozActivity, SpatialNavigator, CardManager, MessageHandler,
|
|
Home, SearchBar, FilterManager, Edit, Utils, Application, MockMozActivity,
|
|
FTEWizard */
|
|
|
|
require('/bower_components/evt/index.js');
|
|
require('/shared/js/uuid.js');
|
|
require('/shared/js/smart-screen/cards/card.js');
|
|
require('/shared/js/smart-screen/cards/application.js');
|
|
require('/shared/js/smart-screen/cards/deck.js');
|
|
require('/shared/js/smart-screen/cards/folder.js');
|
|
require('/shared/js/smart-screen/cards/app_bookmark.js');
|
|
require('/shared/js/smart-screen/clock.js');
|
|
require('/shared/test/unit/mocks/mock_event_target.js');
|
|
require('mock_card_manager.js');
|
|
require('mock_search_bar.js');
|
|
require('mock_menu_group.js');
|
|
require('mock_message_handler.js');
|
|
require('mock_x_scrollable.js');
|
|
require('mock_card_filter.js');
|
|
require('mock_edit.js');
|
|
require('mock_animations.js');
|
|
require('mock_utils.js');
|
|
require('mock_filter_manager.js');
|
|
require('/shared/test/unit/mocks/smart-screen/mock_spatial_navigator.js');
|
|
require('/shared/test/unit/mocks/smart-screen/mock_key_navigation_adapter.js');
|
|
require('/shared/test/unit/mocks/smart-screen/mock_f_t_e_wizard.js');
|
|
require('/shared/test/unit/mocks/mock_l10n.js');
|
|
require('/shared/test/unit/mocks/mocks_helper.js');
|
|
require('/shared/test/unit/mocks/mock_moz_activity.js');
|
|
require('/tv_apps/smart-home/js/home.js');
|
|
|
|
var mocksHelperForHomeTest = new MocksHelper([
|
|
'CardManager',
|
|
'CardFilter',
|
|
'SearchBar',
|
|
'MessageHandler',
|
|
'XScrollable',
|
|
'SpatialNavigator',
|
|
'KeyNavigationAdapter',
|
|
'Animations',
|
|
'Edit',
|
|
'MozActivity',
|
|
'Utils',
|
|
'FilterManager',
|
|
'FTEWizard'
|
|
]).init();
|
|
|
|
suite('home', function() {
|
|
var realL10n = navigator.mozL10n;
|
|
var realMozActivity = window.MozActivity;
|
|
var searchButton, settingsButton, editButton, timeElem;
|
|
var filterTabGroup, filterAllButton;
|
|
var subject;
|
|
var fakeTimer;
|
|
|
|
mocksHelperForHomeTest.attachTestHelpers();
|
|
|
|
suiteSetup(function() {
|
|
realL10n = navigator.mozL10n;
|
|
navigator.mozL10n = MockL10n;
|
|
|
|
searchButton = document.createElement('button');
|
|
searchButton.id = 'search-button';
|
|
document.body.appendChild(searchButton);
|
|
|
|
settingsButton = document.createElement('button');
|
|
settingsButton.id = 'settings-button';
|
|
document.body.appendChild(settingsButton);
|
|
|
|
editButton = document.createElement('button');
|
|
editButton.id = 'edit-button';
|
|
document.body.appendChild(editButton);
|
|
|
|
timeElem = document.createElement('div');
|
|
timeElem.id = 'time';
|
|
document.body.appendChild(timeElem);
|
|
|
|
filterTabGroup = document.createElement('menu-group');
|
|
filterTabGroup.once = function() {};
|
|
filterTabGroup.open = function() {};
|
|
filterTabGroup.close = function() {};
|
|
filterTabGroup.id = 'filter-tab-group';
|
|
filterAllButton = document.createElement('smart-button');
|
|
filterAllButton.id = 'filter-all-button';
|
|
filterTabGroup.appendChild(filterAllButton);
|
|
document.body.appendChild(filterTabGroup);
|
|
});
|
|
|
|
suiteTeardown(function() {
|
|
navigator.mozL10n = realL10n;
|
|
document.body.removeChild(searchButton);
|
|
document.body.removeChild(settingsButton);
|
|
document.body.removeChild(editButton);
|
|
document.body.removeChild(timeElem);
|
|
document.body.removeChild(filterTabGroup);
|
|
|
|
});
|
|
|
|
setup(function() {
|
|
subject = new Home();
|
|
subject.cardScrollable = new XScrollable();
|
|
subject.folderScrollable = new XScrollable();
|
|
subject.messageHandler = new MessageHandler();
|
|
subject.spatialNavigator = new SpatialNavigator();
|
|
subject.cardManager = new CardManager();
|
|
subject.searchBar = new SearchBar();
|
|
subject.filterManager = new FilterManager();
|
|
subject._fteWizard = new FTEWizard();
|
|
subject.edit = new Edit();
|
|
subject.cardListElem = document.createElement('div');
|
|
subject.spatialNavigator.m_focusedElement = document.createElement('div');
|
|
subject.isNavigable = true;
|
|
subject.settingsButton = settingsButton;
|
|
subject.editButton = editButton;
|
|
subject.searchButton = searchButton;
|
|
|
|
fakeTimer = this.sinon.useFakeTimers();
|
|
window.MozActivity = MockMozActivity;
|
|
});
|
|
|
|
teardown(function() {
|
|
window.MozActivity = realMozActivity;
|
|
});
|
|
|
|
suite('visibilityChange > ', function() {
|
|
suite('visible > ', function() {
|
|
setup(function() {
|
|
Object.defineProperty(document, 'visibilityState', {
|
|
value: 'visible',
|
|
writeable: true,
|
|
configurable: true
|
|
});
|
|
});
|
|
|
|
test('should set focus back on current focused element',
|
|
function(done) {
|
|
subject.spatialNavigator.focus = done;
|
|
subject.onVisibilityChange();
|
|
assert.isTrue(Utils.holdFocusForAnimation.calledOnce);
|
|
});
|
|
|
|
test('should start activity', function(done) {
|
|
subject.messageHandler.resumeActivity = done;
|
|
subject.onVisibilityChange();
|
|
});
|
|
});
|
|
|
|
suite('invisible > ', function() {
|
|
setup(function() {
|
|
Object.defineProperty(document, 'visibilityState', {
|
|
value: 'hidden',
|
|
writeable: true,
|
|
configurable: true
|
|
});
|
|
});
|
|
|
|
test('should stop activity when invisible', function() {
|
|
var spy = this.sinon.spy(subject.messageHandler, 'stopActivity');
|
|
subject.onVisibilityChange();
|
|
assert.isTrue(spy.calledOnce);
|
|
});
|
|
|
|
test('should reset filter', function() {
|
|
var spy = this.sinon.spy(subject.filterManager, 'resetFilter');
|
|
subject.onVisibilityChange();
|
|
assert.isTrue(spy.calledOnce);
|
|
});
|
|
});
|
|
});
|
|
|
|
suite('initClock >', function() {
|
|
test('should set time after time elapsed', function() {
|
|
subject.initClock();
|
|
var stub = this.sinon.stub(subject, 'updateClock');
|
|
fakeTimer.tick(1000);
|
|
assert.isTrue(stub.calledOnce);
|
|
});
|
|
});
|
|
|
|
suite('onCardInserted >', function() {
|
|
test('should insert a card into scrollable', function() {
|
|
var card1 = new Folder({});
|
|
var card2 = new Folder({});
|
|
var stub = this.sinon.stub();
|
|
var testCase1 = stub.withArgs(sinon.match.truthy, 0);
|
|
var testCase2 = stub.withArgs(sinon.match.truthy, 1);
|
|
subject.cardScrollable.insertNodeBefore = stub;
|
|
|
|
subject.onCardInserted(subject.cardScrollable, card1, 0);
|
|
assert.isTrue(testCase1.calledOnce);
|
|
assert.isFalse(testCase2.calledOnce);
|
|
subject.onCardInserted(subject.cardScrollable, card2, 1);
|
|
assert.isTrue(testCase2.calledOnce);
|
|
});
|
|
});
|
|
|
|
suite('onCardRemoved >', function() {
|
|
test('should remove specified cards from scrollable', function() {
|
|
var stub = this.sinon.stub();
|
|
subject.cardScrollable.removeNodes = stub;
|
|
subject.onCardRemoved(subject.cardScrollable, [0, 1]);
|
|
assert.isTrue(stub.withArgs([0, 1]).calledOnce);
|
|
});
|
|
});
|
|
|
|
suite('onMove >', function() {
|
|
test('should ask spatial navigator for next focus on non-scrollable target',
|
|
function() {
|
|
subject.spatialNavigator.m_focusedElement = document.createElement('div');
|
|
var stub = this.sinon.stub();
|
|
subject.spatialNavigator.move = stub;
|
|
subject.onMove('left');
|
|
assert.isTrue(stub.calledWith('left'));
|
|
});
|
|
|
|
test('should ask scrollable to move its focus on scrollable target',
|
|
function() {
|
|
var scrollable = new XScrollable();
|
|
scrollable.move = this.sinon.stub();
|
|
scrollable.move.returns(true);
|
|
subject.spatialNavigator.m_focusedElement = scrollable;
|
|
subject.onMove('right');
|
|
assert.isTrue(scrollable.move.calledWith('right'));
|
|
});
|
|
|
|
test('should ask scrollable to move its focus on scrollable target, but ' +
|
|
'fall-back to spatial navigator when scrollable didn\'t handle it',
|
|
function() {
|
|
var scrollable = new XScrollable();
|
|
scrollable.move = this.sinon.stub();
|
|
scrollable.move.returns(false);
|
|
subject.spatialNavigator.m_focusedElement = scrollable;
|
|
var spatialNavigatorMoveStub = this.sinon.stub();
|
|
subject.spatialNavigator.move = spatialNavigatorMoveStub;
|
|
subject.onMove('up');
|
|
assert.isTrue(scrollable.move.calledWith('up'));
|
|
assert.isTrue(spatialNavigatorMoveStub.calledWith('up'));
|
|
});
|
|
|
|
// TODO: add case
|
|
// 'should bypass logic of onMove if edit.onMove returns true'
|
|
});
|
|
|
|
suite('onEnter >', function() {
|
|
test('should open settings on settings button', function() {
|
|
subject.handleFocus(settingsButton);
|
|
|
|
assert.equal(MozActivity.calls.length, 0);
|
|
subject.onEnter();
|
|
assert.equal(MozActivity.calls[0].name, 'configure');
|
|
});
|
|
|
|
test('should toggle edit mode on edit button', function() {
|
|
subject.handleFocus(editButton);
|
|
|
|
subject.edit.toggleEditMode = this.sinon.stub();
|
|
subject.onEnter();
|
|
assert.isTrue(subject.edit.toggleEditMode.calledOnce);
|
|
});
|
|
|
|
test('should launch application on card ', function() {
|
|
var testCard = document.createElement('div');
|
|
testCard.dataset.cardId = '123';
|
|
|
|
var testApp = new Application({});
|
|
testApp.launch = this.sinon.stub();
|
|
subject.cardManager.m_card['123'] = testApp;
|
|
|
|
subject.handleFocus(testCard);
|
|
subject.onEnter();
|
|
assert.isTrue(testApp.launch.calledOnce);
|
|
});
|
|
|
|
// TODO: add case
|
|
// 'should bypass logic of onEnter if edit.onEnter returns true'
|
|
});
|
|
|
|
suite('onSearchBarShown >', function() {
|
|
setup(function() {
|
|
this.sinon.stub(document, 'addEventListener')
|
|
.withArgs('visibilitychange').callsArg(1);
|
|
subject.searchBar.hide = this.sinon.stub();
|
|
});
|
|
|
|
test('should fire search activity', function() {
|
|
assert.equal(MozActivity.calls.length, 0);
|
|
subject.onSearchBarShown();
|
|
assert.equal(MozActivity.calls[0].name, 'search');
|
|
});
|
|
|
|
test('should hide search bar after visibility has changed', function(done) {
|
|
subject.searchBar.hide = function() {
|
|
assert.isTrue(true);
|
|
done();
|
|
};
|
|
subject.onSearchBarShown();
|
|
});
|
|
});
|
|
|
|
suite('onSearchBarHidden >', function() {
|
|
test('should show search button again', function() {
|
|
searchButton.classList.add('hidden');
|
|
subject.onSearchBarHidden();
|
|
assert.isFalse(searchButton.classList.contains('hidden'));
|
|
});
|
|
});
|
|
|
|
suite('handleFocus >', function() {
|
|
test('should switch focus to scrollable target', function() {
|
|
var spy = this.sinon.spy(subject.cardScrollable, 'focus');
|
|
subject.handleFocus(subject.cardScrollable);
|
|
assert.isTrue(spy.calledOnce);
|
|
});
|
|
|
|
test('should switch focus to next focus for normal target', function() {
|
|
var spy = this.sinon.spy(editButton, 'focus');
|
|
subject.handleFocus(subject.editButton);
|
|
assert.isTrue(spy.calledOnce);
|
|
});
|
|
|
|
test('should open menu for menu group target', function() {
|
|
var stub = this.sinon.stub(subject, 'handleFocusMenuGroup');
|
|
subject.handleFocus(filterTabGroup);
|
|
assert.isTrue(stub.calledOnce);
|
|
});
|
|
|
|
test('should call checkFocusedGroup for non-menu elements', function() {
|
|
var stub = this.sinon.stub(subject, 'checkFocusedGroup');
|
|
subject.handleFocus(settingsButton);
|
|
assert.isTrue(stub.withArgs(settingsButton).calledOnce);
|
|
});
|
|
});
|
|
|
|
suite('checkFocusedGroup >', function() {
|
|
test('should close group menu when blur', function() {
|
|
subject.handleFocusMenuGroup(filterTabGroup);
|
|
var stub = this.sinon.stub(filterTabGroup, 'close');
|
|
subject.checkFocusedGroup();
|
|
assert.isTrue(stub.calledOnce);
|
|
});
|
|
});
|
|
|
|
// TODO: Test items:
|
|
// handleFocusMenuGroup >
|
|
// should switch navigable target to child elements of menu on open
|
|
// should switch navigable target back to menu iteslf on close
|
|
// handleScrollableItemFocus >
|
|
// should focus specified item of scrollable
|
|
// handleScrollableItemUnfocus >
|
|
// should blur specified item of scrollable
|
|
// openSettings >
|
|
// should launch configure activity
|
|
// updateClock >
|
|
// should update clock display
|
|
// restartClock >
|
|
// should stop and start clock display again
|
|
});
|