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,18 @@
{
"extends": "../../../../.jshintrc",
"predef": [
"assert",
"suite",
"test",
"setup",
"teardown",
"suiteSetup",
"suiteTeardown",
"require",
"requireApp",
"sinon",
"mocha",
"loadBodyHTML"
]
}

View file

@ -0,0 +1,747 @@
/* global BaseModule, MocksHelper, MockService, MockLazyLoader, MockPromise,
Deferred */
'use strict';
require('/shared/test/unit/mocks/mock_service.js');
require('/shared/test/unit/mocks/mock_promise.js');
require('/shared/test/unit/mocks/mock_lazy_loader.js');
requireApp('smart-system/test/unit/deferred.js');
var mocksForBaseModule = new MocksHelper([
'LazyLoader', 'Service'
]).init();
suite('smart-system/BaseModule', function() {
mocksForBaseModule.attachTestHelpers();
setup(function(done) {
requireApp('smart-system/js/base_module.js', done);
});
test('lowercase capital', function() {
assert.equal('appWindowManager',
BaseModule.lowerCapital('AppWindowManager'));
});
test('parse module path', function() {
var module = BaseModule.parsePath('path/to/ModuleName');
assert.equal(module.path, 'path/to/');
assert.equal(module.name, 'ModuleName');
});
test('object name to file name', function() {
assert.deepEqual('/js/app_window_manager.js',
BaseModule.object2fileName('AppWindowManager'));
assert.deepEqual('/js/path/to/module_name.js',
BaseModule.object2fileName('path/to/ModuleName'));
});
test('lazy load from an array of submodule strings', function(done) {
var stubLoad = this.sinon.stub(MockLazyLoader, 'load');
BaseModule.lazyLoad(['AppWindowManager']).then(function() {
done();
});
assert.isTrue(stubLoad.calledWith(['/js/app_window_manager.js']));
stubLoad.yield();
});
suite('Launching promise', function() {
test('start should resolve right away', function(done) {
var LaunchingPromiseTester = function() {};
BaseModule.create(LaunchingPromiseTester, {
name: 'LaunchingPromiseTester'
});
var lpt = BaseModule.instantiate('LaunchingPromiseTester');
lpt.start().catch((e) => {throw e || 'Should not throw'; })
.then(done, done);
});
test('custom start', function(done) {
var LaunchingPromiseTester = function() {};
BaseModule.create(LaunchingPromiseTester, {
name: 'LaunchingPromiseTester',
_start: function() {
return new Promise(function(resolve) {
resolve();
});
}
});
var lpt = BaseModule.instantiate('LaunchingPromiseTester');
lpt.start().catch((e) => {throw e || 'Should not throw'; })
.then(done, done);
});
});
suite('BaseModule.instantiate', function() {
test('Get a new instance if the module is available', function() {
var InstantiationTester = function() {};
BaseModule.create(InstantiationTester, {
name: 'InstantiationTester'
});
assert.isDefined(BaseModule.instantiate('InstantiationTester'));
assert.equal(BaseModule.instantiate('InstantiationTester').name,
'InstantiationTester');
});
test('Get undefined if the module is unavailable', function() {
assert.isUndefined(BaseModule.instantiate('NoSuchModule'));
});
});
suite('Centralized settins observer', function() {
var fakeAppWindowManager, settings;
setup(function() {
var FakeAppWindowManager = function() {};
FakeAppWindowManager.SETTINGS = ['app-suspending.enabled'];
BaseModule.create(FakeAppWindowManager, {
name: 'FakeAppWindowManager'
});
settings = {
'app-suspending.enabled': true
};
fakeAppWindowManager = new FakeAppWindowManager();
});
teardown(function() {
fakeAppWindowManager.stop();
});
test('addObserver will be called if SETTINGS is specified', function(done) {
var spy = this.sinon.stub(fakeAppWindowManager, 'observe');
this.sinon.stub(MockService, 'request',
function(service, name, consumer) {
if (service === 'SettingsCore:addObserver') {
assert.equal(name, 'app-suspending.enabled');
assert.deepEqual(consumer, fakeAppWindowManager);
consumer.observe(name, settings[name]);
assert.isTrue(spy.calledWith('app-suspending.enabled', true));
done();
}
});
fakeAppWindowManager.start();
});
test('get settings', function(done) {
this.sinon.stub(MockService, 'request').returns(
new Promise(function(resolve) {
resolve(new Promise(function(iresolve) {
iresolve(true);
}));
}));
fakeAppWindowManager.readSetting('app-suspending.enabled')
.then(function(value) {
assert.equal(value, true);
done();
});
});
test('set settings', function(done) {
this.sinon.stub(MockService, 'request',
function(service, object) {
for (var key in object) {
settings[key] = object[key];
}
assert.equal(settings['app-suspending.enabled'], false);
done();
});
fakeAppWindowManager.writeSetting({'app-suspending.enabled': false});
});
test('settings relation function will not be injected if not specified',
function() {
var fakeAppWindowManager2;
var FakeAppWindowManager2 = function() {};
BaseModule.create(FakeAppWindowManager2, {
name: 'FakeAppWindowManager2'
});
fakeAppWindowManager2 = new FakeAppWindowManager2();
assert.isUndefined(fakeAppWindowManager2.observe);
assert.isUndefined(fakeAppWindowManager2._observeSettings);
assert.isUndefined(fakeAppWindowManager2._unobserveSettings);
});
});
suite('Centralized event handler', function() {
var fakeAppWindowManager;
setup(function() {
var FakeAppWindowManager = function() {};
FakeAppWindowManager.EVENTS = ['ftuskip'];
BaseModule.create(FakeAppWindowManager, {
name: 'FakeAppWindowManager'
});
fakeAppWindowManager = new FakeAppWindowManager();
});
teardown(function() {
fakeAppWindowManager.stop();
});
test('handleEvent should be called when registering events', function() {
var stubHandleEvent =
this.sinon.stub(fakeAppWindowManager, 'handleEvent');
window.dispatchEvent(new CustomEvent('ftuskip'));
assert.isFalse(stubHandleEvent.called);
fakeAppWindowManager.start();
var ftuskipEvent = new CustomEvent('ftuskip');
window.dispatchEvent(ftuskipEvent);
assert.isTrue(stubHandleEvent.calledWith(ftuskipEvent));
});
test('specific handler should be called if it exists', function() {
var stubHandleFtuskip =
fakeAppWindowManager._handle_ftuskip = this.sinon.spy();
window.dispatchEvent(new CustomEvent('ftuskip'));
assert.isFalse(stubHandleFtuskip.called);
fakeAppWindowManager.start();
var ftuskipEvent = new CustomEvent('ftuskip');
window.dispatchEvent(ftuskipEvent);
assert.isTrue(stubHandleFtuskip.calledWith(ftuskipEvent));
});
test('pre handler should be called if it exists', function() {
var spy = fakeAppWindowManager._handle_ftuskip = this.sinon.spy();
var ftuskipEvent = new CustomEvent('ftuskip');
window.dispatchEvent(ftuskipEvent);
assert.isFalse(spy.called);
fakeAppWindowManager.start();
window.dispatchEvent(ftuskipEvent);
assert.isTrue(spy.calledWith(ftuskipEvent));
});
test('pre handler should be called if it exists', function() {
var spy = fakeAppWindowManager._pre_handleEvent = this.sinon.spy();
var spyFtuskip = fakeAppWindowManager._handle_ftuskip = this.sinon.spy();
var ftuskipEvent = new CustomEvent('ftuskip');
window.dispatchEvent(ftuskipEvent);
assert.isFalse(spy.called);
assert.isFalse(spyFtuskip.called);
fakeAppWindowManager.start();
window.dispatchEvent(ftuskipEvent);
assert.isTrue(spy.calledWith(ftuskipEvent));
assert.isTrue(spyFtuskip.calledWith(ftuskipEvent));
});
test('specific event handler should be not called ' +
'if pre handler returns false', function() {
fakeAppWindowManager._pre_handleEvent = function() {};
var spy = this.sinon.stub(fakeAppWindowManager,
'_pre_handleEvent').returns(false);
var spyFtuskip = fakeAppWindowManager._handle_ftuskip = this.sinon.spy();
var ftuskipEvent = new CustomEvent('ftuskip');
window.dispatchEvent(ftuskipEvent);
assert.isFalse(spy.called);
assert.isFalse(spyFtuskip.called);
fakeAppWindowManager.start();
window.dispatchEvent(ftuskipEvent);
assert.isTrue(spy.calledWith(ftuskipEvent));
assert.isFalse(spyFtuskip.calledWith(ftuskipEvent));
});
test('post handler should be called if it exists', function() {
var spy = fakeAppWindowManager._post_handleEvent = this.sinon.spy();
var ftuskipEvent = new CustomEvent('ftuskip');
window.dispatchEvent(ftuskipEvent);
assert.isFalse(spy.called);
fakeAppWindowManager.start();
window.dispatchEvent(ftuskipEvent);
assert.isTrue(spy.calledWith(ftuskipEvent));
});
test('event relation function will not be injected if not specified',
function() {
var FakeAppWindowManager2 = function() {};
BaseModule.create(FakeAppWindowManager2, {
name: 'FakeAppWindowManager2'
});
var fakeAppWindowManager2 = new FakeAppWindowManager2();
assert.isUndefined(fakeAppWindowManager2.handleEvent);
assert.isUndefined(fakeAppWindowManager2._pre_handleEvent);
assert.isUndefined(fakeAppWindowManager2._post_handleEvent);
assert.isUndefined(fakeAppWindowManager2._subscribeEvents);
assert.isUndefined(fakeAppWindowManager2._unsubscribeEvents);
});
});
suite('Submodule management', function() {
var fakeAppWindowManager, fakePromise;
setup(function() {
BaseModule.__clearDefined();
});
suite('Already defined submodules with array SUB_MODULES', function() {
setup(function() {
fakePromise = new MockPromise();
this.sinon.stub(BaseModule, 'lazyLoad', function() {
return fakePromise;
});
window.FakeAppWindowManager = function() {};
window.FakeAppWindowManager.SUB_MODULES = ['FakeTaskManager'];
BaseModule.create(window.FakeAppWindowManager, {
name: 'FakeAppWindowManager'
});
window.FakeTaskManager = function() {};
BaseModule.create(window.FakeTaskManager, {
name: 'FakeTaskManager'
});
fakeAppWindowManager = new window.FakeAppWindowManager();
fakeAppWindowManager.start();
});
test('submodule should be not loaded', function() {
fakeAppWindowManager._fakeTaskManager_loaded = this.sinon.spy();
assert.isDefined(fakeAppWindowManager.fakeTaskManager);
assert.isFalse(fakeAppWindowManager._fakeTaskManager_loaded.called);
});
});
suite('Already defined submodules with object SUB_MODULES', function() {
setup(function() {
fakePromise = new MockPromise();
this.sinon.stub(BaseModule, 'lazyLoad', function() {
return fakePromise;
});
window.FakeAppWindowManager = function() {};
window.FakeAppWindowManager.SUB_MODULES = {
default: ['FakeTaskManager']
};
BaseModule.create(window.FakeAppWindowManager, {
name: 'FakeAppWindowManager'
});
window.FakeTaskManager = function() {};
BaseModule.create(window.FakeTaskManager, {
name: 'FakeTaskManager'
});
fakeAppWindowManager = new window.FakeAppWindowManager();
fakeAppWindowManager.start();
});
test('submodule should be not loaded', function() {
fakeAppWindowManager._fakeTaskManager_loaded = this.sinon.spy();
assert.isDefined(fakeAppWindowManager.fakeTaskManager);
assert.isFalse(fakeAppWindowManager._fakeTaskManager_loaded.called);
});
});
suite('Not defined submodules with array SUB_MODULES', function() {
setup(function() {
fakePromise = new MockPromise();
this.sinon.stub(BaseModule, 'lazyLoad', function() {
return fakePromise;
});
window.FakeAppWindowManager = function() {};
window.FakeAppWindowManager.SUB_MODULES = [
'FakeTaskManager',
'path/to/FakeSubModuleInDir'
];
BaseModule.create(window.FakeAppWindowManager, {
name: 'FakeAppWindowManager'
});
window.FakeTaskManager = null;
window.FakeSubModuleInDir = null;
fakeAppWindowManager = new window.FakeAppWindowManager();
fakeAppWindowManager.start();
});
teardown(function() {
fakeAppWindowManager.stop();
window.FakeTaskManager = null;
window.FakeAppWindowManager = null;
window.FakeSubModuleInDir = null;
});
test('submodule should be loaded', function() {
var spy = fakeAppWindowManager._fakeTaskManager_loaded =
this.sinon.spy();
var spy2 = fakeAppWindowManager._fakeSubModuleInDir_loaded =
this.sinon.spy();
window.FakeTaskManager = function() {};
BaseModule.create(window.FakeTaskManager, {
name: 'FakeTaskManager'
});
window.FakeSubModuleInDir = function() {};
BaseModule.create(window.FakeSubModuleInDir, {
name: 'FakeSubModuleInDir'
});
fakePromise.mFulfillToValue();
assert.isDefined(fakeAppWindowManager.fakeTaskManager);
assert.isTrue(spy.called);
assert.isDefined(fakeAppWindowManager.fakeSubModuleInDir);
assert.isTrue(spy2.called);
});
test('submodule loaded handler should be called if it exists',
function() {
var spy = fakeAppWindowManager._fakeTaskManager_loaded =
this.sinon.spy();
window.FakeTaskManager = function() {};
BaseModule.create(window.FakeTaskManager, {
name: 'FakeTaskManager'
});
fakePromise.mFulfillToValue();
assert.isDefined(fakeAppWindowManager.fakeTaskManager);
assert.isTrue(spy.called);
});
test('submodule should be started once parent is started', function() {
window.FakeTaskManager = function() {};
BaseModule.create(window.FakeTaskManager, {
name: 'FakeTaskManager'
});
var spyStart = this.sinon.stub(window.FakeTaskManager.prototype,
'start');
fakePromise.mFulfillToValue();
assert.isTrue(spyStart.called);
});
test('submodule should be stopped once parent is stopped', function() {
window.FakeTaskManager = function() {};
window.FakeSubModuleInDir = function() {};
BaseModule.create(window.FakeTaskManager, {
name: 'FakeTaskManager'
});
BaseModule.create(window.FakeSubModuleInDir, {
name: 'FakeSubModuleInDir'
});
fakePromise.mFulfillToValue();
var spyStop =
this.sinon.stub(fakeAppWindowManager.fakeTaskManager, 'stop');
var spyStop2 =
this.sinon.stub(fakeAppWindowManager.fakeSubModuleInDir, 'stop');
fakeAppWindowManager.stop();
assert.isTrue(spyStop.called);
assert.isTrue(spyStop2.called);
});
test('submodule should not be started if the parent is already stopped',
function() {
window.FakeTaskManager = function() {};
BaseModule.create(window.FakeTaskManager, {
name: 'FakeTaskManager'
});
var spyStart =
this.sinon.stub(window.FakeTaskManager.prototype, 'start');
fakeAppWindowManager.stop();
fakePromise.mFulfillToValue();
assert.isFalse(spyStart.called);
});
});
suite('Not defined submodules with object SUB_MODULES', function() {
setup(function() {
fakePromise = new MockPromise();
this.sinon.stub(BaseModule, 'lazyLoad', function() {
return fakePromise;
});
window.FakeAppWindowManager = function() {};
window.FakeAppWindowManager.SUB_MODULES = {
default: ['FakeTaskManager'],
_GAIA_DEVICE_TYPE_: ['path/to/FakeSubModuleInDir']
};
BaseModule.create(window.FakeAppWindowManager, {
name: 'FakeAppWindowManager'
});
window.FakeTaskManager = null;
window.FakeSubModuleInDir = null;
fakeAppWindowManager = new window.FakeAppWindowManager();
fakeAppWindowManager.start();
});
teardown(function() {
fakeAppWindowManager.stop();
window.FakeTaskManager = null;
window.FakeAppWindowManager = null;
window.FakeSubModuleInDir = null;
});
test('submodule should be loaded', function() {
var spy = fakeAppWindowManager._fakeTaskManager_loaded =
this.sinon.spy();
var spy2 = fakeAppWindowManager._fakeSubModuleInDir_loaded =
this.sinon.spy();
window.FakeTaskManager = function() {};
BaseModule.create(window.FakeTaskManager, {
name: 'FakeTaskManager'
});
window.FakeSubModuleInDir = function() {};
BaseModule.create(window.FakeSubModuleInDir, {
name: 'FakeSubModuleInDir'
});
fakePromise.mFulfillToValue();
assert.isDefined(fakeAppWindowManager.fakeTaskManager);
assert.isTrue(spy.called);
assert.isDefined(fakeAppWindowManager.fakeSubModuleInDir);
assert.isTrue(spy2.called);
});
test('submodule loaded handler should be called if it exists',
function() {
var spy = fakeAppWindowManager._fakeTaskManager_loaded =
this.sinon.spy();
window.FakeTaskManager = function() {};
BaseModule.create(window.FakeTaskManager, {
name: 'FakeTaskManager'
});
fakePromise.mFulfillToValue();
assert.isDefined(fakeAppWindowManager.fakeTaskManager);
assert.isTrue(spy.called);
});
test('submodule should be started once parent is started', function() {
window.FakeTaskManager = function() {};
BaseModule.create(window.FakeTaskManager, {
name: 'FakeTaskManager'
});
var spyStart = this.sinon.stub(window.FakeTaskManager.prototype,
'start');
fakePromise.mFulfillToValue();
assert.isTrue(spyStart.called);
});
test('submodule should be stopped once parent is stopped', function() {
window.FakeTaskManager = function() {};
window.FakeSubModuleInDir = function() {};
BaseModule.create(window.FakeTaskManager, {
name: 'FakeTaskManager'
});
BaseModule.create(window.FakeSubModuleInDir, {
name: 'FakeSubModuleInDir'
});
fakePromise.mFulfillToValue();
var spyStop =
this.sinon.stub(fakeAppWindowManager.fakeTaskManager, 'stop');
var spyStop2 =
this.sinon.stub(fakeAppWindowManager.fakeSubModuleInDir, 'stop');
fakeAppWindowManager.stop();
assert.isTrue(spyStop.called);
assert.isTrue(spyStop2.called);
});
test('submodule should not be started if the parent is already stopped',
function() {
window.FakeTaskManager = function() {};
BaseModule.create(window.FakeTaskManager, {
name: 'FakeTaskManager'
});
var spyStart =
this.sinon.stub(window.FakeTaskManager.prototype, 'start');
fakeAppWindowManager.stop();
fakePromise.mFulfillToValue();
assert.isFalse(spyStart.called);
});
});
});
suite('Service registration', function() {
var fakeAppWindowManager;
setup(function() {
var FakeAppWindowManager = function() {};
FakeAppWindowManager.SERVICES = ['isBusyLoading'];
BaseModule.create(FakeAppWindowManager, {
name: 'FakeAppWindowManager',
isBusyLoading: function() {}
});
fakeAppWindowManager = new FakeAppWindowManager();
fakeAppWindowManager.start();
});
teardown(function() {
fakeAppWindowManager.stop();
});
test('register/unregister functions should be injected', function() {
assert.isDefined(fakeAppWindowManager._registerServices);
assert.isDefined(fakeAppWindowManager._unregisterServices);
});
test('Should register service to System when starting', function() {
fakeAppWindowManager.stop();
var stubRegister = this.sinon.stub(MockService, 'register');
fakeAppWindowManager.start();
assert.isTrue(stubRegister.calledWith('isBusyLoading',
fakeAppWindowManager));
});
test('Should unregister service to System when stopping', function() {
var stubRegister = this.sinon.stub(MockService, 'unregister');
fakeAppWindowManager.stop();
assert.isTrue(stubRegister.calledWith('isBusyLoading',
fakeAppWindowManager));
});
test('Should not inject service registration functions', function() {
var FakeAppWindowManager2 = function() {};
BaseModule.create(FakeAppWindowManager2, {
name: 'FakeAppWindowManager2',
isBusyLoading: function() {}
});
var fakeAppWindowManager2 = new FakeAppWindowManager2();
assert.isUndefined(fakeAppWindowManager2._registerServices);
assert.isUndefined(fakeAppWindowManager2._unregisterServices);
});
});
suite('State registration', function() {
var fakeFtuLauncher;
setup(function() {
var FakeFtuLauncher = function() {};
FakeFtuLauncher.STATES = ['isUpgrading'];
BaseModule.create(FakeFtuLauncher, {
_upgrading: false,
name: 'FakeFtuLauncher',
isUpgrading: function() {
return this._upgrading;
}
});
fakeFtuLauncher = new FakeFtuLauncher();
fakeFtuLauncher.start();
});
teardown(function() {
fakeFtuLauncher.stop();
});
test('Should register service to System when starting', function() {
fakeFtuLauncher.stop();
var stubRegister = this.sinon.stub(MockService, 'registerState');
fakeFtuLauncher.start();
assert.isTrue(stubRegister.calledWith('isUpgrading',
fakeFtuLauncher));
});
test('Should unregister service to System when stopping', function() {
var stubRegister = this.sinon.stub(MockService, 'unregisterState');
fakeFtuLauncher.stop();
assert.isTrue(stubRegister.calledWith('isUpgrading',
fakeFtuLauncher));
});
test('Should not inject service registration functions', function() {
var FakeFtuLauncher2 = function() {};
BaseModule.create(FakeFtuLauncher2, {
name: 'FakeFtuLauncher2',
isUpgrading: function() {}
});
var fakeFtuLauncher2 = new FakeFtuLauncher2();
this.sinon.stub(MockService, 'registerState');
this.sinon.stub(MockService, 'unregisterState');
fakeFtuLauncher2.start();
assert.isFalse(MockService.registerState.called);
fakeFtuLauncher2.stop();
assert.isFalse(MockService.unregisterState.called);
});
});
suite('Start chain', function() {
var chainTester;
var chainTester_startDeferred, cModule_startDeferred;
setup(function() {
chainTester_startDeferred = new Deferred();
cModule_startDeferred = new Deferred();
var ChainTester = function() {};
var CModule = function() {};
BaseModule.create(CModule, {
name: 'CModule',
DEBUG: true,
_start: sinon.spy(function() {
return cModule_startDeferred.promise;
})
});
ChainTester.SUB_MODULES = ['CModule'];
BaseModule.create(ChainTester, {
name: 'ChainTester',
DEBUG: true,
_start: sinon.spy(function() {
return chainTester_startDeferred.promise;
})
});
chainTester = new ChainTester();
});
test('Should wait until child start', function(done) {
var p = chainTester.start();
assert.isTrue(chainTester._start.calledOnce);
assert.isTrue(chainTester.cModule._start.calledOnce);
p.then(done, done);
chainTester_startDeferred.resolve();
cModule_startDeferred.resolve();
});
});
suite('Import', function() {
var importTester;
setup(function() {
var ImportTester = function() {};
ImportTester.IMPORTS = ['BModule', 'CModule'];
BaseModule.create(ImportTester, {
name: 'ImportTester',
_start: function() {}
});
importTester = new ImportTester();
});
teardown(function() {
importTester.stop();
});
test('Module start will be executed until import loaded', function() {
var p = new MockPromise();
this.sinon.stub(MockLazyLoader, 'load', function() {
return p;
});
var stubCustomStart = this.sinon.stub(importTester, '_start');
importTester.start();
assert.isFalse(stubCustomStart.called);
p.mFulfillToValue();
assert.isTrue(stubCustomStart.called);
});
});
suite('Module life cycle control', function() {
var lifeCycleTester;
setup(function() {
var LifeCycleTester = function() {};
BaseModule.create(LifeCycleTester, {
name: 'LifeCycleTester',
_start: function() {},
_stop: function() {}
});
lifeCycleTester = new LifeCycleTester();
});
teardown(function() {
lifeCycleTester.stop();
});
test('custom start should be triggered', function() {
var spy = this.sinon.stub(lifeCycleTester, '_start');
lifeCycleTester.start();
assert.isTrue(spy.calledOnce);
});
test('custom start will not execute if already started', function() {
lifeCycleTester.start();
var spy = this.sinon.stub(lifeCycleTester, '_start');
lifeCycleTester.start();
assert.isFalse(spy.called);
});
test('custom stop should be triggered', function() {
var spy = this.sinon.stub(lifeCycleTester, '_stop');
lifeCycleTester.start();
lifeCycleTester.stop();
assert.isTrue(spy.calledOnce);
});
test('custom stop will not execute if already stopped', function() {
lifeCycleTester.start();
lifeCycleTester.stop();
var spy = this.sinon.stub(lifeCycleTester, '_stop');
lifeCycleTester.stop();
assert.isFalse(spy.called);
});
});
});

