VulpesOS/gaia/apps/keyboard/test/build/integration/keyboard_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

437 lines
15 KiB
JavaScript
Executable file

'use strict';
/* jshint node: true, mocha: true */
/* global suiteSetup */
var assert = require('chai').assert;
var path = require('path');
var fs = require('fs');
var helper = require('helper');
var AdmZip = require('adm-zip');
var jsdom = require('jsdom').jsdom;
function checkLayoutsJSON(zipPath, expectedArr) {
var zip = new AdmZip(zipPath);
var entry = zip.getEntry('js/settings/layouts.json');
var actualArr = JSON.parse(zip.readAsText(entry));
actualArr.forEach(function(layout) {
assert.isTrue(
!!layout.dictFileSize,
'Expect layout contain to non-zero dictFileSize, id=' + layout.id);
delete layout.dictFileSize;
});
expectedArr.forEach(function(layout) {
delete layout.dictFileSize;
});
assert.deepEqual(actualArr, expectedArr);
}
suite('Keyboard layouts building tests', function() {
suiteSetup(helper.cleanupWorkspace);
teardown(helper.cleanupWorkspace);
// default make -- build with selected layouts and dictionaries
test('APP=keyboard make', function(done) {
var cmd = 'APP=keyboard make';
helper.exec(cmd, function(error, stdout, stderr) {
helper.checkError(error, stdout, stderr);
var config = JSON.parse(process.env.BUILD_CONFIG);
var layoutIds = ['ar',
'bn-Avro',
'bn-Probhat',
'de',
'de-Neo',
'dz-BT',
'en',
'en-Colemak',
'en-Dvorak',
'en-Neo',
'eo',
'es',
'es-Americas',
'fa',
'fr',
'fr-CA',
'fr-CH',
'fr-Dvorak-bepo',
'he',
'hi',
'ig',
'ko',
'mk',
'my',
'pl',
'pt-BR',
'ta',
'te',
'th',
'uk',
'vi-Qwerty',
'vi-Telex',
'vi-Typewriter',
'wo',
'zh-Hans-Pinyin'];
var zipPath = path.join(process.cwd(), 'profile',
'webapps', 'keyboard.gaiamobile.org', 'application.zip');
var appDirPath = config.GAIA_DIR + '/apps/keyboard';
var layouts = layoutIds.map(function(layout) {
return 'js/layouts/' + layout + '.js';
});
// Unfortunately we can only whilelist files here because we shouldn't
// throw error if excluded files are missing (e.g. README).
var imes = [
'js/imes/jshangul/jshangul.js',
'js/imes/jspinyin/empinyin_files.data',
'js/imes/jspinyin/empinyin_files.js',
'js/imes/jspinyin/jspinyin.js',
'js/imes/jspinyin/libpinyin.js',
'js/imes/jspinyin/worker.js',
'js/imes/latin/latin.js',
'js/imes/latin/predictions.js',
'js/imes/latin/worker.js'
];
var dicts = [
'js/imes/latin/dictionaries/de.dict',
'js/imes/latin/dictionaries/en_us.dict',
'js/imes/latin/dictionaries/es.dict',
'js/imes/latin/dictionaries/fr.dict',
'js/imes/latin/dictionaries/pl.dict',
'js/imes/latin/dictionaries/pt_br.dict'
];
var checkList = [].concat(layouts, imes, dicts);
checkList.forEach(function(path) {
helper.checkFileInZip(zipPath, path, appDirPath + '/' + path);
});
// Verify inputs entry in manifest
var zip = new AdmZip(zipPath);
var entry = zip.getEntry('manifest.webapp');
var manifest = JSON.parse(zip.readAsText(entry));
var inputKeysInManifest = Object.keys(manifest.inputs);
assert.deepEqual(inputKeysInManifest.sort(),
[].concat(layoutIds, 'number', 'emoji').sort());
// Verify dictionary config
var dictJSON = JSON.parse(fs.readFileSync(
appDirPath +
'/test/build/integration/resources/' +
'default-make-layouts.json'));
checkLayoutsJSON(zipPath, dictJSON);
done();
});
});
// Build with all layouts and dictionaries
test('APP=keyboard GAIA_KEYBOARD_LAYOUTS=* make', function(done) {
var cmd = 'APP=keyboard GAIA_KEYBOARD_LAYOUTS=* make';
helper.exec(cmd, function(error, stdout, stderr) {
helper.checkError(error, stdout, stderr);
var config = JSON.parse(process.env.BUILD_CONFIG);
var zipPath = path.join(process.cwd(), 'profile',
'webapps', 'keyboard.gaiamobile.org', 'application.zip');
var appDirPath = config.GAIA_DIR + '/apps/keyboard';
var layoutIds =
fs.readdirSync(appDirPath + '/js/layouts').filter(function(filename) {
return (path.extname(filename) === '.js');
}).map(function(filename) {
return path.basename(filename, '.js');
}).filter(function(layoutId) {
// Exclude noIncludeInExpandLayoutIdSet layouts
return (['emoji'].indexOf(layoutId) === -1);
});
var layouts = layoutIds.map(function(layout) {
return 'js/layouts/' + layout + '.js';
});
// Unfortunately we can only whilelist files here because we shouldn't
// throw error if excluded files are missing (e.g. README).
// For the sake of simplicity let's only check the main scripts.
var imes = [
'js/imes/handwriting/handwriting.js',
'js/imes/india/india.js',
'js/imes/jshangul/jshangul.js',
'js/imes/jskanji/jskanji.js',
'js/imes/jspinyin/jspinyin.js',
'js/imes/latin/latin.js',
'js/imes/vietnamese/vietnamese.js',
'js/imes/myanmar/myanmar.js'
];
var dicts = [
'js/imes/latin/dictionaries/bg.dict',
'js/imes/latin/dictionaries/bs.dict',
'js/imes/latin/dictionaries/ca.dict',
'js/imes/latin/dictionaries/cs.dict',
'js/imes/latin/dictionaries/da.dict',
'js/imes/latin/dictionaries/de.dict',
'js/imes/latin/dictionaries/el.dict',
'js/imes/latin/dictionaries/en_gb.dict',
'js/imes/latin/dictionaries/en_us.dict',
'js/imes/latin/dictionaries/es.dict',
'js/imes/latin/dictionaries/eu.dict',
'js/imes/latin/dictionaries/fr.dict',
'js/imes/latin/dictionaries/ga.dict',
'js/imes/latin/dictionaries/gd.dict',
'js/imes/latin/dictionaries/gl.dict',
'js/imes/latin/dictionaries/gv.dict',
'js/imes/latin/dictionaries/hr.dict',
'js/imes/latin/dictionaries/hu.dict',
'js/imes/latin/dictionaries/it.dict',
'js/imes/latin/dictionaries/lt.dict',
'js/imes/latin/dictionaries/lv.dict',
'js/imes/latin/dictionaries/nb.dict',
'js/imes/latin/dictionaries/nl.dict',
'js/imes/latin/dictionaries/pl.dict',
'js/imes/latin/dictionaries/pt_br.dict',
'js/imes/latin/dictionaries/pt_pt.dict',
'js/imes/latin/dictionaries/ro.dict',
'js/imes/latin/dictionaries/ru.dict',
'js/imes/latin/dictionaries/sk.dict',
'js/imes/latin/dictionaries/sq.dict',
'js/imes/latin/dictionaries/sr-Cyrl.dict',
'js/imes/latin/dictionaries/sr-Latn.dict',
'js/imes/latin/dictionaries/sv.dict',
'js/imes/latin/dictionaries/tr.dict',
'js/imes/latin/dictionaries/af.dict'
];
var checkList = [].concat(layouts, imes, dicts);
checkList.forEach(function(path) {
helper.checkFileInZip(zipPath, path, appDirPath + '/' + path);
});
// Verify inputs entry in manifest
var zip = new AdmZip(zipPath);
var entry = zip.getEntry('manifest.webapp');
var manifest = JSON.parse(zip.readAsText(entry));
var inputKeysInManifest = Object.keys(manifest.inputs);
assert.deepEqual(inputKeysInManifest.sort(),
[].concat(layoutIds, 'number', 'emoji').sort());
// Verify dictionary config
var dictJSON = JSON.parse(fs.readFileSync(
appDirPath +
'/test/build/integration/resources/' +
'all-layout-make-layouts.json'));
checkLayoutsJSON(zipPath, dictJSON);
done();
});
});
// Build with all layouts with no dictionaries
// (preload ko layout here to avoid empty check.)
test('APP=keyboard GAIA_KEYBOARD_LAYOUTS=ko ' +
'GAIA_KEYBOARD_DOWNLOADABLE_LAYOUTS=noPreloadDictRequired make',
function(done) {
var cmd = 'APP=keyboard GAIA_KEYBOARD_LAYOUTS=ko ' +
'GAIA_KEYBOARD_DOWNLOADABLE_LAYOUTS=noPreloadDictRequired make';
helper.exec(cmd, function(error, stdout, stderr) {
helper.checkError(error, stdout, stderr);
var config = JSON.parse(process.env.BUILD_CONFIG);
var zipPath = path.join(process.cwd(), 'profile',
'webapps', 'keyboard.gaiamobile.org', 'application.zip');
var appDirPath = config.GAIA_DIR + '/apps/keyboard';
// For this test, we verify there isn't any dictionary
// in the zip.
var zip = new AdmZip(zipPath);
var entries = zip.getEntries();
var imePath = 'js/imes';
var sizeLimit = (1 << 10) * 100; // 100K
entries.forEach(function(entry) {
if (entry.entryName.substr(0, imePath.length) !== imePath) {
return;
}
var fileSize = entry.getData().length;
assert.isTrue(fileSize < sizeLimit,
'IME file is larger than non-dictionary limit: ' + entry.entryName +
', size: ' + fileSize + ' bytes.');
});
// Verify dictionary config
var dictJSON = JSON.parse(fs.readFileSync(
appDirPath +
'/test/build/integration/resources/' +
'no-preload-dict-required-make-layouts.json'));
checkLayoutsJSON(zipPath, dictJSON);
done();
});
});
// Build default layouts with only en dictionary, and extra IMEs
test('APP=keyboard GAIA_KEYBOARD_LAYOUTS=en ' +
'GAIA_KEYBOARD_DOWNLOADABLE_LAYOUTS=' +
'en,pt-BR,es,de,fr,fr-CA,pl,ko,zh-Hans-Pinyin,en-Dvorak make',
function(done) {
var cmd = 'APP=keyboard GAIA_KEYBOARD_LAYOUTS=en ' +
'GAIA_KEYBOARD_DOWNLOADABLE_LAYOUTS=' +
'en,pt-BR,es,de,fr,fr-CA,pl,ko,zh-Hans-Pinyin,en-Dvorak make';
helper.exec(cmd, function(error, stdout, stderr) {
helper.checkError(error, stdout, stderr);
var config = JSON.parse(process.env.BUILD_CONFIG);
var zipPath = path.join(process.cwd(), 'profile',
'webapps', 'keyboard.gaiamobile.org', 'application.zip');
var appDirPath = config.GAIA_DIR + '/apps/keyboard';
var layoutIds = config.GAIA_KEYBOARD_LAYOUTS.split(',').sort()
.filter(function(layoutId) {
// Exclude noIncludeInExpandLayoutIdSet layouts
return (['emoji'].indexOf(layoutId) === -1);
});
var layouts = layoutIds.map(function(layout) {
return 'js/layouts/' + layout + '.js';
});
// Unfortunately we can only whilelist files here because we shouldn't
// throw error if excluded files are missing (e.g. README).
var imes = [
'js/imes/jshangul/jshangul.js',
'js/imes/jspinyin/empinyin_files.data',
'js/imes/jspinyin/empinyin_files.js',
'js/imes/jspinyin/jspinyin.js',
'js/imes/jspinyin/libpinyin.js',
'js/imes/jspinyin/worker.js',
'js/imes/latin/latin.js',
'js/imes/latin/predictions.js',
'js/imes/latin/worker.js'
];
var dicts = [
'js/imes/latin/dictionaries/es.dict',
'js/imes/latin/dictionaries/fr.dict',
'js/imes/latin/dictionaries/pl.dict',
'js/imes/latin/dictionaries/pt_br.dict'
];
var checkList = [].concat(layouts, imes);
checkList.forEach(function(path) {
helper.checkFileInZip(zipPath, path, appDirPath + '/' + path);
});
// Verify inputs entry in manifest
var zip = new AdmZip(zipPath);
var entry = zip.getEntry('manifest.webapp');
var manifest = JSON.parse(zip.readAsText(entry));
var inputKeysInManifest = Object.keys(manifest.inputs);
// Only layouts with dictionaries should be declaried.
// Noted that en-Dvorak use the same dictionary as en so it should also
// be declaried.
assert.deepEqual(inputKeysInManifest.sort(),
['en', 'en-Dvorak', 'ko', 'number', 'zh-Hans-Pinyin']);
// Verify dictionaries are not built (except en_us.dict)
dicts.forEach(function(dict) {
var entry = zip.getEntry(dict);
assert.equal(entry, null, 'Dictionary should not be built: ' + dict);
});
// Verify dictionary config
var dictJSON = JSON.parse(fs.readFileSync(
appDirPath +
'/test/build/integration/resources/' +
'default-make-en-dict-layouts.json'));
checkLayoutsJSON(zipPath, dictJSON);
done();
});
});
});
suite('Keyboard settings building tests', function() {
suiteSetup(helper.cleanupWorkspace);
teardown(helper.cleanupWorkspace);
// parse settings.html and return domDoc.
var getSettingsDomDoc = function() {
var zipPath = path.join(process.cwd(), 'profile',
'webapps', 'keyboard.gaiamobile.org', 'application.zip');
// Verify settings.html content in manifest
var zip = new AdmZip(zipPath);
var entry = zip.getEntry('settings.html');
return jsdom(zip.readAsText(entry));
};
// return an array of <scripts> tag in <head>
var getScriptsFromDomDoc = function(domDoc) {
// We don't have Array.from in our node version, so use an old way to
// convert HTMLCollections to array
return Array.prototype.slice.call(
domDoc.head.getElementsByTagName('script'));
};
suite('For handwriting', function() {
// return an array of <sections> in the general panel
var getSectionsFromGeneralPanel = function(domDoc) {
return Array.prototype.slice.call(
domDoc.querySelectorAll('#general-container > section'));
};
// default: there shouldn't be handwriting elements in resulting file
test('APP=keyboard make', function(done) {
var cmd = 'APP=keyboard make';
helper.exec(cmd, function(error, stdout, stderr) {
helper.checkError(error, stdout, stderr);
var settingsDOMDoc = getSettingsDomDoc();
assert.isTrue(getScriptsFromDomDoc(settingsDOMDoc).every(function(elem){
return elem.src !== 'js/settings/handwriting_settings_view.js';
}), 'No script should include handwriting_settings_view.js');
assert.isTrue(
getSectionsFromGeneralPanel(settingsDOMDoc).every(function(elem){
return elem.id !== 'handwriting-settings';
}), 'No section in general panel should include handwriting settings');
done();
});
});
test('GAIA_KEYBOARD_LAYOUTS=zh-Hans-Handwriting APP=keyboard make',
function(done) {
var cmd = 'GAIA_KEYBOARD_LAYOUTS=zh-Hans-Handwriting APP=keyboard make';
helper.exec(cmd, function(error, stdout, stderr) {
helper.checkError(error, stdout, stderr);
var settingsDOMDoc = getSettingsDomDoc();
assert.isTrue(getScriptsFromDomDoc(settingsDOMDoc).some(function(elem){
return elem.src === 'js/settings/handwriting_settings_view.js';
}), 'Some script should include handwriting_settings_view.js');
assert.isTrue(
getSectionsFromGeneralPanel(settingsDOMDoc).some(function(elem){
return elem.id === 'handwriting-settings';
}),
'Some section in general panel should include handwriting settings');
done();
});
});
});
});