VulpesOS/gaia/apps/system/test/unit/input_window_test.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

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