View file

@ -0,0 +1,12 @@
'use strict';
(function(exports) {
var Deferred = function() {
this.promise = new Promise(function(resolve, reject) {
this.resolve = resolve;
this.reject = reject;
}.bind(this));
return this;
};
exports.Deferred = Deferred;
}(window));

View file

@ -0,0 +1,371 @@
/* global FxAccountsClient */
'use strict';
requireApp('smart-system/js/fx_accounts_client.js');
var MockEventListener = {};
var MockDispatchedEvents = [];
function MockAddEventListener(event, listener) {
MockEventListener[event] = listener;
}
function MockRemoveEventListener(event, listener) {
delete MockEventListener[event];
}
function MockDispatchEvent(event) {
MockDispatchedEvents.push(event);
}
suite('system/FxAccountsClient >', function() {
var result = null;
var error = null;
var expectedData = 'data';
var expectedError = 'error';
var successCbCalled = false;
var errorCbCalled = false;
var stubAddEventListener;
var stubRemoveEventListener;
var stubDispatchEvent;
function successCb(data) {
successCbCalled = true;
result = data;
}
function errorCb(errorMsg) {
errorCbCalled = true;
error = errorMsg;
}
setup(function() {
stubAddEventListener = this.sinon.stub(window, 'addEventListener',
MockAddEventListener);
stubRemoveEventListener = this.sinon.stub(window, 'removeEventListener',
MockRemoveEventListener);
stubDispatchEvent = this.sinon.stub(window, 'dispatchEvent',
MockDispatchEvent);
});
teardown(function() {
stubAddEventListener.restore();
stubRemoveEventListener.restore();
stubDispatchEvent.restore();
});
suite('Init', function() {
test('Integrity', function() {
assert.isNotNull(FxAccountsClient);
assert.equal(Object.keys(FxAccountsClient).length, 9);
});
test('No event listeners', function() {
assert.isUndefined(MockEventListener.mozFxAccountsChromeEvent);
});
});
// API calls
suite('getAccount', function() {
setup(function() {
FxAccountsClient.getAccount(successCb, errorCb);
});
test('Event dispatched to chrome side', function() {
assert.equal(MockDispatchedEvents.length, 1);
assert.ok(MockEventListener.mozFxAccountsChromeEvent);
assert.ok(MockDispatchedEvents[0].detail.id);
assert.ok(MockDispatchedEvents[0].detail.data);
assert.deepEqual(MockDispatchedEvents[0].detail.data, {
method: 'getAccount'
});
});
});
suite('getAccount reply success', function() {
setup(function() {
MockEventListener.mozFxAccountsChromeEvent({
detail: {
id: MockDispatchedEvents[0].detail.id,
data: expectedData
}
});
});
suiteTeardown(function() {
MockDispatchedEvents = [];
result = null;
error = null;
successCbCalled = false;
errorCbCalled = false;
});
test('On chrome event', function() {
assert.isTrue(successCbCalled);
assert.isFalse(errorCbCalled);
assert.equal(result, expectedData);
});
});
suite('getAccount', function() {
setup(function() {
FxAccountsClient.getAccount(successCb, errorCb);
});
test('Event dispatched to chrome side', function() {
assert.equal(MockDispatchedEvents.length, 1);
assert.ok(MockEventListener.mozFxAccountsChromeEvent);
assert.ok(MockDispatchedEvents[0].detail.id);
assert.ok(MockDispatchedEvents[0].detail.data);
assert.deepEqual(MockDispatchedEvents[0].detail.data, {
method: 'getAccount'
});
});
});
suite('getAccount reply error', function() {
setup(function() {
MockEventListener.mozFxAccountsChromeEvent({
detail: {
id: MockDispatchedEvents[0].detail.id,
error: expectedError
}
});
});
suiteTeardown(function() {
MockDispatchedEvents = [];
result = null;
error = null;
successCbCalled = false;
errorCbCalled = false;
});
test('On chrome event', function() {
assert.isFalse(successCbCalled);
assert.isTrue(errorCbCalled);
assert.equal(error, expectedError);
});
});
suite('logout', function() {
setup(function() {
FxAccountsClient.logout(successCb, errorCb);
});
test('Event dispatched to chrome side', function() {
assert.equal(MockDispatchedEvents.length, 1);
assert.ok(MockEventListener.mozFxAccountsChromeEvent);
assert.ok(MockDispatchedEvents[0].detail.id);
assert.ok(MockDispatchedEvents[0].detail.data);
assert.deepEqual(MockDispatchedEvents[0].detail.data, {
method: 'logout'
});
});
suiteTeardown(function() {
MockDispatchedEvents = [];
});
});
suite('queryAccount/verificationStatus', function() {
setup(function() {
FxAccountsClient.queryAccount('email', successCb, errorCb);
FxAccountsClient.verificationStatus('email', successCb, errorCb);
});
test('Event dispatched to chrome side', function() {
assert.equal(MockDispatchedEvents.length, 2);
assert.ok(MockEventListener.mozFxAccountsChromeEvent);
assert.ok(MockDispatchedEvents[0].detail.id);
assert.ok(MockDispatchedEvents[1].detail.id);
assert.ok(MockDispatchedEvents[0].detail.data);
assert.ok(MockDispatchedEvents[1].detail.data);
assert.deepEqual(MockDispatchedEvents[0].detail.data, {
method: 'queryAccount',
email: 'email'
});
assert.deepEqual(MockDispatchedEvents[1].detail.data, {
method: 'verificationStatus',
email: 'email'
});
});
suiteTeardown(function() {
MockDispatchedEvents = [];
});
});
suite('signIn/signUp', function() {
setup(function() {
FxAccountsClient.signIn('email', 'pass', successCb, errorCb);
FxAccountsClient.signUp('email', 'pass', successCb, errorCb);
});
test('Event dispatched to chrome side', function() {
assert.equal(MockDispatchedEvents.length, 2);
assert.ok(MockEventListener.mozFxAccountsChromeEvent);
assert.ok(MockDispatchedEvents[0].detail.id);
assert.ok(MockDispatchedEvents[1].detail.id);
assert.ok(MockDispatchedEvents[0].detail.data);
assert.ok(MockDispatchedEvents[1].detail.data);
var signInData = MockDispatchedEvents[0].detail.data;
assert.equal(signInData.method, 'signIn');
assert.equal(signInData.email, 'email');
assert.equal(signInData.password, 'pass');
assert.ok(signInData.fetchKeys !== undefined);
var signUpData = MockDispatchedEvents[1].detail.data;
assert.equal(signUpData.method, 'signUp');
assert.equal(signUpData.email, 'email');
assert.equal(signUpData.password, 'pass');
assert.ok(signUpData.fetchKeys !== undefined);
});
suiteTeardown(function() {
MockDispatchedEvents = [];
});
});
suite('resendVerificationEmail', function() {
setup(function() {
FxAccountsClient.resendVerificationEmail('email', successCb, errorCb);
});
test('Event dispatched to chrome side', function() {
assert.equal(MockDispatchedEvents.length, 1);
assert.ok(MockEventListener.mozFxAccountsChromeEvent);
assert.ok(MockDispatchedEvents[0].detail.id);
assert.ok(MockDispatchedEvents[0].detail.data);
assert.deepEqual(MockDispatchedEvents[0].detail.data, {
method: 'resendVerificationEmail',
email: 'email'
});
});
suiteTeardown(function() {
MockDispatchedEvents = [];
});
});
suite('getKeys', function() {
setup(function() {
FxAccountsClient.getKeys(successCb, errorCb);
});
test('Event dispatched to chrome side', function() {
assert.equal(MockDispatchedEvents.length, 1);
assert.ok(MockEventListener.mozFxAccountsChromeEvent);
assert.ok(MockDispatchedEvents[0].detail.id);
assert.ok(MockDispatchedEvents[0].detail.data);
assert.deepEqual(MockDispatchedEvents[0].detail.data, {
method: 'getKeys'
});
});
});
suite('getKeys response', function() {
setup(function() {
MockEventListener.mozFxAccountsChromeEvent({
detail: {
id: MockDispatchedEvents[0].detail.id,
data: expectedData
}
});
});
suiteTeardown(function() {
MockDispatchedEvents = [];
result = null;
error = null;
successCbCalled = false;
errorCbCalled = false;
});
test('On chrome event', function() {
assert.isTrue(successCbCalled);
assert.isFalse(errorCbCalled);
assert.equal(result, expectedData);
});
});
suite('getAssertion', function() {
setup(function() {
FxAccountsClient.getAssertion({
silent: true,
audience: 'audience'
}, successCb, errorCb);
});
teardown(function() {
MockDispatchedEvents = [];
});
test('Event dispatched to chrome side', function() {
assert.equal(MockDispatchedEvents.length, 1);
assert.ok(MockEventListener.mozFxAccountsChromeEvent);
assert.ok(MockDispatchedEvents[0].detail.id);
assert.ok(MockDispatchedEvents[0].detail.data);
assert.deepEqual(MockDispatchedEvents[0].detail.data, {
method: 'getAssertion',
silent: true,
audience: 'audience'
});
});
});
suite('getAssertion - no options', function() {
setup(function() {
FxAccountsClient.getAssertion(null, successCb, errorCb);
});
teardown(function() {
MockDispatchedEvents = [];
});
test('Event dispatched to chrome side', function() {
assert.equal(MockDispatchedEvents.length, 1);
assert.ok(MockEventListener.mozFxAccountsChromeEvent);
assert.ok(MockDispatchedEvents[0].detail.id);
assert.ok(MockDispatchedEvents[0].detail.data);
assert.deepEqual(MockDispatchedEvents[0].detail.data, {
method: 'getAssertion',
silent: null,
audience: null
});
});
});
suite('getAssertion response', function() {
setup(function() {
FxAccountsClient.getAssertion(null, successCb, errorCb);
MockEventListener.mozFxAccountsChromeEvent({
detail: {
id: MockDispatchedEvents[0].detail.id,
data: expectedData
}
});
});
suiteTeardown(function() {
MockDispatchedEvents = [];
result = null;
error = null;
successCbCalled = false;
errorCbCalled = false;
});
test('On chrome event', function() {
assert.isTrue(successCbCalled);
assert.isFalse(errorCbCalled);
assert.equal(result, expectedData);
});
});
});

