'use strict'; /* global MocksHelper, InputLayouts, MockKeyboardManager, MockKeyboardHelper, MockNavigatorMozSettings, MockNavigatorMozSettingsLock, MockDOMRequest */ require('/test/unit/mock_keyboard_manager.js'); require('/test/unit/mock_custom_event.js'); require('/shared/test/unit/mocks/mock_keyboard_helper.js'); require('/shared/test/unit/mocks/mock_event_target.js'); require('/shared/test/unit/mocks/mock_dom_request.js'); require('/shared/js/input_mgmt/mock_navigator_mozsettings.js'); require('/js/input_layouts.js'); var mocksForInputLayouts = new MocksHelper([ 'KeyboardHelper', 'KeyboardManager' ]).init(); suite('InputLayouts', function() { var inputLayouts; var realMozSettings; var realMozInputMethod; var setSupportsSwitchingTypesStub; var appLayouts = [{ layoutId: 'en', app: { origin: 'app://k.gaiamobile.org', manifestURL: 'app://k.gaiamobile.org/manifest.webapp' }, inputManifest: { launch_path: '/settings.html', name: 'en', types: ['text', 'number'] }, manifest: { name: 'eng' } }]; mocksForInputLayouts.attachTestHelpers(); suiteSetup(function() { realMozSettings = navigator.mozSettings; }); suiteTeardown(function() { navigator.mozSettings = realMozSettings; }); setup(function() { navigator.mozSettings = new MockNavigatorMozSettings(); inputLayouts = new InputLayouts(MockKeyboardManager, { 'text': 'textG', 'password': 'password', 'text2': 'textG' }); realMozInputMethod = navigator.mozInputMethod; setSupportsSwitchingTypesStub = this.sinon.stub(); navigator.mozInputMethod = { mgmt: { setSupportsSwitchingTypes: setSupportsSwitchingTypesStub } }; }); teardown(function() { navigator.mozInputMethod = realMozInputMethod; }); test('start() calls _getSettings', function() { var stubGetSettings = this.sinon.stub(inputLayouts, '_getSettings'); inputLayouts.start(); assert.isTrue(stubGetSettings.called); }); test('groupToTypeTable generation', function() { assert.deepEqual(inputLayouts._groupToTypeTable, { 'textG': ['text', 'text2'], 'password': ['password'] }); }); test('transformLayout', function() { var transformed = inputLayouts._transformLayout(appLayouts[0]); // don't do deepEqual 'cause getters will not match assert.equal(transformed.id, 'en'); assert.equal(transformed.origin, 'app://k.gaiamobile.org'); assert.equal(transformed.manifestURL, 'app://k.gaiamobile.org/manifest.webapp'); assert.equal(transformed.path, '/settings.html'); assert.equal(transformed.name, 'en'); assert.equal(transformed.appName, 'eng'); }); test('insertLayouts', function() { this.sinon.stub(MockKeyboardHelper, 'isKeyboardType').returns(true); var stubTransformLayout = this.sinon.stub(inputLayouts, '_transformLayout').returns('LAYOUT'); inputLayouts._enabledApps = new Set(); inputLayouts._insertLayouts(appLayouts); assert.isTrue( inputLayouts._enabledApps.has('app://k.gaiamobile.org/manifest.webapp') ); assert.isTrue('text' in inputLayouts.layouts); assert.isTrue('number' in inputLayouts.layouts); assert.isTrue(stubTransformLayout.calledWith(appLayouts[0])); assert.deepEqual(inputLayouts.layouts.text, ['LAYOUT']); assert.deepEqual(inputLayouts.layouts.number, ['LAYOUT']); }); test('insertFallbackLayouts', function() { var oldFallbackLayouts = MockKeyboardHelper.fallbackLayouts; MockKeyboardHelper.fallbackLayouts = { password: { app: { origin: 'app://keyboard.gaiamobile.org', manifestURL: 'app://keyboard.gaiamobile.org/manifest.webapp' }, layoutId: 'pwLayout', inputManifest: { launch_path: '/settings.html', name: 'pwInput' }, manifest: { name: 'pwInput' } } }; var stubTransformLayout = this.sinon.stub(inputLayouts, '_transformLayout').returns('LAYOUT'); inputLayouts._enabledApps = new Set(); inputLayouts._insertFallbackLayouts(); assert.isTrue( inputLayouts._enabledApps.has( 'app://keyboard.gaiamobile.org/manifest.webapp' ) ); assert.isTrue( stubTransformLayout.calledWith( MockKeyboardHelper.fallbackLayouts.password ) ); assert.deepEqual(inputLayouts.layouts.password, ['LAYOUT']); MockKeyboardHelper.fallbackLayouts = oldFallbackLayouts; }); test('setSupportsSwitchingTypes (w/ more than one layout enabled)', function() { inputLayouts.layouts = { 'text': ['en', 'fr', 'zh-hans'], 'password': ['en', 'fr'], 'number': [] }; var oldGroupToTypeTable = inputLayouts._groupToTypeTable; inputLayouts._groupToTypeTable = { 'text': ['text', 'textarea'], 'password': ['password'] }; inputLayouts._setSupportsSwitchingTypes(); assert.isTrue(setSupportsSwitchingTypesStub .calledWith(['text', 'textarea', 'password'])); inputLayouts._groupToTypeTable = oldGroupToTypeTable; }); test('setSupportsSwitchingTypes (w/ only one layout enabled)', function() { inputLayouts.layouts = { 'text': ['en'], 'password': ['en'], 'number': [] }; var oldGroupToTypeTable = inputLayouts._groupToTypeTable; inputLayouts._groupToTypeTable = { 'text': ['text', 'textarea'], 'password': ['password'] }; inputLayouts._setSupportsSwitchingTypes(); assert.isTrue(setSupportsSwitchingTypesStub .calledWith([])); inputLayouts._groupToTypeTable = oldGroupToTypeTable; }); test('generateToGroupMapping', function() { inputLayouts.layouts = { 'text': [ { manifestURL: 'app://k.gaiamobile.org/manifest.webapp', id: 'en' }, { manifestURL: 'app://k.gaiamobile.org/manifest.webapp', id: 'fr' }, { manifestURL: 'app://k.gaiamobile.org/manifest.webapp', id: 'es' } ], 'number': [ { manifestURL: 'app://k.gaiamobile.org/manifest.webapp', id: 'en' }, { manifestURL: 'app://k.gaiamobile.org/manifest.webapp', id: 'es' }, { manifestURL: 'app://k.gaiamobile.org/manifest.webapp', id: 'pt' }, { manifestURL: 'app://k2.gaiamobile.org/manifest.webapp', id: 'romanNumerial' } ] }; inputLayouts._generateToGroupMapping(); assert.deepEqual(inputLayouts._layoutToGroupMapping, { 'app://k.gaiamobile.org/manifest.webapp/en': [ {group: 'text', index: 0}, {group: 'number', index: 0} ], 'app://k.gaiamobile.org/manifest.webapp/fr': [ {group: 'text', index: 1} ], 'app://k.gaiamobile.org/manifest.webapp/es': [ {group: 'text', index: 2}, {group: 'number', index: 1} ], 'app://k.gaiamobile.org/manifest.webapp/pt': [ {group: 'number', index: 2} ], 'app://k2.gaiamobile.org/manifest.webapp/romanNumerial': [ {group: 'number', index: 3} ] }); }); // we're not testing layouts[group]._activeLayoutIdx here as it's being tested // (in an integrated sense) in KeyboardManager's "Try using the same layout // when switching input types" test test('saveGroupsCurrentActiveLayout', function() { inputLayouts._layoutToGroupMapping = { 'app://k.gaiamobile.org/manifest.webapp/en': [ {group: 'text', index: 12}, {group: 'number', index: 34} ] }; inputLayouts.layouts = { 'text': [], 'number': [] }; inputLayouts._currentActiveLayouts = {}; inputLayouts.layouts.text[12] = 'en'; inputLayouts.layouts.number[34] = 'en'; var stubMockNavigatorMozSettingsLock = this.sinon.stub(MockNavigatorMozSettingsLock.prototype); stubMockNavigatorMozSettingsLock.set.returns(new MockDOMRequest()); inputLayouts.saveGroupsCurrentActiveLayout({ manifestURL: 'app://k.gaiamobile.org/manifest.webapp', id: 'en' }); assert.equal(inputLayouts.layouts.text._activeLayoutIdx, 12, '"text" activeLayout was not changed'); assert.equal(inputLayouts.layouts.number._activeLayoutIdx, 34, '"number" activeLayout was not changed'); assert.isTrue(stubMockNavigatorMozSettingsLock.set.calledWith( { 'keyboard.current-active-layouts': { text: { manifestURL: 'app://k.gaiamobile.org/manifest.webapp', id: 'en' }, number: { manifestURL: 'app://k.gaiamobile.org/manifest.webapp', id: 'en' } } } )); }); test('processLayouts', function() { var stubInsertLayouts = this.sinon.stub(inputLayouts, '_insertLayouts', function() { inputLayouts.layouts = { text: ['en'], password: ['en'] }; inputLayouts._enabledApps.add('app://k.gaiamobile.org/manifest.webapp'); }); var stubInsertFallbacklayouts = this.sinon.stub(inputLayouts, '_insertFallbackLayouts'); var emitLayoutsCountStub = this.sinon.stub(inputLayouts, '_setSupportsSwitchingTypes'); var enabledApps = inputLayouts.processLayouts(appLayouts); assert.isTrue(stubInsertLayouts.calledWith(appLayouts)); assert.isTrue(stubInsertFallbacklayouts.called); assert.isTrue( Object.keys(inputLayouts.layouts).every( group => inputLayouts.layouts[group]._activeLayoutIdx === undefined ) ); assert.isTrue(emitLayoutsCountStub.called); assert.isTrue(enabledApps.has('app://k.gaiamobile.org/manifest.webapp')); assert.equal(enabledApps.size, 1); }); suite('getGroupCurrentActiveLayoutIndexAsync', function() { test('success route null', function(done) { // we test three things in this test: // 1. when _promise = null, if everything is good; // 2. when _promise already has something (subsequent to 1), // 2a. and resolves to some known layout // 2b. and resolves to some unknown layout // 2a and 2b are what KeyboardManager test used to test. inputLayouts.layouts = { text: [ { id: 'fr', manifestURL: 'app://k.gaiamobile.org/manifest.webapp' }, { id: 'en', manifestURL: 'app://k.gaiamobile.org/manifest.webapp' } ] }; var stubMockNavigatorMozSettingsLock = this.sinon.stub(MockNavigatorMozSettingsLock.prototype); var step1 = function(){ inputLayouts._promise = null; var req = new MockDOMRequest(); stubMockNavigatorMozSettingsLock.get.returns(req); var p = inputLayouts.getGroupCurrentActiveLayoutIndexAsync('text'); assert.equal(stubMockNavigatorMozSettingsLock.get.callCount, 1); assert.isTrue( stubMockNavigatorMozSettingsLock.get .calledWith('keyboard.current-active-layouts') ); req.fireSuccess({ 'keyboard.current-active-layouts': { text: { id: 'en', manifestURL: 'app://k.gaiamobile.org/manifest.webapp' } } }); p.then(step2); }; var step2 = function(){ assert.notStrictEqual(inputLayouts._promise, null); var p = inputLayouts.getGroupCurrentActiveLayoutIndexAsync('text'); // get should not be called again assert.equal(stubMockNavigatorMozSettingsLock.get.callCount, 1); p.then(currentActiveLayoutsIdx => { assert.equal(currentActiveLayoutsIdx, 1); step3(); }); }; var step3 = function(){ assert.notStrictEqual(inputLayouts._promise, null); var p = inputLayouts.getGroupCurrentActiveLayoutIndexAsync('number'); // get should not be called again assert.equal(stubMockNavigatorMozSettingsLock.get.callCount, 1); p.then(currentActiveLayoutsIdx => { assert.strictEqual(currentActiveLayoutsIdx, undefined); done(); }); }; step1(); }); test('_getSettings throws and resets _promise on error', function(done) { var stubMockNavigatorMozSettingsLock = this.sinon.stub(MockNavigatorMozSettingsLock.prototype); inputLayouts._promise = null; var req = new MockDOMRequest(); stubMockNavigatorMozSettingsLock.get.returns(req); var p = inputLayouts.getGroupCurrentActiveLayoutIndexAsync('text'); assert.notStrictEqual(inputLayouts._promise, null); // we want to catch that throw to not disrupt test flow p.catch(e => { assert.equal(e, 'error!'); assert.strictEqual(inputLayouts._promise, null); done(); }); req.fireError('error!'); }); }); });