mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-05 08:25:32 +00:00
354 lines
9.8 KiB
JavaScript
354 lines
9.8 KiB
JavaScript
// KeymanWeb test suite - processing of the Karma configuration's client.args parameter.
|
|
|
|
com = com || {};
|
|
com.keyman = com.keyman || {};
|
|
com.keyman.karma = com.keyman.karma || {};
|
|
com.keyman.karma.DEVICE_DETECT_FAILURE = false;
|
|
|
|
// If we've set things up to support Device dection without loading KMW...
|
|
try {
|
|
let device = new com.keyman.Device();
|
|
device.detect();
|
|
} catch (err) {
|
|
// Sets a warning flag that unit-test files can use to disable themselves.
|
|
com.keyman.karma.DEVICE_DETECT_FAILURE = true;
|
|
}
|
|
|
|
// Keyman test suite utility methods
|
|
|
|
var setupKMW = function(kmwOptions, timeout) {
|
|
var ui;
|
|
|
|
if(typeof(kmwOptions) == 'string' || typeof(kmwOptions) == 'undefined' || kmwOptions == null) {
|
|
ui = kmwOptions;
|
|
|
|
var kmwOptions = {
|
|
attachType:'auto',
|
|
root:'source',
|
|
resources:'../../../../source'
|
|
};
|
|
|
|
if(ui) {
|
|
kmwOptions.ui = ui;
|
|
}
|
|
}
|
|
|
|
const kmwPromise = setupScript('source/keymanweb.js', timeout, (scriptEle) => {
|
|
fixture.el.appendChild(scriptEle);
|
|
});
|
|
|
|
ui = kmwOptions.ui;
|
|
|
|
kmwOptions.attachType = kmwOptions.attachType ? kmwOptions.attachType : 'auto';
|
|
|
|
if(!kmwOptions.root) {
|
|
kmwOptions.root = 'source';
|
|
}
|
|
|
|
if(!kmwOptions.resources) {
|
|
kmwOptions.resources = '../../../../source';
|
|
}
|
|
|
|
let uiPromise;
|
|
if(ui) {
|
|
uiPromise = setupScript('source/kmwui' + ui + '.js', timeout, (scriptEle) => {
|
|
fixture.el.appendChild(scriptEle);
|
|
});
|
|
|
|
kmwOptions.ui=ui;
|
|
}
|
|
|
|
let compositePromise = kmwPromise;
|
|
if(uiPromise) {
|
|
compositePromise = Promise.all([kmwPromise, uiPromise]);
|
|
}
|
|
|
|
return finalPromise = compositePromise.then(() => {
|
|
if(window['keyman']) {
|
|
return window['keyman'].init(kmwOptions);
|
|
} else {
|
|
return Promise.reject();
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Produces a script element tied to a Promise for its eventual load (or failure thereof).
|
|
*
|
|
* The script element is only available via callback due to implementation constraints.
|
|
*
|
|
* @param {*} src The source script's (relative) path on the test server.
|
|
* @param {*} timeout
|
|
* @param {*} functor A callback to handle the script element.
|
|
* @returns
|
|
*/
|
|
var setupScript = function(src, timeout, functor) {
|
|
return new Promise((resolve, reject) => {
|
|
const Lscript = document.createElement('script');
|
|
let hasResolved = false;
|
|
Lscript.charset="UTF-8"; // KMEW-89
|
|
Lscript.type = 'text/javascript';
|
|
Lscript.async = false;
|
|
|
|
const timer = window.setTimeout(() => {
|
|
reject("Script load attempt timed out.");
|
|
}, timeout);
|
|
|
|
Lscript.onload = Lscript.onreadystatechange = () => {
|
|
window.clearTimeout(timer);
|
|
if(!hasResolved && (Lscript.readyState === undefined || Lscript.readyState == "complete")) {
|
|
hasResolved = true;
|
|
resolve();
|
|
}
|
|
}
|
|
|
|
Lscript.onerror = (err) => {
|
|
window.clearTimeout(timer);
|
|
reject(err);
|
|
}
|
|
|
|
Lscript.src = src;
|
|
|
|
functor(Lscript);
|
|
});
|
|
}
|
|
|
|
var teardownKMW = function() {
|
|
var error = null;
|
|
if(keyman) { // If our setupKMW fails somehow, this guard prevents a second error report on teardown.
|
|
|
|
// We want to be SURE teardown works correctly, or we'll get lots of strange errors on other tests.
|
|
// Thus, error-handling on shutdown itself. It HAS mattered.
|
|
try {
|
|
keyman['shutdown']();
|
|
} catch(err) {
|
|
error = err;
|
|
}
|
|
|
|
try {
|
|
var success = delete window["keyman"];
|
|
if(!success) {
|
|
window["keyman"] = undefined;
|
|
}
|
|
} finally {
|
|
if(error) {
|
|
console.log("Error during KMW shutdown!");
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var loadKeyboardStub = function(stub, timeout, params) {
|
|
var kbdName = "Keyboard_" + stub.id;
|
|
|
|
keyman.addKeyboards(stub);
|
|
if(!params || !params.passive) {
|
|
return keyman.setActiveKeyboard(kbdName, stub.languages.id);
|
|
} else if(keyman.getActiveKeyboard() != kbdName) {
|
|
return setupScript(stub.filename, timeout, (ele) => {
|
|
fixture.el.appendChild(ele);
|
|
});
|
|
} else {
|
|
return Promise.resolve();
|
|
}
|
|
}
|
|
|
|
var loadKeyboardFromJSON = function(jsonPath, timeout, params) {
|
|
var stub = fixture.load(jsonPath, true);
|
|
|
|
return loadKeyboardStub(stub, timeout, params);
|
|
}
|
|
|
|
function runLoadedKeyboardTest(testDef, device, usingOSK, assertCallback) {
|
|
var inputElem = document.getElementById('singleton');
|
|
if(inputElem['kmw_ip']) {
|
|
inputElem = inputElem['kmw_ip'];
|
|
}
|
|
|
|
let proctor = new KMWRecorder.BrowserProctor(inputElem, device, usingOSK, assertCallback);
|
|
testDef.test(proctor);
|
|
}
|
|
|
|
function runKeyboardTestFromJSON(jsonPath, params, callback, assertCallback, timeout) {
|
|
var testSpec = new KMWRecorder.KeyboardTest(fixture.load(jsonPath, true));
|
|
let device = new com.keyman.Device();
|
|
device.detect();
|
|
|
|
loadKeyboardStub(testSpec.keyboard, timeout).then(() => {
|
|
runLoadedKeyboardTest(testSpec, device.coreSpec, params.usingOSK, assertCallback);
|
|
keyman.removeKeyboards(testSpec.keyboard.id);
|
|
callback();
|
|
});
|
|
}
|
|
|
|
function retrieveAndReset(Pelem) {
|
|
var alias = Pelem['kmw_ip'];
|
|
var val = "";
|
|
if(alias) {
|
|
val = alias.textContent;
|
|
alias.setText("", 0);
|
|
} else {
|
|
val = Pelem.value;
|
|
Pelem.value = "";
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
// Useful for tests related to strings with supplementary pairs.
|
|
var toSupplementaryPairString = function(code){
|
|
var H = Math.floor((code - 0x10000) / 0x400) + 0xD800;
|
|
var L = (code - 0x10000) % 0x400 + 0xDC00;
|
|
|
|
return String.fromCharCode(H, L);
|
|
}
|
|
|
|
var toEscapedSupplementaryPairString = function(code){
|
|
var H = (Math.floor((code - 0x10000) / 0x400) + 0xD800).toString(16);
|
|
var L = ((code - 0x10000) % 0x400 + 0xDC00).toString(16);
|
|
|
|
return "\\u"+H+"\\u"+L;
|
|
}
|
|
|
|
// Defines an object for dynamically adding elements for testing purposes.
|
|
// Designed for use with the robustAttachment.html fixture.
|
|
|
|
var DynamicElements;
|
|
var inputCounter = 0;
|
|
|
|
if(typeof(DynamicElements) == 'undefined') {
|
|
DynamicElements = {};
|
|
|
|
DynamicElements.addInput = function() {
|
|
var masterDiv = document.getElementById('DynamicElements');
|
|
var newInput = document.createElement("input");
|
|
var i = inputCounter++;
|
|
|
|
newInput.id = 'input' + i;
|
|
newInput.className = 'test';
|
|
newInput.placeholder = "Dynamic area #" + i + "!";
|
|
|
|
masterDiv.appendChild(newInput);
|
|
return newInput.id;
|
|
}
|
|
|
|
DynamicElements.addText = function () {
|
|
var masterDiv = document.getElementById('DynamicElements');
|
|
var newTextArea = document.createElement("textarea");
|
|
var i = inputCounter++;
|
|
|
|
newTextArea.id = 'textarea' + i;
|
|
newTextArea.className = 'test';
|
|
newTextArea.placeholder = "Dynamic area #" + i + "!";
|
|
|
|
masterDiv.appendChild(newTextArea);
|
|
return newTextArea.id;
|
|
}
|
|
|
|
DynamicElements.addIFrame = function(loadCallback) {
|
|
var masterDiv = document.getElementById('DynamicElements');
|
|
var frame = document.createElement("iframe");
|
|
var i = inputCounter++;
|
|
|
|
frame.height = "100";
|
|
frame.id = 'iframe' + i;
|
|
if(loadCallback) {
|
|
frame.addEventListener('load', function() {
|
|
// Give KMW's attachment events a chance to run first.
|
|
window.setTimeout(loadCallback, Math.max(100, testconfig.timeouts.scriptLoad));
|
|
});
|
|
}
|
|
frame.setAttribute("src", "resources/html/iframe.html");
|
|
|
|
masterDiv.appendChild(frame);
|
|
return frame.id;
|
|
}
|
|
|
|
DynamicElements.addDesignIFrame = function(loadCallback) {
|
|
var masterDiv = document.getElementById('DynamicElements');
|
|
var frame = document.createElement("iframe");
|
|
var i = inputCounter++;
|
|
|
|
frame.height = "100";
|
|
frame.id = 'designIFrame' + i;
|
|
frame.src = "resources/html/editableFrame.html";
|
|
|
|
if(loadCallback) {
|
|
frame.addEventListener('load', function() {
|
|
loadCallback();
|
|
});
|
|
}
|
|
|
|
masterDiv.appendChild(frame);
|
|
return frame.id;
|
|
}
|
|
|
|
DynamicElements.addEditable = function() {
|
|
var masterDiv = document.getElementById('DynamicElements');
|
|
var editable = document.createElement("div");
|
|
var i = inputCounter++;
|
|
|
|
editable.contentEditable = true;
|
|
editable.textContent = "Edit me!";
|
|
editable.id = 'editable' + i;
|
|
editable.style.width="500px";
|
|
|
|
masterDiv.appendChild(editable);
|
|
return editable.id;
|
|
}
|
|
|
|
// base: takes an optional element to use as the touch alias's ['base'] property.
|
|
DynamicElements.addTouchAlias = function(base) {
|
|
var masterDiv = document.getElementById('DynamicElements');
|
|
var touchAlias = com.keyman.dom.constructTouchAlias(base);
|
|
var i = inputCounter++;
|
|
|
|
touchAlias.id = 'touchAlias' + i;
|
|
|
|
masterDiv.appendChild(touchAlias);
|
|
return touchAlias.id;
|
|
}
|
|
|
|
DynamicElements.assertAttached = function(ele, done) {
|
|
var assertion = function() {
|
|
assert.isTrue(keyman.isAttached(ele), "Element tag '" + ele.tagName + "', id '" + ele.id + "' was not attached!");
|
|
}
|
|
if(done) {
|
|
window.setTimeout(function() {
|
|
assertion();
|
|
done();
|
|
}, testconfig.timeouts.eventDelay);
|
|
} else {
|
|
assertion();
|
|
}
|
|
}
|
|
|
|
DynamicElements.assertDetached = function(ele, done) {
|
|
var assertion = function() {
|
|
assert.isFalse(keyman.isAttached(ele), "Element tag '" + ele.tagName + "', id '" + ele.id + "' was not detached!");
|
|
}
|
|
if(done) {
|
|
window.setTimeout(function() {
|
|
assertion();
|
|
done();
|
|
}, testconfig.timeouts.eventDelay);
|
|
} else {
|
|
assertion();
|
|
}
|
|
}
|
|
|
|
// Is utilized only by the attachmentAPI test case, but it was originally defined as part of the same
|
|
// object as the rest of DynamicElements, which is useful for numerous test cases.
|
|
DynamicElements.init = function() {
|
|
var s_key_json = {"type": "key", "key":"s", "code":"KeyS","keyCode":83,"modifierSet":0,"location":0};
|
|
DynamicElements.keyCommand = new KMWRecorder.PhysicalInputEventSpec(s_key_json);
|
|
|
|
DynamicElements.enabledLaoOutput = "ຫ";
|
|
DynamicElements.enabledKhmerOutput = "ស";
|
|
// Simulated JavaScript events do not produce text output.
|
|
DynamicElements.disabledOutput = "";
|
|
}
|
|
|
|
DynamicElements.init();
|
|
}
|