View file

@ -0,0 +1,445 @@
/* global FxAccountsClient, FxAccountsManager, FxAccountsUI,
MocksHelper, MockIACPort */
'use strict';
requireApp('system/js/fx_accounts_manager.js');
requireApp('system/test/unit/mock_fxa_client.js');
requireApp('system/test/unit/mock_fxa_ui.js');
requireApp('system/test/unit/mock_iac_handler.js');
require('/shared/test/unit/mocks/mock_lazy_loader.js');
var MockEventListener = {};
function MockAddEventListener(event, listener) {
MockEventListener[event] = listener;
}
var mocksHelperFxAManager = new MocksHelper([
'FxAccountsClient',
'FxAccountsUI',
'IACHandler',
'LazyLoader'
]).init();
suite('system/FxAccountManager >', function() {
var stubAddEventListener;
mocksHelperFxAManager.attachTestHelpers();
setup(function() {
stubAddEventListener = this.sinon.stub(window, 'addEventListener',
MockAddEventListener);
FxAccountsManager.start();
});
teardown(function() {
stubAddEventListener.restore();
});
suite('Init', function() {
test('Integrity', function() {
assert.isNotNull(FxAccountsManager);
assert.equal(Object.keys(FxAccountsManager).length, 5);
});
test('Test event listeners', function() {
assert.ok(MockEventListener['iac-fxa-mgmt']);
assert.ok(MockEventListener['iac-fxa-mgmt'] instanceof Function);
assert.ok(MockEventListener.mozFxAccountsUnsolChromeEvent);
assert.ok(MockEventListener.mozFxAccountsUnsolChromeEvent instanceof
Object);
});
});
suite('On getAccount port message, successCb', function() {
setup(function() {
FxAccountsClient._successMsg = 'success';
FxAccountsManager.onPortMessage({
'detail': {
'name': 'getAccount'
}
});
});
teardown(function() {
FxAccountsClient._reset();
});
test('FxAccountsClient.getAccount called', function() {
assert.equal(FxAccountsClient._call, 'getAccount');
});
test('Got fxa-mgmt port', function() {
assert.equal(MockIACPort._name, 'fxa-mgmt');
});
test('Sent success message through port', function() {
assert.equal(MockIACPort._messages.length, 1);
assert.ok(MockIACPort._messages[0] instanceof Object);
assert.deepEqual(MockIACPort._messages[0], {
'methodName': 'getAccount',
'data': 'success'
});
});
});
suite('On getAccount port message, errorCb', function() {
setup(function() {
FxAccountsClient._errorMsg = 'error';
FxAccountsManager.onPortMessage({
'detail': {
'name': 'getAccount'
}
});
});
teardown(function() {
FxAccountsClient._reset();
});
test('FxAccountsClient.getAccount called', function() {
assert.equal(FxAccountsClient._call, 'getAccount');
});
test('Got fxa-mgmt port', function() {
assert.equal(MockIACPort._name, 'fxa-mgmt');
});
test('Sent success message through port', function() {
assert.equal(MockIACPort._messages.length, 1);
assert.ok(MockIACPort._messages[0] instanceof Object);
assert.deepEqual(MockIACPort._messages[0], {
'methodName': 'getAccount',
'error': 'error'
});
});
});
suite('On logout port message, successCb', function() {
setup(function() {
FxAccountsClient._successMsg = 'success';
FxAccountsManager.onPortMessage({
'detail': {
'name': 'logout'
}
});
});
teardown(function() {
FxAccountsClient._reset();
});
test('FxAccountsClient.logout called', function() {
assert.equal(FxAccountsClient._call, 'logout');
});
test('Got fxa-mgmt port', function() {
assert.equal(MockIACPort._name, 'fxa-mgmt');
});
test('Sent success message through port', function() {
assert.equal(MockIACPort._messages.length, 1);
assert.ok(MockIACPort._messages[0] instanceof Object);
assert.deepEqual(MockIACPort._messages[0], {
'methodName': 'logout',
'data': 'success'
});
});
});
suite('On logout port message, errorCb', function() {
setup(function() {
FxAccountsClient._errorMsg = 'error';
FxAccountsManager.onPortMessage({
'detail': {
'name': 'logout'
}
});
});
teardown(function() {
FxAccountsClient._reset();
});
test('FxAccountsClient.logout called', function() {
assert.equal(FxAccountsClient._call, 'logout');
});
test('Got fxa-mgmt port', function() {
assert.equal(MockIACPort._name, 'fxa-mgmt');
});
test('Sent success message through port', function() {
assert.equal(MockIACPort._messages.length, 1);
assert.ok(MockIACPort._messages[0] instanceof Object);
assert.deepEqual(MockIACPort._messages[0], {
'methodName': 'logout',
'error': 'error'
});
});
});
suite('On openFlow port message, successCb', function() {
setup(function() {
FxAccountsUI._successMsg = 'success';
FxAccountsManager.onPortMessage({
'detail': {
'name': 'openFlow'
}
});
});
teardown(function() {
FxAccountsUI._reset();
});
test('FxAccountsUI.login called', function() {
assert.equal(FxAccountsUI._call, 'login');
});
test('Got fxa-mgmt port', function() {
assert.equal(MockIACPort._name, 'fxa-mgmt');
});
test('Sent success message through port', function() {
assert.equal(MockIACPort._messages.length, 1);
assert.ok(MockIACPort._messages[0] instanceof Object);
assert.deepEqual(MockIACPort._messages[0], {
'methodName': 'openFlow',
'data': 'success'
});
});
});
suite('On openFlow port message, errorCb', function() {
setup(function() {
FxAccountsUI._errorMsg = 'error';
FxAccountsManager.onPortMessage({
'detail': {
'name': 'openFlow'
}
});
});
teardown(function() {
FxAccountsUI._reset();
});
test('FxAccountsUI.login called', function() {
assert.equal(FxAccountsUI._call, 'login');
});
test('Got fxa-mgmt port', function() {
assert.equal(MockIACPort._name, 'fxa-mgmt');
});
test('Sent success message through port', function() {
assert.equal(MockIACPort._messages.length, 1);
assert.ok(MockIACPort._messages[0] instanceof Object);
assert.deepEqual(MockIACPort._messages[0], {
'methodName': 'openFlow',
'error': 'error'
});
});
});
suite('On openFlow mozFxAccountsRPChromeEvent', function() {
var id = 123;
var dispatchEventStub;
setup(function() {
dispatchEventStub = this.sinon.stub(window, 'dispatchEvent');
FxAccountsUI._successMsg = 'success';
FxAccountsManager.handleEvent({
'detail': {
'id': id,
'eventName': 'openFlow'
}
});
});
teardown(function() {
dispatchEventStub.restore();
FxAccountsUI._reset();
});
test('FxAccountsUI.login called', function() {
assert.equal(FxAccountsUI._call, 'login');
});
test('on FxAccountsUI reply sendContentEvent', function() {
sinon.assert.calledOnce(dispatchEventStub);
});
});
suite('On refreshAuthentication port message, successCb', function() {
setup(function() {
FxAccountsUI._successMsg = 'success';
FxAccountsManager.onPortMessage({
'detail': {
'name': 'refreshAuthentication',
'email': 'dummy@domain.org'
}
});
});
teardown(function() {
FxAccountsUI._reset();
});
test('FxAccountsUI.refreshAuthentication called', function() {
assert.equal(FxAccountsUI._call, 'refreshAuthentication');
assert.equal(FxAccountsUI._email, 'dummy@domain.org');
});
test('Got fxa-mgmt port', function() {
assert.equal(MockIACPort._name, 'fxa-mgmt');
});
test('Sent success message through port', function() {
assert.equal(MockIACPort._messages.length, 1);
assert.ok(MockIACPort._messages[0] instanceof Object);
assert.deepEqual(MockIACPort._messages[0], {
'methodName': 'refreshAuthentication',
'data': 'success'
});
});
});
suite('On refreshAuthentication port message, errorCb', function() {
setup(function() {
FxAccountsUI._errorMsg = 'error';
FxAccountsManager.onPortMessage({
'detail': {
'name': 'refreshAuthentication',
'email': 'dummy@domain.org'
}
});
});
teardown(function() {
FxAccountsUI._reset();
});
test('FxAccountsUI.refreshAuthentication called', function() {
assert.equal(FxAccountsUI._call, 'refreshAuthentication');
assert.equal(FxAccountsUI._email, 'dummy@domain.org');
});
test('Got fxa-mgmt port', function() {
assert.equal(MockIACPort._name, 'fxa-mgmt');
});
test('Sent success message through port', function() {
assert.equal(MockIACPort._messages.length, 1);
assert.ok(MockIACPort._messages[0] instanceof Object);
assert.deepEqual(MockIACPort._messages[0], {
'methodName': 'refreshAuthentication',
'error': 'error'
});
});
});
suite('On refreshAuthentication mozFxAccountsRPChromeEvent', function() {
var id = 123;
var dispatchEventStub;
setup(function() {
dispatchEventStub = this.sinon.stub(window, 'dispatchEvent');
FxAccountsUI._successMsg = 'success';
FxAccountsManager.handleEvent({
'detail': {
'id': id,
'eventName': 'refreshAuthentication',
'data': {
'email': 'dummy@domain.org'
}
}
});
});
teardown(function() {
dispatchEventStub.restore();
FxAccountsUI._reset();
});
test('FxAccountsUI.refreshAuthentication called', function() {
assert.equal(FxAccountsUI._call, 'refreshAuthentication');
assert.equal(FxAccountsUI._email, 'dummy@domain.org');
});
test('on FxAccountsUI reply sendContentEvent', function() {
sinon.assert.calledOnce(dispatchEventStub);
});
});
suite('On resendVerificationEmail port message, successCb', function() {
setup(function() {
FxAccountsClient._successMsg = 'success';
FxAccountsManager.onPortMessage({
'detail': {
'name': 'resendVerificationEmail',
'email': 'dummy@domain.org'
}
});
});
teardown(function() {
FxAccountsClient._reset();
});
test('FxAccountsClient.resendVerificationEmail called', function() {
assert.equal(FxAccountsClient._call, 'resendVerificationEmail');
assert.equal(FxAccountsClient._email, 'dummy@domain.org');
});
test('Got fxa-mgmt port', function() {
assert.equal(MockIACPort._name, 'fxa-mgmt');
});
test('Sent success message through port', function() {
assert.equal(MockIACPort._messages.length, 1);
assert.ok(MockIACPort._messages[0] instanceof Object);
assert.deepEqual(MockIACPort._messages[0], {
'methodName': 'resendVerificationEmail',
'data': 'success'
});
});
});
suite('On resendVerificationEmail port message, errorCb', function() {
setup(function() {
FxAccountsClient._errorMsg = 'error';
FxAccountsManager.onPortMessage({
'detail': {
'name': 'resendVerificationEmail',
'email': 'dummy@domain.org'
}
});
});
teardown(function() {
FxAccountsClient._reset();
});
test('FxAccountsClient.resendVerificationEmail called', function() {
assert.equal(FxAccountsClient._call, 'resendVerificationEmail');
assert.equal(FxAccountsClient._email, 'dummy@domain.org');
});
test('Got fxa-mgmt port', function() {
assert.equal(MockIACPort._name, 'fxa-mgmt');
});
test('Sent success message through port', function() {
assert.equal(MockIACPort._messages.length, 1);
assert.ok(MockIACPort._messages[0] instanceof Object);
assert.deepEqual(MockIACPort._messages[0], {
'methodName': 'resendVerificationEmail',
'error': 'error'
});
});
});
});

