Merge pull request #7027 from keymanapp/refactor/web/web-test-setup-promises

refactor(web): converts test_utils funcs to Promise use 🤝
This commit is contained in:
Joshua Horton 2022-08-03 08:17:55 +07:00 committed by GitHub
commit c92bf0bf8a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 203 additions and 208 deletions

View file

@ -3,26 +3,23 @@ var assert = chai.assert;
describe('Attachment API', function() {
this.timeout(testconfig.timeouts.standard);
before(function(done) {
before(function() {
assert.isFalse(com.keyman.karma.DEVICE_DETECT_FAILURE, "Cannot run due to device detection failure.");
fixture.setBase('fixtures');
this.timeout(testconfig.timeouts.scriptLoad * 3);
setupKMW({ attachType:'manual' }, function() {
loadKeyboardFromJSON("/keyboards/lao_2008_basic.json", function() {
// Sequential so we don't have to worry about race conditions and such
// to signal completion with done().
loadKeyboardFromJSON("/keyboards/khmer_angkor.json", function() {
keyman.setActiveKeyboard("lao_2008_basic");
done();
}, testconfig.timeouts.scriptLoad);
}, testconfig.timeouts.scriptLoad);
}, testconfig.timeouts.scriptLoad);
return setupKMW({ attachType:'manual' }, testconfig.timeouts.scriptLoad).then(() => {
const kbd1 = loadKeyboardFromJSON("/keyboards/lao_2008_basic.json", testconfig.timeouts.scriptLoad, { passive: true });
const kbd2 = loadKeyboardFromJSON("/keyboards/khmer_angkor.json", testconfig.timeouts.scriptLoad, { passive: true });
return Promise.all([kbd1, kbd2]).then(() => {
return keyman.setActiveKeyboard("lao_2008_basic");
});
});
});
after(function() {
keyman.removeKeyboards('lao_2008_basic');
keyman.removeKeyboards('khmer_angkor');
teardownKMW();
});
@ -193,11 +190,11 @@ Modernizr.on('touchevents', function(result) {
this.timeout(testconfig.timeouts.standard);
before(function(done) {
before(function() {
this.timeout(testconfig.timeouts.scriptLoad);
fixture.setBase('fixtures');
setupKMW({ attachType:'auto' }, done, testconfig.timeouts.scriptLoad);
return setupKMW({ attachType:'auto' }, testconfig.timeouts.scriptLoad);
});
beforeEach(function() {
@ -261,11 +258,11 @@ Modernizr.on('touchevents', function(result) {
this.timeout(testconfig.timeouts.standard);
before(function(done) {
before(function() {
this.timeout(testconfig.timeouts.scriptLoad);
fixture.setBase('fixtures');
setupKMW({ attachType:'auto' }, done, testconfig.timeouts.scriptLoad);
return setupKMW({ attachType:'auto' }, testconfig.timeouts.scriptLoad);
});
beforeEach(function() {

View file

@ -8,12 +8,12 @@ describe('Basic KeymanWeb', function() {
assert.isFalse(com.keyman.karma.DEVICE_DETECT_FAILURE, "Cannot run due to device detection failure.");
})
beforeEach(function(done) {
beforeEach(function() {
this.timeout(testconfig.timeouts.scriptLoad);
fixture.setBase('fixtures');
fixture.load("singleInput.html");
setupKMW(null, done, testconfig.timeouts.scriptLoad);
return setupKMW(null, testconfig.timeouts.scriptLoad);
});
afterEach(function() {
@ -37,13 +37,13 @@ Modernizr.on('touchevents', function(result) {
describe('Basic Toggle UI', function() {
this.timeout(testconfig.timeouts.scriptLoad);
beforeEach(function(done) {
beforeEach(function() {
this.timeout(testconfig.timeouts.uiLoad);
fixture.setBase('fixtures');
fixture.load('singleInput.html');
// Sequentially loads two scripts, so 2x timeout.
setupKMW('toggle', done, testconfig.timeouts.uiLoad, function() { return keyman.ui.initialized; });
// Loads two scripts in parallel, but just in case, 2x timeout.
return setupKMW('toggle', testconfig.timeouts.uiLoad);
});
afterEach(function() {
@ -71,13 +71,13 @@ Modernizr.on('touchevents', function(result) {
describe('Basic Button UI', function() {
beforeEach(function(done) {
beforeEach(function() {
this.timeout(testconfig.timeouts.uiLoad);
fixture.setBase('fixtures');
fixture.load('singleInput.html');
// Sequentially loads two scripts, so 2x timeout.
setupKMW('button', done, testconfig.timeouts.uiLoad, function() { return keyman.ui.init; });
// Loads two scripts in parallel, but just in case, 2x timeout.
return setupKMW('button', testconfig.timeouts.uiLoad);
});
afterEach(function() {
@ -92,13 +92,13 @@ Modernizr.on('touchevents', function(result) {
describe('Basic Float UI', function() {
beforeEach(function(done) {
beforeEach(function() {
this.timeout(testconfig.timeouts.uiLoad);
fixture.setBase('fixtures');
fixture.load('singleInput.html');
// Sequentially loads two scripts, so 2x timeout.
setupKMW('float', done, testconfig.timeouts.uiLoad, function() { return keyman.ui.initialized; });
// Loads two scripts in parallel, but just in case, 2x timeout.
return setupKMW('float', testconfig.timeouts.uiLoad);
});
afterEach(function() {
@ -126,12 +126,13 @@ Modernizr.on('touchevents', function(result) {
describe('Basic Toolbar UI', function() {
beforeEach(function(done) {
beforeEach(function() {
this.timeout(testconfig.timeouts.uiLoad);
fixture.setBase('fixtures');
fixture.load('singleInput.html');
setupKMW('toolbar', done, testconfig.timeouts.uiLoad, function() { return keyman.ui.init; });
// Loads two scripts in parallel, but just in case, 2x timeout.
return setupKMW('toolbar', testconfig.timeouts.uiLoad);
});
afterEach(function() {

View file

@ -3,9 +3,9 @@ var assert = chai.assert;
describe('Engine - Browser Interactions', function() {
this.timeout(testconfig.timeouts.scriptLoad);
before(function(done) {
before(function() {
fixture.setBase('fixtures');
setupKMW(null, done, testconfig.timeouts.scriptLoad);
return setupKMW(null, testconfig.timeouts.scriptLoad);
});
beforeEach(function(done) {
@ -24,26 +24,8 @@ describe('Engine - Browser Interactions', function() {
fixture.cleanup();
});
describe('Keyboard Loading', function() {
it('Local', function(done) {
this.timeout(testconfig.timeouts.scriptLoad);
var test_callback = function() {
assert.isNotNull(keyman.getKeyboard("lao_2008_basic", "lo"), "Keyboard stub was not registered!");
assert.equal(keyman.getActiveKeyboard(), "Keyboard_lao_2008_basic", "Keyboard not set automatically!");
keyman.removeKeyboards('lao_2008_basic');
assert.equal(keyman.getActiveKeyboard(), '', "Keyboard not removed correctly!");
done();
}
loadKeyboardFromJSON("/keyboards/lao_2008_basic.json", test_callback, testconfig.timeouts.scriptLoad, {passive: true});
});
});
describe('RegisterStub', function() {
it.skip('RegisterStub on same keyboard twice', function(done) {
// mcdurdin: skipping this test for now as it is sporadically failing and have not been able to trace source of issue
// see https://github.com/keymanapp/keyman/issues/5799
it('RegisterStub on same keyboard twice', function() {
this.timeout(testconfig.timeouts.scriptLoad);
var test_callback = function() {
@ -51,10 +33,10 @@ describe('Engine - Browser Interactions', function() {
assert.equal(keyman.getActiveKeyboard(), "Keyboard_lao_2008_basic", "Keyboard not set automatically!");
keyman.removeKeyboards('lao_2008_basic');
assert.equal(keyman.getActiveKeyboard(), '', "Keyboard not removed correctly!");
done();
}
loadKeyboardFromJSON("/keyboards/lao_2008_basic.json", test_callback, testconfig.timeouts.scriptLoad, {passive: true});
let finalPromise = loadKeyboardFromJSON("/keyboards/lao_2008_basic.json", testconfig.timeouts.scriptLoad)
.then(test_callback);
var stub = {
'KI': 'Keyboard_lao_2008_basic',
@ -64,7 +46,7 @@ describe('Engine - Browser Interactions', function() {
'KF': 'resources/keyboards/lao_2008_basic.js'
};
assert.equal(com.keyman.text.KeyboardInterface.prototype.registerStub(stub), 1, "Registering existing keyboard should return 1!");
done();
return finalPromise;
});
});
@ -72,8 +54,8 @@ describe('Engine - Browser Interactions', function() {
describe('Variable Stores', function() {
this.timeout(testconfig.timeouts.scriptLoad + testconfig.timeouts.standard);
beforeEach(function(done) {
loadKeyboardFromJSON("/keyboards/options_with_save.json", done, testconfig.timeouts.scriptLoad);
beforeEach(function() {
return loadKeyboardFromJSON("/keyboards/options_with_save.json", testconfig.timeouts.scriptLoad);
});
after(function() {
@ -110,9 +92,10 @@ describe('Engine - Browser Interactions', function() {
done();
}
loadKeyboardFromJSON("/keyboards/options_with_save.json", function() {
keyman.setActiveKeyboard(keyboardID, 'en').then(remainderOfTest);
}, testconfig.timeouts.scriptLoad);
return loadKeyboardFromJSON("/keyboards/options_with_save.json", testconfig.timeouts.scriptLoad)
.then(() => {
return keyman.setActiveKeyboard(keyboardID, 'en');
}).then(remainderOfTest);
});
});
@ -144,9 +127,9 @@ describe('Engine - Browser Interactions', function() {
describe('Integrated Simulation Checks', function() {
this.timeout(testconfig.timeouts.standard);
before(function(done){
before(function() {
this.timeout = testconfig.timeouts.scriptLoad;
loadKeyboardFromJSON("/keyboards/lao_2008_basic.json", done, testconfig.timeouts.scriptLoad);
return loadKeyboardFromJSON("/keyboards/lao_2008_basic.json", testconfig.timeouts.scriptLoad);
});
beforeEach(function() {
@ -213,9 +196,9 @@ describe('Engine - Browser Interactions', function() {
describe('Unmatched Final Groups', function() {
this.timeout(testconfig.timeouts.scriptLoad);
before(function(done) {
before(function() {
fixture.setBase('fixtures');
setupKMW(null, done, testconfig.timeouts.scriptLoad + testconfig.timeouts.eventDelay);
return setupKMW(null, testconfig.timeouts.scriptLoad + testconfig.timeouts.eventDelay);
});
beforeEach(function(done) {
@ -240,3 +223,82 @@ describe('Unmatched Final Groups', function() {
runKeyboardTestFromJSON('/engine_tests/ghp_enter.json', {usingOSK: true}, done, assert.equal, testconfig.timeouts.scriptLoad);
});
});
// Kept separate to maintain an extra-clean setup for this test.
describe('Engine - Browser Interactions', function() {
this.timeout(testconfig.timeouts.scriptLoad);
before(function() {
fixture.setBase('fixtures');
});
beforeEach(function() {
fixture.load("singleInput.html");
return setupKMW(null, testconfig.timeouts.scriptLoad);
});
afterEach(function() {
fixture.cleanup();
teardownKMW();
});
describe('Keyboard Loading', function() {
it('Local', function() {
this.timeout(testconfig.timeouts.scriptLoad);
var test_callback = function() {
assert.isNotNull(keyman.getKeyboard("lao_2008_basic", "lo"), "Keyboard stub was not registered!");
assert.equal(keyman.getActiveKeyboard(), "Keyboard_lao_2008_basic", "Keyboard not set automatically!");
keyman.removeKeyboards('lao_2008_basic');
assert.equal(keyman.getActiveKeyboard(), '', "Keyboard not removed correctly!");
}
return loadKeyboardFromJSON("/keyboards/lao_2008_basic.json", testconfig.timeouts.scriptLoad)
.then(test_callback);
});
it('Automatically sets first available keyboard', function() {
this.timeout(2 * testconfig.timeouts.scriptLoad);
var test_callback = function() {
assert.isNotNull(keyman.getKeyboard("lao_2008_basic", "lo"), "Keyboard stub was not registered!");
assert.equal(keyman.getActiveKeyboard(), "Keyboard_lao_2008_basic", "Keyboard not set automatically!");
keyman.removeKeyboards('lao_2008_basic');
assert.equal(keyman.getActiveKeyboard(), '', "Keyboard not removed correctly!");
}
return loadKeyboardFromJSON("/keyboards/lao_2008_basic.json", testconfig.timeouts.scriptLoad, {passive: true})
.then(() => {
// Because we're loading the keyboard 'passively', KMW's setActiveKeyboard function is auto-called
// on the stub-add. That specific call (for first keyboard auto-activation) is outside of KMW's
// current Promise chain, so we can't _directly_ rely on a KMW Promise to test it.
return new Promise((resolve) => {
let hasResolved = false;
// So, we give KMW the time needed for auto-activation to happen, polling a bit actively so that we don't
// wait unnecessarily long after it occurs.
let absoluteTimer = window.setTimeout(() => {
if(!hasResolved) {
resolve();
hasResolved = true;
}
window.clearTimeout(intervalTimer);
}, testconfig.timeouts.scriptLoad);
let intervalTimer = window.setInterval(() => {
if(keyman.getActiveKeyboard() != '') {
window.clearTimeout(intervalTimer);
window.clearTimeout(absoluteTimer);
if(!hasResolved) {
resolve();
hasResolved = true;
}
}
}, 50);
});
// Once this delay-Promise resolves successfully (either way)...
}).then(test_callback); // THEN we run our checks.
});
});
});

View file

@ -3,9 +3,9 @@ var assert = chai.assert;
describe('Engine - Chirality', function() {
this.timeout(testconfig.timeouts.scriptLoad);
before(function(done) {
before(function() {
fixture.setBase('fixtures');
setupKMW(null, done, testconfig.timeouts.scriptLoad);
return setupKMW(null, testconfig.timeouts.scriptLoad);
});
beforeEach(function(done) {

View file

@ -3,21 +3,16 @@ var assert = chai.assert;
describe('Event Management', function() {
this.timeout(testconfig.timeouts.standard);
before(function(done) {
before(function() {
this.timeout(testconfig.timeouts.scriptLoad * 2);
fixture.setBase('fixtures');
fixture.load("eventTestConfig.html");
setupKMW(null, function() {
return setupKMW(null, testconfig.timeouts.scriptLoad).then(() => {
// We use this keyboard since we only need minimal input functionality for these tests.
// Smaller is better when dealing with net latency.
loadKeyboardFromJSON("/keyboards/test_simple_deadkeys.json", function() {
// Interestingly, when auto-testing there's a Safari bug that prevents
// this from being preserved after the first forced blur command below.
done();
}, testconfig.timeouts.scriptLoad);
}, testconfig.timeouts.scriptLoad);
return loadKeyboardFromJSON("/keyboards/test_simple_deadkeys.json", testconfig.timeouts.scriptLoad);
});
});
after(function() {

View file

@ -76,19 +76,18 @@ describe('Text Selection', function() {
// TODO: Add automated tests for editable DIV, designMode iframe
for(var inputType of ['Input', 'TextArea']) {
describe('Text Selection in '+inputType, function() {
before(function(done) {
before(function() {
// These tests require use of KMW's device-detection functionality.
assert.isFalse(com.keyman.karma.DEVICE_DETECT_FAILURE, "Cannot run due to device detection failure.");
fixture.setBase('fixtures');
fixture.load("single"+inputType+".html");
this.timeout(testconfig.timeouts.scriptLoad*2);
setupKMW(null, function() {
loadKeyboardFromJSON("/keyboards/web_context_tests.json", function() {
keyman.setActiveKeyboard("web_context_tests");
done();
}, testconfig.timeouts.scriptLoad);
}, testconfig.timeouts.scriptLoad);
return setupKMW(null, testconfig.timeouts.scriptLoad).then(() => {
return loadKeyboardFromJSON("/keyboards/web_context_tests.json", testconfig.timeouts.scriptLoad).then(() => {
return keyman.setActiveKeyboard("web_context_tests");
});
});
});
after(function() {

View file

@ -16,7 +16,7 @@ try {
// Keyman test suite utility methods
var setupKMW = function(kmwOptions, done, timeout, uiInitCheck) {
var setupKMW = function(kmwOptions, timeout) {
var ui;
if(typeof(kmwOptions) == 'string' || typeof(kmwOptions) == 'undefined' || kmwOptions == null) {
@ -33,8 +33,9 @@ var setupKMW = function(kmwOptions, done, timeout, uiInitCheck) {
}
}
var kmw = setupScript('source/keymanweb.js', done, timeout, uiInitCheck);
fixture.el.appendChild(kmw);
const kmwPromise = setupScript('source/keymanweb.js', timeout, (scriptEle) => {
fixture.el.appendChild(scriptEle);
});
ui = kmwOptions.ui;
@ -48,43 +49,68 @@ var setupKMW = function(kmwOptions, done, timeout, uiInitCheck) {
kmwOptions.resources = '../../../../source';
}
let uiPromise;
if(ui) {
var ui = setupScript('source/kmwui' + ui + '.js');
fixture.el.appendChild(ui);
uiPromise = setupScript('source/kmwui' + ui + '.js', timeout, (scriptEle) => {
fixture.el.appendChild(scriptEle);
});
kmwOptions.ui=ui;
}
var initFunc = function() {
if(window['keyman']) {
window['keyman'].init(kmwOptions);
} else {
window.setTimeout(function() {
initFunc();
})
}
};
/* Keep this timeout short - if set too long, kmwinit's default initialization
* will kick in and prevent our settings from going through!
*/
window.setTimeout(function() {
initFunc();
}, 5);
}
var setupScript = function(src, done, timeout, uiInitCheck) {
var Lscript = document.createElement('script');
Lscript.charset="UTF-8"; // KMEW-89
Lscript.type = 'text/javascript';
Lscript.async = false;
if(done) {
Lscript.onload = initTimer(done, timeout, uiInitCheck);
let compositePromise = kmwPromise;
if(uiPromise) {
compositePromise = Promise.all([kmwPromise, uiPromise]);
}
Lscript.src = src;
return finalPromise = compositePromise.then(() => {
if(window['keyman']) {
return window['keyman'].init(kmwOptions);
} else {
return Promise.reject();
}
});
}
return Lscript;
/**
* 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() {
@ -113,110 +139,25 @@ var teardownKMW = function() {
}
}
// Make sure the main script loads...
var initTimer = function(done, timeout, uiInitCheck) {
var uiLoadDelay;
if(typeof(uiInitCheck) != 'function') {
uiInitCheck = function() { return true; };
uiLoadDelay = false;
} else {
uiLoadDelay = true;
}
// We need managed state for this.
var InitializationManager = function() {
this.killSwitch = false;
this.initCheckCallback = function() {
if(window['keyman'] && window['keyman'].initialized == 2 && uiInitCheck()) {
if(done) {
this.timer = window.setTimeout(function() {
// There can be some odd cross-interference with the UI modules and their initialization.
// We use a significant delay here to avoid said problems.
done();
}, uiLoadDelay ? 2000 : 0);
}
} else if(!this.killSwitch) {
this.timer = window.setTimeout(this.initCheckCallback, 50);
}
}.bind(this);
if(timeout) {
window.setTimeout(function() {
this.killSwitch = true;
if(this.timer) {
window.clearTimeout(this.timer);
this.timer = 0;
}
}.bind(this), timeout);
}
}
var im = new InitializationManager();
return im.initCheckCallback;
};
// Make sure the main script loads...
var onScriptLoad = function(scriptURL, callback, timeout) {
var ScriptLoadObserver = function() {
this.target = document.createElement('a');
this.target.href = scriptURL;
if(timeout) {
this.timer = window.setTimeout(function() {
if(this.mo) {
this.mo.disconnect();
}
}.bind(this), timeout);
}
var moCallback = function(mutations) {
for(var i=0; i < mutations.length; i++) {
var mutation = mutations[i];
for(var j=0; j < mutation.addedNodes.length; j++) {
var child = mutation.addedNodes[j];
if(child instanceof HTMLScriptElement) {
if(child.src == this.target.href) {
child.onload = callback;
}
}
}
}
}
this.observe = function() {
var config = { childList: true, subtree: true };
this.mo = new MutationObserver(moCallback.bind(this));
this.mo.observe(document, config);
}
}
var slo = new ScriptLoadObserver();
slo.observe();
};
var loadKeyboardStub = function(stub, callback, timeout, params) {
var loadKeyboardStub = function(stub, timeout, params) {
var kbdName = "Keyboard_" + stub.id;
keyman.addKeyboards(stub);
if(!params || !params.passive) {
keyman.setActiveKeyboard(kbdName, stub.languages.id);
}
if(keyman.getActiveKeyboard() != kbdName) {
onScriptLoad(stub.filename, function() {
callback();
}, timeout);
return keyman.setActiveKeyboard(kbdName, stub.languages.id);
} else if(keyman.getActiveKeyboard() != kbdName) {
return setupScript(stub.filename, timeout, (ele) => {
fixture.el.appendChild(ele);
});
} else {
callback();
return Promise.resolve();
}
}
var loadKeyboardFromJSON = function(jsonPath, callback, timeout) {
var loadKeyboardFromJSON = function(jsonPath, timeout, params) {
var stub = fixture.load(jsonPath, true);
loadKeyboardStub(stub, callback, timeout);
return loadKeyboardStub(stub, timeout, params);
}
function runLoadedKeyboardTest(testDef, device, usingOSK, assertCallback) {
@ -234,11 +175,11 @@ function runKeyboardTestFromJSON(jsonPath, params, callback, assertCallback, tim
let device = new com.keyman.Device();
device.detect();
loadKeyboardStub(testSpec.keyboard, function() {
loadKeyboardStub(testSpec.keyboard, timeout).then(() => {
runLoadedKeyboardTest(testSpec, device.coreSpec, params.usingOSK, assertCallback);
keyman.removeKeyboards(testSpec.keyboard.id);
callback();
}, timeout);
});
}
function retrieveAndReset(Pelem) {