Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
392 lines
11 KiB
JavaScript
Executable file
392 lines
11 KiB
JavaScript
Executable file
'use strict';
|
|
|
|
/* globals InputWindow, AppWindow */
|
|
|
|
require('/shared/test/unit/mocks/mock_service.js');
|
|
require('/shared/test/unit/mocks/mock_manifest_helper.js');
|
|
requireApp('system/test/unit/mock_app_transition_controller.js');
|
|
|
|
require('/js/browser_frame.js');
|
|
require('/js/app_window.js');
|
|
require('/js/browser_mixin.js');
|
|
require('/js/input_window.js');
|
|
|
|
var mocksForInputWindow = new window.MocksHelper([
|
|
'ManifestHelper', 'Service', 'AppTransitionController'
|
|
]).init();
|
|
|
|
suite('system/InputWindow', function() {
|
|
mocksForInputWindow.attachTestHelpers();
|
|
|
|
var app;
|
|
var keyboardContainer;
|
|
|
|
setup(function() {
|
|
keyboardContainer = document.createElement('div');
|
|
keyboardContainer.id = 'keyboards';
|
|
document.body.appendChild(keyboardContainer);
|
|
this.sinon.stub(document, 'getElementById', function(id) {
|
|
if (id === 'keyboards') {
|
|
return keyboardContainer;
|
|
} else {
|
|
return document.createElement('div');
|
|
}
|
|
});
|
|
|
|
app = new InputWindow({
|
|
manifest: {},
|
|
manifestURL: 'app://keyboard.gaiamobile.org/manifestURL.webapp',
|
|
origin: 'app://keyboard.gaiamobile.org',
|
|
path: '/index.html#ime1',
|
|
id: 'ime1'
|
|
});
|
|
});
|
|
|
|
teardown(function() {
|
|
document.body.removeChild(keyboardContainer);
|
|
});
|
|
|
|
test('Constructor', function() {
|
|
assert.isTrue(app.isInputMethod);
|
|
assert.equal(app.url, 'app://keyboard.gaiamobile.org/index.html#ime1');
|
|
|
|
assert.equal(app.browser.element.dataset.frameName, 'ime1');
|
|
});
|
|
|
|
suite('Event handlings', function() {
|
|
suite('mozbrowserresize', function() {
|
|
var stubPublish ;
|
|
var stubSetHeight;
|
|
|
|
setup(function(){
|
|
// this attaches mozbrowserresize listener
|
|
app._setAsActiveInput(true);
|
|
|
|
stubPublish = this.sinon.stub(app, 'publish');
|
|
stubSetHeight = this.sinon.stub(app, '_setHeight');
|
|
});
|
|
|
|
teardown(function(){
|
|
app._setAsActiveInput(false);
|
|
});
|
|
|
|
var triggerEvent = function (){
|
|
var evt = new CustomEvent('mozbrowserresize', {
|
|
detail: {
|
|
height: 200
|
|
}
|
|
});
|
|
|
|
sinon.spy(evt, 'stopPropagation');
|
|
|
|
app.browser.element.dispatchEvent(evt);
|
|
|
|
return evt;
|
|
};
|
|
|
|
test('transitionstate-invariant part', function() {
|
|
var evt = triggerEvent();
|
|
assert.isTrue(stubSetHeight.calledWith(200));
|
|
assert.isTrue(stubPublish.calledWith('ready'));
|
|
assert.isTrue(evt.stopPropagation.called);
|
|
});
|
|
|
|
test('transitionstate is opened', function() {
|
|
app.transitionController._transitionState = 'opened';
|
|
|
|
triggerEvent();
|
|
|
|
assert.isTrue(
|
|
stubPublish.calledWith('heightchanged'),
|
|
'heightchanged should be published when transitionState is opened'
|
|
);
|
|
});
|
|
|
|
// these states should not trigger heightchanged
|
|
var otherStates = ['opening', 'closing', 'closed'];
|
|
|
|
otherStates.forEach(state => {
|
|
test('transitionstate is ' + state, function() {
|
|
app.transitionController._transitionState = state;
|
|
|
|
triggerEvent();
|
|
|
|
assert.isFalse(
|
|
stubPublish.calledWith('heightchanged'),
|
|
`heightchanged should not be published
|
|
when transitionState is ${state}`
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
suite('_ready', function() {
|
|
var stubSetHeight;
|
|
var stubOpen;
|
|
|
|
setup(function(){
|
|
app.element.addEventListener('_ready', app);
|
|
app.height = 300;
|
|
app._pendingReady = true;
|
|
|
|
stubSetHeight = this.sinon.stub(app, '_setHeight');
|
|
stubOpen = this.sinon.stub(AppWindow.prototype, 'open');
|
|
});
|
|
|
|
test('handler', function() {
|
|
app.publish('ready');
|
|
|
|
assert.isTrue(stubSetHeight.calledWith(300));
|
|
assert.isTrue(stubOpen.calledOn(app),
|
|
'should call superclass open');
|
|
assert.isFalse(app._pendingReady, 'should reset _pendingReady');
|
|
});
|
|
|
|
test('immediateOpen = true', function() {
|
|
app.immediateOpen = true;
|
|
app.publish('ready');
|
|
|
|
assert.isTrue(stubOpen.calledWith('immediate'),
|
|
'open should be called with immediate');
|
|
});
|
|
|
|
test('immediateOpen = false', function() {
|
|
app.immediateOpen = false;
|
|
app.publish('ready');
|
|
|
|
assert.isFalse(stubOpen.calledWith('immediate'),
|
|
'open should not be called with immediate');
|
|
});
|
|
|
|
test('should not be able to triggered twice', function() {
|
|
app.publish('ready');
|
|
|
|
app.publish('ready');
|
|
|
|
assert.isFalse(stubSetHeight.calledTwice);
|
|
assert.isFalse(stubOpen.calledTwice);
|
|
});
|
|
});
|
|
});
|
|
|
|
suite('setHeight()', function() {
|
|
var oldDevicePixelRatio;
|
|
|
|
suiteSetup(function() {
|
|
oldDevicePixelRatio = window.devicePixelRatio;
|
|
|
|
Object.defineProperty(window, 'devicePixelRatio', {
|
|
get: function() {
|
|
return 2.5;
|
|
},
|
|
configurable: true
|
|
});
|
|
});
|
|
|
|
suiteTeardown(function() {
|
|
Object.defineProperty(window, 'devicePixelRatio', {
|
|
get: function() {
|
|
return oldDevicePixelRatio;
|
|
},
|
|
configurable: true
|
|
});
|
|
});
|
|
|
|
test('without rounding', function () {
|
|
app._setHeight(20);
|
|
assert.equal(app.height, 20);
|
|
});
|
|
|
|
test('with rounding', function () {
|
|
app._setHeight(25);
|
|
|
|
// with the round calculation the resulting height should be closed to
|
|
// 24.8, whose dpx should be one px less than ceil(25*dpx).
|
|
assert.isTrue(
|
|
Math.abs(app.height - 24.8) < Number.EPSILON
|
|
);
|
|
});
|
|
});
|
|
|
|
suite('setAsActiveInput', function() {
|
|
var stubSetVisible;
|
|
var stubSetInputMethodActive;
|
|
setup(function(){
|
|
stubSetVisible = this.sinon.stub(app, 'setVisible');
|
|
// perhaps the iframe (or any browser element) doesn't have
|
|
// setInputMethodActive, so we need to add it
|
|
if (app.browser.element.setInputMethodActive) {
|
|
stubSetInputMethodActive =
|
|
this.sinon.stub(app.browser.element, 'setInputMethodActive');
|
|
} else {
|
|
stubSetInputMethodActive =
|
|
app.browser.element.setInputMethodActive = this.sinon.stub();
|
|
}
|
|
|
|
app.height = 123;
|
|
});
|
|
|
|
test('active = true', function() {
|
|
var stubClassListAdd = this.sinon.stub(app.element.classList, 'add');
|
|
var stubAddEventListener =
|
|
this.sinon.stub(app.browser.element, 'addEventListener');
|
|
|
|
app._setAsActiveInput(true);
|
|
|
|
assert.isTrue(stubSetVisible.calledWith(true));
|
|
assert.isTrue(stubSetInputMethodActive.calledWith(true));
|
|
assert.isTrue(stubClassListAdd.calledWith('top-most'));
|
|
assert.isTrue(
|
|
stubAddEventListener.calledWith('mozbrowserresize', app, true)
|
|
);
|
|
|
|
assert.equal(app.height, 123);
|
|
});
|
|
|
|
test('active = false', function() {
|
|
var stubClassListRemove =
|
|
this.sinon.stub(app.element.classList, 'remove');
|
|
var stubRemoveEventListener =
|
|
this.sinon.stub(app.browser.element, 'removeEventListener');
|
|
|
|
app._setAsActiveInput(false);
|
|
|
|
assert.isTrue(stubSetVisible.calledWith(false));
|
|
assert.isTrue(stubSetInputMethodActive.calledWith(false));
|
|
assert.isTrue(stubClassListRemove.calledWith('top-most'));
|
|
assert.isTrue(
|
|
stubRemoveEventListener.calledWith('mozbrowserresize', app, true)
|
|
);
|
|
|
|
assert.strictEqual(app.height, 0);
|
|
});
|
|
});
|
|
|
|
test('close', function() {
|
|
var stubRemoveEventListener =
|
|
this.sinon.stub(app.element, 'removeEventListener');
|
|
var stubClose = this.sinon.stub(AppWindow.prototype, 'close');
|
|
|
|
app.close('immediate');
|
|
|
|
assert.isTrue(stubRemoveEventListener.calledWith('_ready'), app);
|
|
assert.isTrue(stubClose.calledOn(app), 'should call superclass open');
|
|
assert.isTrue(stubClose.calledWith('immediate'));
|
|
|
|
stubClose.reset();
|
|
|
|
app.close();
|
|
|
|
assert.isFalse(stubClose.calledWith('immediate'));
|
|
});
|
|
|
|
suite('open', function() {
|
|
setup(function() {
|
|
app.hash = '#ime1';
|
|
app.pathInitial = '/index.html';
|
|
});
|
|
|
|
test('should set _pendingReady', function() {
|
|
app._pendingReady = false;
|
|
|
|
app.open({
|
|
hash: '#ime1',
|
|
immediateOpen: false
|
|
});
|
|
|
|
assert.isTrue(app._pendingReady);
|
|
});
|
|
|
|
test('hash changed', function() {
|
|
app.immediateOpen = true;
|
|
|
|
var configs = {
|
|
id: 'ime2',
|
|
hash: '#ime2',
|
|
immediateOpen: false
|
|
};
|
|
|
|
var stubReadyHandler = this.sinon.stub(app, '_handle__ready');
|
|
var stubSetAsActiveInput = this.sinon.stub(app, '_setAsActiveInput');
|
|
|
|
app.open(configs);
|
|
|
|
assert.equal(app.browser.element.src,
|
|
'app://keyboard.gaiamobile.org/index.html#ime2');
|
|
assert.equal(app.browser.element.dataset.frameName, 'ime2');
|
|
assert.isFalse(app.immediateOpen);
|
|
assert.isTrue(stubSetAsActiveInput.calledWith(true));
|
|
|
|
app.publish('ready');
|
|
assert.isTrue(stubReadyHandler.called);
|
|
});
|
|
|
|
suite('hash not changed', function() {
|
|
var stubReadyHandler;
|
|
var configs = {
|
|
hash: '#ime1',
|
|
immediateOpen: false
|
|
};
|
|
|
|
setup(function() {
|
|
stubReadyHandler = this.sinon.stub(app, '_handle__ready');
|
|
this.sinon.stub(app, '_setAsActiveInput');
|
|
|
|
app.immediateOpen = false;
|
|
});
|
|
|
|
test('transitionState is closing', function() {
|
|
app.transitionController._transitionState = 'closing';
|
|
|
|
app.open(configs);
|
|
|
|
assert.isTrue(
|
|
app.immediateOpen,
|
|
'immediateOpen should be true if hash not changed and state = closing'
|
|
);
|
|
assert.isTrue(
|
|
stubReadyHandler.called,
|
|
`ready should be automatically triggered if hash not changed
|
|
and state = closing`
|
|
);
|
|
});
|
|
|
|
// these states should not immediateOpen + trigger ready event
|
|
var otherStates = ['opening', 'opened', 'closed'];
|
|
|
|
otherStates.forEach(state => {
|
|
test('transitionState is ' + state, function() {
|
|
app.transitionController._transitionState = state;
|
|
|
|
app.open(configs);
|
|
|
|
assert.isFalse(
|
|
app.immediateOpen,
|
|
`immediateOpen should be false if hash not changed
|
|
and state = ${state}`
|
|
);
|
|
|
|
assert.isFalse(
|
|
stubReadyHandler.called,
|
|
`ready should not be automatically triggered if hash not changed
|
|
and state = ${state}`
|
|
);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
test('should not set/lock orientation', function() {
|
|
var stubLockOrientation =
|
|
this.sinon.stub(AppWindow.prototype, 'lockOrientation');
|
|
var stubSetOrientation =
|
|
this.sinon.stub(AppWindow.prototype, 'setOrientation');
|
|
|
|
app.lockOrientation();
|
|
|
|
app.setOrientation();
|
|
|
|
assert.isFalse(stubLockOrientation.called);
|
|
assert.isFalse(stubSetOrientation.called);
|
|
});
|
|
});
|