View file

@ -0,0 +1,227 @@
'use strict';
/* global MocksHelper, FxAccountsDialog, SystemDialog, LayoutManager,
focusManager */
/* jshint nonew: false */
require('/test/unit/mock_app_window_manager.js');
require('/test/unit/mock_layout_manager.js');
require('/test/unit/mock_system_dialog_manager.js');
require('/test/unit/mock_keyboard_manager.js');
require('/test/unit/mock_focus_manager.js');
require('/js/service.js');
require('/js/base_ui.js');
require('/js/system_dialog.js');
require('/js/fxa_dialog.js');
var mocksForFxAccountsDialog = new MocksHelper([
'AppWindowManager',
'LayoutManager',
'SystemDialogManager',
'KeyboardManager',
'focusManager'
]).init();
suite('smart-system/FxAccountsDialog', function() {
var stubDispatch, container,
fakeOptions = {
onShow: function() {},
onHide: function() {}
};
mocksForFxAccountsDialog.attachTestHelpers();
setup(function() {
container = document.createElement('div');
document.body.appendChild(container);
SystemDialog.prototype.containerElement = container;
stubDispatch = this.sinon.stub(window, 'dispatchEvent');
window.layoutManager = new LayoutManager();
});
teardown(function() {
document.body.removeChild(container);
SystemDialog.prototype.containerElement = container = null;
stubDispatch.restore();
window.layoutManager = null;
});
suite('Handle events', function() {
test('Create system dialog would trigger events', function() {
var fxAccountsDialog = new window.FxAccountsDialog(fakeOptions);
assert.isTrue(stubDispatch.calledWithMatch(sinon.match(
function(e) {
return 'system-dialog-created' === e.type;
})),
'the event has not been fired');
fxAccountsDialog = null;
});
test('Show system dialog would trigger events', function() {
var fxAccountsDialog = new window.FxAccountsDialog(fakeOptions);
fxAccountsDialog.show();
assert.isTrue(stubDispatch.calledWithMatch(sinon.match(
function(e) {
return 'system-dialog-show' === e.type;
})),
'the event has not been fired');
});
test('Hide system dialog would trigger events', function() {
var fxAccountsDialog = new window.FxAccountsDialog(fakeOptions);
fxAccountsDialog.hide();
assert.isTrue(stubDispatch.calledWithMatch(sinon.match(
function(e) {
return 'system-dialog-hide' === e.type;
})),
'the event has not been fired');
});
test('The attribute "onShow" should be called with reason ' +
'after system dialog is shown.', function() {
var fxAccountsDialog = new window.FxAccountsDialog(fakeOptions);
var stubOnShowCallback = this.sinon.stub(fxAccountsDialog.options,
'onShow');
var fakeReason = null;
fxAccountsDialog.onShow(fakeReason);
assert.isTrue(stubOnShowCallback.calledWith(null));
});
test('The attribute "onHide" should be called with reason ' +
'after system dialog is hidden.', function() {
var fxAccountsDialog = new window.FxAccountsDialog(fakeOptions);
var stubOnHideCallback = this.sinon.stub(fxAccountsDialog.options,
'onHide');
var fakeReason = 'home';
fxAccountsDialog.onHide(fakeReason);
assert.isTrue(stubOnHideCallback.calledWith('home'));
});
});
suite('Create instance ID', function() {
test('Create system Firefox accounts dialog ' +
'would create instanceID = "fxa-dialog"', function() {
var fxAccountsDialog = new window.FxAccountsDialog(fakeOptions);
assert.equal('fxa-dialog', fxAccountsDialog.instanceID);
});
});
suite('Get element', function() {
test('Return element while called getView() function', function() {
var fxAccountsDialog = new window.FxAccountsDialog(fakeOptions);
var stubGetView = this.sinon.stub(fxAccountsDialog, 'getView');
fxAccountsDialog.getView();
assert.isTrue(stubGetView.called);
});
test('Create system Firefox accounts dialog ' +
'would get dialog element.', function() {
var fxAccountsDialog = new window.FxAccountsDialog(fakeOptions);
assert.isNotNull(fxAccountsDialog.element);
});
test('Created system dialog should be hidden', function() {
var fxAccountsDialog = new window.FxAccountsDialog(fakeOptions);
assert.isTrue(fxAccountsDialog.element.hidden,
'Element is created hidden.');
});
});
suite('Resize functions', function() {
var isCalled;
setup(function(done) {
isCalled = false;
Object.defineProperty(FxAccountsDialog.prototype.containerElement.style,
'height', {
configurable: true,
set: function() {
isCalled = true;
}
});
done();
});
teardown(function() {
delete FxAccountsDialog.prototype.containerElement.style.height;
});
test('The dialog height should be updated ' +
'while "updateHeight()" called.', function() {
var fxAccountsDialog = new window.FxAccountsDialog(fakeOptions);
fxAccountsDialog.updateHeight();
assert.isTrue(isCalled);
});
test('The dialog height should be updated ' +
'while resize request is coming.', function() {
var fxAccountsDialog = new window.FxAccountsDialog(fakeOptions);
fxAccountsDialog.resize();
assert.isTrue(isCalled);
});
});
suite('Handle focus', () => {
var focusSpy;
var addUISpy;
var removeUISpy;
setup(() => {
focusSpy = sinon.spy(focusManager, 'focus');
addUISpy = sinon.spy(focusManager, 'addUI');
removeUISpy = sinon.spy(focusManager, 'removeUI');
});
teardown(() => {
focusSpy.restore();
addUISpy.restore();
removeUISpy.restore();
});
test('The created FxAccountsDialog will be added into focusManager', () => {
new FxAccountsDialog(fakeOptions);
sinon.assert.calledOnce(addUISpy);
});
test('The destroyed FxAccountsDialog will be removed from focusManager',
() => {
var fxAccountsDialog = new FxAccountsDialog(fakeOptions);
fxAccountsDialog.destroy();
sinon.assert.calledOnce(removeUISpy);
});
test('Should be able to get the "#fxa-dialog" element', () => {
var fxAccountsDialog = new FxAccountsDialog(fakeOptions);
var element = fxAccountsDialog.getElement();
assert.equal('fxa-dialog', element.id);
});
test('Should be focusable when the dialog is visible', () => {
var fxAccountsDialog = new FxAccountsDialog(fakeOptions);
fxAccountsDialog.element.classList.add('visible');
assert.isTrue(fxAccountsDialog.isFocusable());
});
test('Should not be focusable when the dialog is not visible', () => {
var fxAccountsDialog = new FxAccountsDialog(fakeOptions);
assert.isFalse(fxAccountsDialog.isFocusable());
});
test('Should remove focus when the dialog is hidden', () => {
var fxAccountsDialog = new FxAccountsDialog(fakeOptions);
fxAccountsDialog.hide();
sinon.assert.calledOnce(focusSpy);
});
test('Should focus when the dialog is shown', () => {
var fxAccountsDialog = new FxAccountsDialog(fakeOptions);
fxAccountsDialog.show();
sinon.assert.calledOnce(focusSpy);
});
});
});

View file

@ -0,0 +1,326 @@
/* global FxAccountsIACHelper, MockApp, MockAppsMgmt */
'use strict';
requireApp('system/test/unit/mock_apps_mgmt.js');
requireApp('system/test/unit/mock_app.js');
// XXX consider moving this to a separate file if it gets much more complex
// arthurcc's suggested replacement:
var port = {
postMessage: function(message) {
var msg = {
data: {
data: {},
methodName: message.name
}
};
setTimeout(function() {
port._onmessage(msg);
});
},
_onmessage: null,
set onmessage(cb) {
port._onmessage = cb;
}
};
suite('FirefoxOS Accounts IAC Client Suite', function() {
var realMozApps;
var postMessageSpy;
suiteSetup(function() {
realMozApps = navigator.mozApps;
navigator.mozApps = MockAppsMgmt;
});
suiteTeardown(function() {
navigator.mozApps = realMozApps;
});
setup(function(done) {
// For each test, setup the 'self' app, able to
// do IAC
var app = new MockApp({
'connect': function(keyword) {
var future = {
'then': function(cb) {}
};
sinon.stub(future, 'then', function(cb) {
cb([port]);
});
return future;
}
});
navigator.mozApps.setSelf(app);
// XXX we have to require() the system under test *after* we define the
// MockApp, because the code calls app.connect() as soon as it is loaded
require('/shared/js/fxa_iac_client.js', done);
});
teardown(function() {
if (postMessageSpy && postMessageSpy.restore) {
postMessageSpy.restore();
}
});
test('Library integrity', function() {
assert.isNotNull(FxAccountsIACHelper);
assert.equal(Object.keys(FxAccountsIACHelper).length, 9);
});
['getAccount', 'openFlow', 'logout'].forEach(function(method) {
suite(method + ' suite', function() {
setup(function() {
postMessageSpy = sinon.spy(port, 'postMessage');
});
test('Check that we send the ' + method + ' message', function(done) {
this.timeout(20000);
port.methodName = method;
FxAccountsIACHelper[method](
function() {
assert.ok(postMessageSpy.called);
var arg = postMessageSpy.args[0][0];
// We do have an id for this message
assert.isNotNull(arg.id);
assert.isNotNull(arg);
// Remove the id, as it's automatically generated
delete arg.id;
assert.deepEqual(arg, {
'name': method
});
done();
},
function() {
// Break if we are called.
assert.ok(false);
done();
}
);
});
teardown(function() {
postMessageSpy.restore();
});
});
});
suite('refreshAuthentication suite', function() {
setup(function() {
postMessageSpy = sinon.spy(port, 'postMessage');
});
test('Check that we send the refreshAuth message', function(done) {
this.timeout(20000);
port.methodName = 'refreshAuthentication';
FxAccountsIACHelper.refreshAuthentication('dummy@domain.org',
function() {
assert.ok(postMessageSpy.called);
var arg = postMessageSpy.args[0][0];
// We do have an id for this message
assert.isNotNull(arg.id);
assert.isNotNull(arg);
// Remove the id, as it's automatically generated
delete arg.id;
assert.deepEqual(arg, {
'name': 'refreshAuthentication',
'email': 'dummy@domain.org'
});
done();
},
function() {
// Break if we are called.
assert.ok(false);
done();
}
);
});
teardown(function() {
postMessageSpy.restore();
});
});
suite('resendVerificationEmail suite', function() {
setup(function() {
postMessageSpy = sinon.spy(port, 'postMessage');
});
test('Check that we send the resend message', function(done) {
this.timeout(20000);
port.methodName = 'resendVerificationEmail';
FxAccountsIACHelper.resendVerificationEmail('dummy@domain.org',
function() {
assert.ok(postMessageSpy.called);
var arg = postMessageSpy.args[0][0];
// We do have an id for this message
assert.isNotNull(arg.id);
assert.isNotNull(arg);
// Remove the id, as it's automatically generated
delete arg.id;
assert.deepEqual(arg, {
'name': 'resendVerificationEmail',
'email': 'dummy@domain.org'
});
done();
},
function() {
// Break if we are called.
assert.ok(false);
done();
}
);
});
teardown(function() {
postMessageSpy.restore();
});
});
suite('addEventListener tests', function() {
var callbackCalled = false;
var otherCallbackCalled = false;
var listener = function() {
callbackCalled = true;
};
var otherListener = function() {
otherCallbackCalled = true;
};
setup(function() {
FxAccountsIACHelper.addEventListener('myEvent', listener);
FxAccountsIACHelper.addEventListener('myOtherEvent', otherListener);
port._onmessage({
data: {
data: {},
eventName: 'myEvent'
}
});
});
test('Check that we trigger the appropriate callback', function() {
assert.ok(callbackCalled);
assert.ok(!otherCallbackCalled);
});
teardown(function() {
FxAccountsIACHelper.removeEventListener('myEvent', listener);
FxAccountsIACHelper.removeEventListener('myOtherEvent', otherListener);
});
});
suite('removeEventListener tests', function() {
var callbackCalled = false;
var otherCallbackCalled = false;
var listener = function() {
callbackCalled = true;
};
var otherListener = function() {
otherCallbackCalled = true;
};
setup(function() {
FxAccountsIACHelper.addEventListener('myEvent', listener);
FxAccountsIACHelper.addEventListener('myOtherEvent', otherListener);
FxAccountsIACHelper.removeEventListener('myEvent', listener);
port._onmessage({
data: {
data: {},
eventName: 'myEvent'
}
});
port._onmessage({
data: {
data: {},
eventName: 'myOtherEvent'
}
});
});
test('Check that we trigger the appropriate callback', function() {
assert.ok(!callbackCalled);
assert.ok(otherCallbackCalled);
});
});
suite('Startup race condition tests - bug 974108', function() {
var callbackCalled, otherCallbackCalled;
var listener = function() {
callbackCalled = true;
};
var otherListener = function() {
otherCallbackCalled = true;
};
setup(function() {
this.clock = sinon.useFakeTimers();
callbackCalled = false;
otherCallbackCalled = false;
// we are testing that postmessage requests are queued, not overwritten,
// during the period between starting the Helper and the port being open.
// we need to clear out the port, add 2 new subscribers, then check both
// are called.
var app = new MockApp({
'connect': function(keyword) {
var future = {
'then': function(cb) {}
};
sinon.stub(future, 'then', function(cb) {
// wait a turn so that we can queue up multiple requests
setTimeout(function() {
cb([port]);
}, 0);
});
return future;
}
});
navigator.mozApps.setSelf(app);
FxAccountsIACHelper.reset();
});
teardown(function() {
this.clock.restore();
});
test('Should queue multiple requests until port is opened', function() {
callbackCalled = false;
otherCallbackCalled = false;
// reset() will destroy the existing port, forcing message requests
// to be queued up.
FxAccountsIACHelper.reset();
// two requests -- one to be sent as soon as the connection's ready,
// the other after that.
FxAccountsIACHelper.logout(otherListener);
FxAccountsIACHelper.getAccount(listener);
this.clock.tick(1000);
assert.isTrue(callbackCalled);
assert.isTrue(otherCallbackCalled);
});
test('Should queue multiple callbacks for one request', function() {
callbackCalled = false;
otherCallbackCalled = false;
FxAccountsIACHelper.reset();
FxAccountsIACHelper.getAccount(listener);
FxAccountsIACHelper.getAccount(otherListener);
this.clock.tick(1000);
assert.isTrue(callbackCalled);
assert.isTrue(otherCallbackCalled);
});
});
});

View file

@ -0,0 +1,436 @@
/* global MockSimpleKeyNavigation, InteractiveNotifications, focusManager */
'use strict';
requireApp('smart-system/test/unit/mock_iac_handler.js');
requireApp('smart-system/test/unit/mock_simple_key_navigation.js');
requireApp('smart-system/bower_components/evt/index.js');
requireApp('smart-system/bower_components/smart-banner/script.js');
requireApp('smart-system/js/interactive_notifications.js');
suite('interactive notifications', function() {
var testTarget;
var TYPE;
var message1 = {
'text': 'message1',
'onClosed': function(){}
};
var message2 = {
'title': 'title2',
'text': 'message2',
'buttons': [{'id': 'button-1', 'label': 'button1'}],
'onClosed': function(){}
};
var message3 = {
'text': 'message3',
'onClosed': function(){}
};
var message4 = {
'text': 'message4',
'buttons': [{'id': 'button-2', 'label': 'button2'}],
'onClosed': function(){}
};
var fakeApp = {
'focus': function() {},
'getTopMostWindow': function() {
return this;
}
};
var fakeAppWinMgr = {
'getActiveApp': function() {
return fakeApp;
}
};
var stubs = {};
var fakeTimer;
var realSimpleKeyNavigation;
var realFocusManager;
var mockElements = {};
function createMockElement(options) {
var id = options.id;
var mockOpenClose = options.mockOpenClose;
var tagName = options.tagName || 'div';
var element = document.createElement(tagName);
element.id = id;
if (mockOpenClose) {
element.open = element.close = function(){};
element.on = element.once = element.off = function(){};
}
if (tagName === 'smart-banner') {
element.hide = element.flyOpen = function() {};
}
document.body.appendChild(element);
return element;
}
function createMockUI() {
// containerElement
mockElements['notification-container'] = createMockElement({
id: 'notification-container',
mockOpenClose: true,
tagName: 'smart-banner'
});
// buttonGroupElement
mockElements['notification-button-group'] =
createMockElement({id: 'notification-button-group'});
// titleElement
mockElements['notification-title'] =
createMockElement({id: 'notification-title'});
// bodyElement
mockElements['notification-body'] =
createMockElement({id: 'notification-body'});
// button1Element
mockElements['notification-button-0'] =
createMockElement({id: 'notification-button-0'});
// button2Element
mockElements['notification-button-1'] =
createMockElement({id: 'notification-button-1'});
}
// var getElementByIdStub;
suiteSetup(function() {
window.IACHandler = window.MockIACHandler;
window.AppWindowManager = fakeAppWinMgr;
realFocusManager = window.focusManager;
window.focusManager = {
focus: function() {},
addUI: function() {}
};
realSimpleKeyNavigation = window.SimpleKeyNavigation;
window.SimpleKeyNavigation = MockSimpleKeyNavigation;
createMockUI();
});
suiteTeardown(function() {
window.SimpleKeyNavigation = realSimpleKeyNavigation;
window.focusManager = realFocusManager;
mockElements = {};
});
setup(function() {
TYPE = InteractiveNotifications.TYPE;
testTarget = new InteractiveNotifications();
testTarget.start();
stubs.msg1Closed = sinon.stub(message1, 'onClosed');
stubs.msg2Closed = sinon.stub(message2, 'onClosed');
stubs.msg3Closed = sinon.stub(message3, 'onClosed');
stubs.msg4Closed = sinon.stub(message4, 'onClosed');
stubs.updateUISpy = sinon.spy(testTarget, '_updateNotificationUI');
stubs.bannerHide =
sinon.spy(mockElements['notification-container'], 'hide');
stubs.focusManagerFocus = sinon.spy(focusManager, 'focus');
fakeTimer = sinon.useFakeTimers();
});
teardown(function() {
stubs.msg1Closed.restore();
stubs.msg2Closed.restore();
stubs.msg3Closed.restore();
stubs.msg4Closed.restore();
stubs.updateUISpy.restore();
stubs.bannerHide.restore();
stubs.focusManagerFocus.restore();
fakeTimer.restore();
testTarget.stop();
});
test('show normal notification without buttons', function() {
testTarget.showNotification(TYPE.NORMAL, message1);
assert.isTrue(stubs.updateUISpy.calledWith(TYPE.NORMAL, message1));
assert.isFalse(stubs.bannerHide.called);
assert.isTrue(mockElements['notification-body'].textContent !== '');
assert.isTrue(mockElements['notification-title'].textContent === '');
fakeTimer.tick(5000);
assert.isTrue(stubs.bannerHide.calledOnce);
});
test('show normal notification with buttons', function() {
testTarget.showNotification(TYPE.NORMAL, message2);
assert.isTrue(stubs.updateUISpy.calledWith(TYPE.NORMAL, message2));
assert.isTrue(mockElements['notification-title'].titleContent !== '');
assert.isTrue(mockElements['notification-container'].classList.contains(
'has-title'));
assert.isFalse(stubs.bannerHide.called);
fakeTimer.tick(5000);
assert.isFalse(stubs.bannerHide.called);
fakeTimer.tick(3000);
assert.isTrue(stubs.bannerHide.calledOnce);
});
test('show alert notification without buttons', function() {
testTarget.showNotification(TYPE.ALERT, message1);
assert.isTrue(stubs.updateUISpy.calledWith(TYPE.ALERT, message1));
assert.isFalse(stubs.msg1Closed.called);
fakeTimer.tick(8000);
assert.isFalse(stubs.msg1Closed.called);
});
test('show alert notification with buttons', function() {
testTarget.showNotification(TYPE.ALERT, message2);
assert.isTrue(stubs.updateUISpy.calledWith(TYPE.ALERT, message2));
assert.isFalse(stubs.msg2Closed.called);
fakeTimer.tick(8000);
assert.isFalse(stubs.msg2Closed.called);
});
test('should set focus back after hideNotification()', function() {
testTarget.showNotification(TYPE.NORMAL, message1);
fakeTimer.tick(5000);
assert.isTrue(stubs.focusManagerFocus.calledOnce);
});
suite('> queue normal notification', function() {
setup(function() {
testTarget.showNotification(TYPE.NORMAL, message1);
testTarget.showNotification(TYPE.NORMAL, message3);
});
test('> close first', function() {
testTarget.hideNotification(TYPE.NORMAL, message1);
assert.isTrue(stubs.bannerHide.called);
testTarget.handleEvent({type: 'hidden'});
assert.isTrue(stubs.updateUISpy.calledWith(TYPE.NORMAL, message3));
});
test('> auto hide first', function() {
fakeTimer.tick(5000);
testTarget.handleEvent({type: 'hidden'});
assert.isTrue(stubs.msg1Closed.called);
assert.isTrue(stubs.updateUISpy.calledWith(TYPE.NORMAL, message3));
});
test('> close wrong type (alert)', function() {
testTarget.hideNotification(TYPE.ALERT, message1);
assert.isFalse(stubs.msg1Closed.called);
assert.isFalse(stubs.updateUISpy.calledWith(TYPE.NORMAL, message3));
assert.isFalse(stubs.msg3Closed.called);
});
test('> close wrong msg', function() {
testTarget.hideNotification(TYPE.NORMAL, message2);
assert.isFalse(stubs.msg1Closed.called);
assert.isFalse(stubs.updateUISpy.calledWith(TYPE.NORMAL, message3));
assert.isFalse(stubs.msg3Closed.called);
});
test('> close queued', function() {
testTarget.hideNotification(TYPE.NORMAL, message3);
assert.isTrue(stubs.msg3Closed.called);
assert.isFalse(stubs.updateUISpy.calledWith(TYPE.NORMAL, message3));
assert.isFalse(stubs.msg1Closed.called);
});
});
suite('> queue alert notification', function() {
setup(function() {
testTarget.showNotification(TYPE.ALERT, message1);
assert.isTrue(stubs.updateUISpy.calledWith(TYPE.ALERT, message1));
testTarget.showNotification(TYPE.ALERT, message3);
assert.isFalse(stubs.updateUISpy.calledWith(TYPE.ALERT, message3));
assert.isFalse(stubs.msg3Closed.called);
});
test('> close first', function() {
testTarget.hideNotification(TYPE.ALERT, message1);
testTarget.handleEvent({type: 'hidden'});
assert.isTrue(stubs.msg1Closed.called);
assert.isTrue(stubs.updateUISpy.calledWith(TYPE.ALERT, message3));
});
test('> close wrong type (normal)', function() {
testTarget.hideNotification(TYPE.NORMAL, message1);
assert.isFalse(stubs.msg1Closed.called);
assert.isFalse(stubs.updateUISpy.calledWith(TYPE.ALERT, message3));
assert.isFalse(stubs.msg3Closed.called);
});
test('> close wrong msg', function() {
testTarget.hideNotification(TYPE.ALERT, message2);
assert.isFalse(stubs.msg1Closed.called);
assert.isFalse(stubs.updateUISpy.calledWith(TYPE.ALERT, message3));
assert.isFalse(stubs.msg3Closed.called);
});
test('> close queued', function() {
testTarget.hideNotification(TYPE.ALERT, message3);
assert.isTrue(stubs.msg3Closed.called);
assert.isFalse(stubs.updateUISpy.calledWith(TYPE.ALERT, message3));
assert.isFalse(stubs.msg1Closed.called);
});
});
suite('> notification priority from low to high', function() {
setup(function() {
testTarget.showNotification(TYPE.NORMAL, message1);
assert.isTrue(stubs.updateUISpy.calledWith(TYPE.NORMAL, message1));
});
test('> show alert', function() {
testTarget.showNotification(TYPE.ALERT, message3);
testTarget.handleEvent({type: 'hidden'});
assert.isTrue(stubs.updateUISpy.calledWith(TYPE.ALERT, message3));
assert.isTrue(stubs.msg1Closed.called);
fakeTimer.tick(5000);
// recheck if onclosed is double called
assert.isTrue(stubs.msg1Closed.calledOnce);
});
test('> queue normal and show alert', function() {
// 1, 2 is normal, 3 is alert
testTarget.showNotification(TYPE.NORMAL, message2);
assert.isFalse(stubs.updateUISpy.calledWith(TYPE.NORMAL, message2));
assert.isFalse(stubs.msg1Closed.called);
testTarget.showNotification(TYPE.ALERT, message3);
testTarget.handleEvent({type: 'hidden'});
assert.isTrue(stubs.updateUISpy.calledWith(TYPE.ALERT, message3));
assert.isTrue(stubs.msg1Closed.called);
fakeTimer.tick(5000);
// recheck if onclosed is double called
assert.isTrue(stubs.msg1Closed.calledOnce);
// hide alert
testTarget.hideNotification(TYPE.ALERT, message3);
testTarget.handleEvent({type: 'hidden'});
// check queued normal
assert.isTrue(stubs.updateUISpy.calledWith(TYPE.NORMAL, message2));
assert.isTrue(stubs.msg3Closed.called);
});
});
suite('> notification priority from high to low', function() {
setup(function() {
testTarget.showNotification(TYPE.ALERT, message1);
assert.isTrue(stubs.updateUISpy.calledWith(TYPE.ALERT, message1));
});
test('> show alert', function() {
// 1 is alert, 3 is normal
testTarget.showNotification(TYPE.NORMAL, message3);
assert.isFalse(stubs.updateUISpy.calledWith(TYPE.NORMAL, message3));
assert.isFalse(stubs.msg1Closed.called);
// hide alert
testTarget.hideNotification(TYPE.ALERT, message1);
testTarget.handleEvent({type: 'hidden'});
// check queued
assert.isTrue(stubs.updateUISpy.calledWith(TYPE.NORMAL, message3));
assert.isTrue(stubs.msg1Closed.called);
});
test('> queue normal, show alert, and hide previous alert', function() {
// 2 is normal, 1, 3 is alert
// queue normal
testTarget.showNotification(TYPE.NORMAL, message2);
assert.isFalse(stubs.updateUISpy.calledWith(TYPE.NORMAL, message2));
assert.isFalse(stubs.msg1Closed.called);
// queue alert
testTarget.showNotification(TYPE.ALERT, message3);
assert.isFalse(stubs.updateUISpy.calledWith(TYPE.ALERT, message3));
assert.isFalse(stubs.msg1Closed.called);
// hide alert 1
testTarget.hideNotification(TYPE.ALERT, message1);
testTarget.handleEvent({type: 'hidden'});
assert.isTrue(stubs.updateUISpy.calledWith(TYPE.ALERT, message3));
assert.isTrue(stubs.msg1Closed.called);
// hide alert 3
testTarget.hideNotification(TYPE.ALERT, message3);
testTarget.handleEvent({type: 'hidden'});
assert.isTrue(stubs.updateUISpy.calledWith(TYPE.NORMAL, message2));
assert.isTrue(stubs.msg3Closed.called);
});
});
suite('IAC Connections', function() {
var port = {
postMessage: function(data){}
};
var portStub;
var postedData;
function sendIACMessage(id, type, message) {
var iacEvt = document.createEvent('CustomEvent');
iacEvt.initCustomEvent('iac-interactivenotifications',
/* canBubble: */ true, /* cancelable */ false, {
'id': id,
'type': type,
'message': message
});
window.dispatchEvent(iacEvt);
}
suiteSetup(function() {
window.MockIACHandler._portMap.interactivenotifications = port;
});
suiteTeardown(function() {
window.MockIACHandler.reset();
});
setup(function() {
portStub = sinon.stub(port, 'postMessage', function(data) {
postedData = data;
});
});
teardown(function() {
portStub.restore();
});
test('send normal', function() {
sendIACMessage('a', TYPE.NORMAL, message1);
assert.isTrue(stubs.updateUISpy.calledWith(TYPE.NORMAL, message1));
// auto hide
testTarget.handleEvent({type: 'hidden'});
fakeTimer.tick(5000);
assert.isTrue(portStub.calledOnce);
assert.equal('notification-closed', postedData.action);
assert.equal('a', postedData.id);
assert.equal(TYPE.NORMAL, postedData.type);
assert.isUndefined(postedData.button);
});
test('send alert', function() {
sendIACMessage('a', TYPE.ALERT, message1);
assert.isTrue(stubs.updateUISpy.calledWith(TYPE.ALERT, message1));
assert.isFalse(portStub.calledOnce);
// hide alert
testTarget.hideNotification(TYPE.ALERT, message1);
testTarget.handleEvent({type: 'hidden'});
assert.isTrue(portStub.calledOnce);
assert.equal('notification-closed', postedData.action);
assert.equal('a', postedData.id);
assert.equal(TYPE.ALERT, postedData.type);
assert.isUndefined(postedData.button);
});
test('hide normal with button', function() {
sendIACMessage('a', TYPE.NORMAL, message1);
assert.isTrue(stubs.updateUISpy.calledWith(TYPE.NORMAL, message1));
testTarget.hideNotification(TYPE.NORMAL, message1, 'buttonX');
testTarget.handleEvent({type: 'hidden'});
assert.isTrue(portStub.calledOnce);
assert.equal('notification-closed', postedData.action);
assert.equal('a', postedData.id);
assert.equal(TYPE.NORMAL, postedData.type);
assert.equal('buttonX', postedData.button);
// check auto hide
fakeTimer.tick(5000);
assert.isTrue(portStub.calledOnce);
});
});
});

View file

@ -0,0 +1,62 @@
'use strict';
var MockAppWindowManager = function() {};
MockAppWindowManager.prototype = {
isRunning: function(config) {
return (config.origin in this.mRunningApps);
},
mRunningApps: {},
// TODO: Remove this.
getRunningApps: function mawm_getRunningApps() {
return this.mRunningApps;
},
// TODO: Remove this.
getApps: function mawm_getRunningApps() {
return this.mRunningApps;
},
getActiveApp: function mawm_getActiveApp() {
return this.mActiveApp;
},
getApp: function mawm_getActiveApp(origin) {
return this.mRunningApps[origin];
},
getAppByURL: function mawm_getAppByUrl() {
return null;
},
// reference to active appWindow instance.
mActiveApp: null,
slowTransition: false,
// Switch to a different app
display: function mawm_display(origin, callback) {
this.mActiveApp = this.mRunningApps[origin];
},
kill: function mawm_kill(origin) {
this.mLastKilledOrigin = origin;
},
mTeardown: function mawm_mTeardown() {
this.mRunningApps = {};
this.mActiveApp = null;
},
broadcastMessage: function() {
},
sendStopRecordingRequest: function(callback) {
if (callback) {
callback();
}
},
start: function() {}
};

View file

@ -0,0 +1,42 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
/* exported MockasyncStorage */
var MockasyncStorage = {
mItems: {},
setItem: function(key, value, callback) {
this.mItems[key] = value;
if (typeof callback === 'function') {
callback();
}
},
getItem: function(key, callback) {
var value = this.mItems[key];
// use '|| null' will turn a 'false' to null
if (value === undefined) {
value = null;
}
if (typeof callback === 'function') {
callback(value);
}
},
removeItem: function(key, callback) {
if (key in this.mItems) {
delete this.mItems[key];
}
if (typeof callback === 'function') {
callback();
}
},
mTeardown: function() {
this.mItems = {};
}
};

View file

@ -0,0 +1,17 @@
/* exported MockfocusManager */
'use strict';
var MockfocusManager = {
addUI() {},
removeUI() {},
start() {},
stop() {},
focus() {}
};

View file

@ -0,0 +1,50 @@
'use strict';
/* exported MockFxAccountsClient */
var MockFxAccountsClient = {
_errorMsg: null,
_successMsg: null,
_call: null,
_email: null,
_reset: function() {
this._call = null;
this._errorMsg = null;
this._successMsg = null;
this._email = null;
},
_triggerCallback: function(successCb, errorCb) {
if (this._errorMsg && errorCb) {
errorCb(this._errorMsg);
return;
}
successCb && successCb(this._successMsg);
},
getAccount: function(successCb, errorCb) {
this._call = 'getAccount';
this._triggerCallback(successCb, errorCb);
},
getAssertion: function(options, successCb, errorCb) {
this._call = 'getAssertion';
if (this._errorMsg) {
errorCb(this._errorMsg);
return;
}
successCb(Date.now() /* fake assertion */);
},
resendVerificationEmail: function(email, successCb, errorCb) {
this._email = email;
this._call = 'resendVerificationEmail';
this._triggerCallback(successCb, errorCb);
},
logout: function(successCb, errorCb) {
this._call = 'logout';
this._triggerCallback(successCb, errorCb);
}
};

View file

@ -0,0 +1,17 @@
(function(exports) {
'use strict';
var MockIACHandler = {
_portMap: {},
reset: function() {
this._portMap = {};
},
getPort: function(name) {
return this._portMap[name];
}
};
exports.MockIACHandler = MockIACHandler;
}(window));

View file

@ -0,0 +1,13 @@
'use strict';
/* exported MockKeyboardManager */
var MockKeyboardManager = {
mHeight: 0,
init: function() {},
mTeardown: function() {
this.mHeight = 0;
},
_onKeyboardReady: function() {},
_onKeyboardKilled: function() {},
inputTypeTable: {}
};

View file

@ -0,0 +1,27 @@
'use strict';
(function(exports) {
var MockLayoutManager = function MockLayoutManager() {};
MockLayoutManager.prototype = {
width: window.innerWidth,
height: window.innerHeight,
mKeyboardHeight: 0,
keyboardEnabled: false,
match: function() {
return true;
},
getHeightFor: function(win, ignoreKeyboard) {
return this.height - (ignoreKeyboard ? 0 : this.mKeyboardHeight);
},
start: function() {
return this;
},
mTeardown: function mlm_mTeardown() {
this.width = window.innerWidth;
this.height = window.innerHeight;
this.keyboardEnabled = false;
this.mKeyboardHeight = 0;
}
};
exports.MockLayoutManager = MockLayoutManager;
}(window));

View file

@ -0,0 +1,12 @@
(function(exports) {
'use strict';
var MockSimpleKeyNavigation = function() {};
MockSimpleKeyNavigation.prototype = {
start: function() {},
stop: function() {},
focus: function() {}
};
exports.MockSimpleKeyNavigation = MockSimpleKeyNavigation;
}(window));

View file

@ -0,0 +1,12 @@
'use strict';
(function(exports) {
var MockSystemDialogManager = function SystemDialogManager() {};
// It should be exposed only events.
MockSystemDialogManager.prototype.handleEvent =
function() {};
exports.MockSystemDialogManager = MockSystemDialogManager;
})(window);

View file

@ -0,0 +1,3 @@
'use strict';
require('/shared/test/unit/mocks/mocks_helper.js');

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,369 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/* global Deferred */
/* global SyncStateMachine */
/* global SyncStateMachineTransitions */
'use strict';
requireApp('smart-system/test/unit/deferred.js');
requireApp('smart-system/js/sync_state_machine.js');
suite('smart-system/SyncStateMachine >', () => {
suite('Initial state', () => {
test('Integrity', () => {
assert.ok(SyncStateMachine !== undefined);
// SyncStateMachine is supposed to expose a function per transition.
for (var name in SyncStateMachineTransitions) {
if (!SyncStateMachineTransitions.hasOwnProperty(name)) {
continue;
}
assert.ok(SyncStateMachine[name] !== undefined);
assert.ok(SyncStateMachine[name] instanceof Function);
}
});
test('Initial state should be disabled', () => {
assert.equal(SyncStateMachine.state, 'disabled');
});
});
suite('Transitions invalid for state', () => {
[{
from: 'disabled',
invalidTransitions: [
'disable',
'sync',
'error',
'success'
],
transition: 'enable'
}, {
from: 'enabling',
invalidTransitions: [
'enable',
'disable',
'sync'
],
transition: 'success'
}, {
from: 'enabled',
invalidTransitions: [
'enable',
'success'
],
transition: 'sync'
}, {
from: 'syncing',
invalidTransitions: [
'enable',
'sync'
],
transition: 'error'
}, {
from: 'errored',
invalidTransitions: [
'sync',
'success',
'error'
],
transition: 'disable'
}, {
from: 'disabling',
invalidTransitions: [
'enable',
'disable',
'sync'
],
transition: 'success'
}].forEach(config => {
test(config.from + ' - invalid transitions', () => {
config.invalidTransitions.forEach(transition => {
try {
SyncStateMachine[transition]();
assert.ok(false, 'Should have thrown exception');
} catch(e) {
assert.ok(true, 'Expected exception');
assert.equal(e.message, 'Transition ' + transition +
' invalid for the current state');
assert.equal(SyncStateMachine.state, config.from);
}
});
SyncStateMachine[config.transition]();
});
});
});
suite('State transitions', () => {
// Some of the transitions are repeated so we can test all the possible
// transitions.
[{
from: 'disabled',
to: 'enabling',
transition: 'enable',
expectedEvent: 'enabling',
unexpectedEvents: [
'disabling',
'enabled',
'errored',
'disabled',
'syncing'
],
}, {
from: 'enabling',
to: 'errored',
transition: 'error',
expectedEvent: 'errored',
unexpectedEvents: [
'disabling',
'enabled',
'disabled',
'enabling',
'syncing'
]
}, {
from: 'errored',
to: 'disabling',
transition: 'disable',
expectedEvent: 'disabling',
unexpectedEvents: [
'disabled',
'enabled',
'enabling',
'errored',
'syncing'
]
}, {
from: 'disabling',
to: 'disabled',
transition: 'success',
expectedEvent: 'disabled',
unexpectedEvents: [
'enabled',
'enabling',
'errored',
'disabling',
'syncing'
]
}, {
from: 'disabled',
to: 'enabling',
transition: 'enable',
expectedEvent: 'enabling',
unexpectedEvents: [
'disabling',
'enabled',
'errored',
'disabled',
'syncing'
]
}, {
from: 'enabling',
to: 'enabled',
transition: 'success',
expectedEvent: 'enabled',
unexpectedEvents: [
'disabling',
'enabling',
'errored',
'disabled',
'syncing'
]
}, {
from: 'enabled',
to: 'syncing',
transition: 'sync',
expectedEvent: 'syncing',
unexpectedEvents: [
'disabling',
'enabled',
'enabling',
'disabled',
'errored'
]
}, {
from: 'syncing',
to: 'enabled',
transition: 'success',
expectedEvent: 'enabled',
unexpectedEvents: [
'disabling',
'disabled',
'enabling',
'errored',
'syncing'
]
}, {
from: 'enabled',
to: 'syncing',
transition: 'sync',
expectedEvent: 'syncing',
unexpectedEvents: [
'disabling',
'enabled',
'enabling',
'disabled',
'errored'
]
}, {
from: 'syncing',
to: 'disabling',
transition: 'disable',
expectedEvent: 'disabling',
unexpectedEvents: [
'disabled',
'enabled',
'errored',
'enabling',
'syncing'
]
}, {
from: 'disabling',
to: 'disabled',
transition: 'success',
expectedEvent: 'disabled',
unexpectedEvents: [
'enabled',
'enabling',
'errored',
'disabling',
'syncing'
]
}, {
from: 'disabled',
to: 'enabling',
transition: 'enable',
expectedEvent: 'enabling',
unexpectedEvents: [
'disabling',
'disabled',
'errored',
'enabled',
'syncing'
]
}, {
from: 'enabling',
to: 'enabled',
transition: 'success',
expectedEvent: 'enabled',
unexpectedEvents: [
'disabling',
'enabling',
'errored',
'disabled',
'syncing'
]
}, {
from: 'enabled',
to: 'syncing',
transition: 'sync',
expectedEvent: 'syncing',
unexpectedEvents: [
'disabling',
'enabled',
'enabling',
'disabled',
'errored'
]
}, {
from: 'syncing',
to: 'errored',
transition: 'error',
expectedEvent: 'errored',
unexpectedEvents: [
'disabling',
'enabled',
'disabled',
'enabling',
'syncing'
],
arg: 'error'
}, {
from: 'errored',
to: 'enabled',
transition: 'enable',
expectedEvent: 'enabled',
unexpectedEvents: [
'disabling',
'disabled',
'enabling',
'syncing',
'errored'
]
}, {
from: 'enabled',
to: 'disabling',
transition: 'disable',
expectedEvent: 'disabling',
unexpectedEvents: [
'disabled',
'enabled',
'enabling',
'errored',
'syncing'
]
}, {
from: 'disabling',
to: 'disabled',
transition: 'success',
expectedEvent: 'disabled',
unexpectedEvents: [
'enabled',
'enabling',
'errored',
'disabling',
'syncing'
]
}].forEach(config => {
test('Transition ' + config.transition + ' while on ' +
config.from + ' state', done => {
var promises = [];
var onexpectedDeferred = new Deferred();
promises.push(onexpectedDeferred.promise);
var onexpected = (from, transition, args) => {
assert.ok(true, 'Received expected SyncStateMachine' +
config.expectedEvent);
assert.equal(transition, config.transition);
assert.equal(from, config.from);
if (args) {
assert.equal(args, config.arg);
}
onexpectedDeferred.resolve();
};
var onunexpected = () => {
assert.ok(false, 'Received unexpected event');
cleanup();
};
function cleanup() {
config.unexpectedEvents.forEach(unexpectedEvent => {
SyncStateMachine['on' + unexpectedEvent] = null;
});
SyncStateMachine['on' + config.expectedEvent] = null;
done();
}
SyncStateMachine['on' + config.expectedEvent] = onexpected;
config.unexpectedEvents.forEach(unexpectedEvent => {
SyncStateMachine['on' + unexpectedEvent] = onunexpected;
});
promises.push(new Promise(resolve => {
SyncStateMachine[config.transition](config.arg);
assert.equal(SyncStateMachine.state, config.to);
resolve();
}));
Promise.all(promises).then(cleanup);
});
});
});
});