diff --git a/web/common.inc.sh b/web/common.inc.sh index b4a3c47d7eb..2c7ee35fd86 100644 --- a/web/common.inc.sh +++ b/web/common.inc.sh @@ -17,7 +17,7 @@ # compile engine/main # ``` function compile() { - if [ $# -lt 1 ]; then + if [[ $# -lt 1 ]]; then builder_die "Scripting error: insufficient argument count!" fi @@ -27,10 +27,10 @@ function compile() { local SRC_DIR=${2:-"${KEYMAN_ROOT}/web/src"} local BUILD_DIR=${3:-"${KEYMAN_ROOT}/web/build"} - tsc -b "${SRC_DIR}/$COMPILE_TARGET" + tsc -b "${SRC_DIR}/${COMPILE_TARGET}" # So... tsc does declaration-bundling on its own pretty well, at least for local development. - tsc --emitDeclarationOnly --outFile "${BUILD_DIR}/$COMPILE_TARGET/lib/index.d.ts" -p "${SRC_DIR}/$COMPILE_TARGET" + tsc --emitDeclarationOnly --outFile "${BUILD_DIR}/${COMPILE_TARGET}/lib/index.d.ts" -p "${SRC_DIR}/${COMPILE_TARGET}" } function _copy_dir_if_exists() { diff --git a/web/package.json b/web/package.json index 219b2ddac95..887eeed27d0 100644 --- a/web/package.json +++ b/web/package.json @@ -81,6 +81,10 @@ "./tools/testing/test-utils": { "types": "./build/tools/testing/test-utils/obj/index.d.ts", "import": "./build/tools/testing/test-utils/obj/index.js" + }, + "./test/resources": { + "types": "./src/test/auto/resources/build/index.d.ts", + "import": "./src/test/auto/resources/build/index.js" } }, "imports": { diff --git a/web/src/engine/build.sh b/web/src/engine/build.sh index 2b5f6380b18..328d6a4a5d6 100755 --- a/web/src/engine/build.sh +++ b/web/src/engine/build.sh @@ -68,11 +68,35 @@ do_build () { node src/osk/validate-gesture-specs.js } -builder_run_action clean rm -rf "$KEYMAN_ROOT/web/build/engine" +run_tests() { + local OUTPUT_FILE FAILURE_COUNT + # Remove stale coverage data + rm -rf "${KEYMAN_ROOT}/web/build/coverage/raw/engine" + + # Unfortunately we get an error from the coverage report generation: + # "TypeError [ERR_INVALID_URL_SCHEME]: The URL must be of scheme file" + # The following lines ignore the exit code and instead check the number + # of failed tests from the output. + set +e + OUTPUT_FILE=$(mktemp) + test-headless engine "" 2>&1 | tee "${OUTPUT_FILE}" + set -e + + FAILURE_COUNT=$(grep ' failing' "${OUTPUT_FILE}" | xargs | cut -f 1 -d' ') + rm "${OUTPUT_FILE}" + builder_echo "(The 'TypeError [ERR_INVALID_URL_SCHEME]: The URL must be of scheme file' is expected)" + if ((FAILURE_COUNT > 0)); then + builder_die "Headless engine tests failed (.js tests)" + fi + + test-headless-typescript engine +} + +builder_run_action clean rm -rf "${KEYMAN_ROOT}/web/build/engine" builder_run_child_actions clean builder_run_action configure node_select_version_and_npm_ci builder_run_child_actions configure builder_run_child_actions build builder_run_action build do_build -builder_run_action test test-headless-typescript engine +builder_run_action test run_tests builder_run_child_actions test \ No newline at end of file diff --git a/web/src/engine/src/keyboard-storage/cloud/queryEngine.ts b/web/src/engine/src/keyboard-storage/cloud/cloudQueryEngine.ts similarity index 100% rename from web/src/engine/src/keyboard-storage/cloud/queryEngine.ts rename to web/src/engine/src/keyboard-storage/cloud/cloudQueryEngine.ts diff --git a/web/src/engine/src/keyboard-storage/cloud/index.ts b/web/src/engine/src/keyboard-storage/cloud/index.ts deleted file mode 100644 index 2ab752bcded..00000000000 --- a/web/src/engine/src/keyboard-storage/cloud/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { CloudQueryResult, CloudQueryEngine as QueryEngine } from './queryEngine.js'; -export { CloudRequesterInterface as RequesterInterface } from './requesterInterface.js'; diff --git a/web/src/engine/src/keyboard-storage/domCloudRequester.ts b/web/src/engine/src/keyboard-storage/domCloudRequester.ts index 85ab4cd73e1..6d13b43cfde 100644 --- a/web/src/engine/src/keyboard-storage/domCloudRequester.ts +++ b/web/src/engine/src/keyboard-storage/domCloudRequester.ts @@ -1,6 +1,6 @@ import { ManagedPromise } from 'keyman/common/web-utils'; import { CloudRequesterInterface } from './cloud/requesterInterface.js'; -import { CLOUD_MALFORMED_OBJECT_ERR, CLOUD_TIMEOUT_ERR, CLOUD_STUB_REGISTRATION_ERR } from './cloud/queryEngine.js'; +import { CLOUD_MALFORMED_OBJECT_ERR, CLOUD_TIMEOUT_ERR, CLOUD_STUB_REGISTRATION_ERR } from './cloud/cloudQueryEngine.js'; export class DOMCloudRequester implements CloudRequesterInterface { private readonly fileLocal: boolean; diff --git a/web/src/engine/src/keyboard-storage/index.ts b/web/src/engine/src/keyboard-storage/index.ts index 7f83893de2c..e6e3b7b9909 100644 --- a/web/src/engine/src/keyboard-storage/index.ts +++ b/web/src/engine/src/keyboard-storage/index.ts @@ -8,8 +8,15 @@ export { REGION_CODES } from './keyboardStub.js'; export { StubAndKeyboardCache, toPrefixedKeyboardId, toUnprefixedKeyboardId } from './stubAndKeyboardCache.js'; -export { CloudQueryResult, CloudQueryEngine } from './cloud/queryEngine.js'; +export { CloudQueryResult, CloudQueryEngine } from './cloud/cloudQueryEngine.js'; export { CloudRequesterInterface } from './cloud/requesterInterface.js'; export { KeyboardRequisitioner } from './keyboardRequisitioner.js'; export { ModelCache } from './modelCache.js'; -export { DOMCloudRequester } from './domCloudRequester.js'; \ No newline at end of file +export { DOMCloudRequester } from './domCloudRequester.js'; + +import { CLOUD_TIMEOUT_ERR, CLOUD_STUB_REGISTRATION_ERR } from './cloud/cloudQueryEngine.js'; + +export const unitTestEndpoints = { + CLOUD_TIMEOUT_ERR, + CLOUD_STUB_REGISTRATION_ERR +}; diff --git a/web/src/test/auto/headless/engine/interfaces/prediction/predictionContext.tests.js b/web/src/test/auto/headless/engine/interfaces/prediction/predictionContext.tests.js index e5bf59b2cde..6beca50f82e 100644 --- a/web/src/test/auto/headless/engine/interfaces/prediction/predictionContext.tests.js +++ b/web/src/test/auto/headless/engine/interfaces/prediction/predictionContext.tests.js @@ -3,8 +3,8 @@ import sinon from 'sinon'; import { LanguageProcessor, TranscriptionCache } from 'keyman/engine/main'; import { PredictionContext } from 'keyman/engine/interfaces'; -import { Worker as LMWorker } from "@keymanapp/lexical-model-layer/node"; -import { DeviceSpec, SyntheticTextStore } from 'keyman/engine/keyboard'; +import { NodeWorker } from "@keymanapp/lexical-model-layer/node"; +import { SyntheticTextStore } from 'keyman/engine/keyboard'; function compileDummyModel(suggestionSets) { return ` @@ -66,7 +66,7 @@ describe("PredictionContext", () => { let langProcessor; beforeEach(function() { - langProcessor = new LanguageProcessor(LMWorker, new TranscriptionCache()); + langProcessor = new LanguageProcessor(NodeWorker, new TranscriptionCache()); }); afterEach(function() { @@ -83,7 +83,7 @@ describe("PredictionContext", () => { let textStore = new SyntheticTextStore("appl", 4); // "appl|", with '|' as the caret position. const initialTextStore = SyntheticTextStore.from(textStore); - const promise = predictiveContext.setCurrentTarget(textStore); + const promise = predictiveContext.setCurrentTextStore(textStore); // Initial predictive state: no suggestions. context.initializeState() has not yet been called. assert.equal(updateFake.callCount, 1); @@ -122,7 +122,7 @@ describe("PredictionContext", () => { let textStore = new SyntheticTextStore("appl", 4); // "appl|", with '|' as the caret position. const initialTextStore = SyntheticTextStore.from(textStore); - const promise = predictiveContext.setCurrentTarget(textStore); + const promise = predictiveContext.setCurrentTextStore(textStore); // Initial predictive state: no suggestions. context.initializeState() has not yet been called. assert.equal(updateFake.callCount, 1); @@ -181,7 +181,7 @@ describe("PredictionContext", () => { const predictiveContext = new PredictionContext(langProcessor, dummiedGetLayer); let textStore = new SyntheticTextStore("appl", 4); // "appl|", with '|' as the caret position. - const initialSuggestions = await predictiveContext.setCurrentTarget(textStore); + const initialSuggestions = await predictiveContext.setCurrentTextStore(textStore); let updateFake = sinon.fake(); predictiveContext.on('update', updateFake); @@ -206,7 +206,7 @@ describe("PredictionContext", () => { let textState = new SyntheticTextStore("appl", 4); // "appl|", with '|' as the caret position. - await predictiveContext.setCurrentTarget(textState); + await predictiveContext.setCurrentTextStore(textState); let updateFake = sinon.fake(); predictiveContext.on('update', updateFake); @@ -274,7 +274,7 @@ describe("PredictionContext", () => { // Test setup - return to the state at the end of the prior-defined unit test ('suggestion application...') - await predictiveContext.setCurrentTarget(textState); + await predictiveContext.setCurrentTextStore(textState); // This is the point in time that a reversion operation will rewind the context to. const revertBaseTextState = SyntheticTextStore.from(textState); diff --git a/web/src/test/auto/headless/engine/js-processor/basic-engine.tests.js b/web/src/test/auto/headless/engine/js-processor/basic-engine.tests.js index 08bec6f4368..40d6b6797b8 100644 --- a/web/src/test/auto/headless/engine/js-processor/basic-engine.tests.js +++ b/web/src/test/auto/headless/engine/js-processor/basic-engine.tests.js @@ -7,11 +7,15 @@ const require = createRequire(import.meta.url); import { MinimalKeymanGlobal } from 'keyman/engine/keyboard'; import { JSKeyboardInterface } from 'keyman/engine/js-processor'; -import { NodeKeyboardLoader } from '../../../resources/loader/nodeKeyboardLoader.js'; +import { NodeKeyboardLoader } from 'keyman/test/resources'; import { KeyboardTest, NodeProctor } from '@keymanapp/recorder-core'; import { env } from 'node:process'; -const KEYMAN_ROOT = env.KEYMAN_ROOT; +import { fileURLToPath } from 'node:url'; +import { dirname } from 'node:path'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const KEYMAN_ROOT = env.KEYMAN_ROOT ?? (__dirname + '/../../../../../../../'); describe('Engine - Basic Simulation', function() { let testJSONtext = fs.readFileSync(require.resolve('@keymanapp/common-test-resources/json/engine_tests/basic_lao_simulation.json')); diff --git a/web/src/test/auto/headless/engine/js-processor/basic-init.tests.js b/web/src/test/auto/headless/engine/js-processor/basic-init.tests.js index 63fdeb9536a..29d6fb02de5 100644 --- a/web/src/test/auto/headless/engine/js-processor/basic-init.tests.js +++ b/web/src/test/auto/headless/engine/js-processor/basic-init.tests.js @@ -4,8 +4,7 @@ import { createRequire } from 'module'; const require = createRequire(import.meta.url); import { JSKeyboardProcessor } from 'keyman/engine/js-processor'; -import { NodeKeyboardLoader } from '../../../resources/loader/nodeKeyboardLoader.js'; -import { DEFAULT_PROCESSOR_INIT_OPTIONS } from '../../../resources/defaultProcessorInitOptions.js'; +import { DEFAULT_PROCESSOR_INIT_OPTIONS, NodeKeyboardLoader } from 'keyman/test/resources'; global.keyman = {}; // So that keyboard-based checks against the global `keyman` succeed. // 10.0+ dependent keyboards, like khmer_angkor, will otherwise fail to load. diff --git a/web/src/test/auto/headless/engine/js-processor/bundled-module.tests.js b/web/src/test/auto/headless/engine/js-processor/bundled-module.tests.js index a70cc14991a..40b78362ed8 100644 --- a/web/src/test/auto/headless/engine/js-processor/bundled-module.tests.js +++ b/web/src/test/auto/headless/engine/js-processor/bundled-module.tests.js @@ -1,14 +1,14 @@ import { assert } from "chai"; -import { DEFAULT_PROCESSOR_INIT_OPTIONS } from '../../../resources/defaultProcessorInitOptions.js'; -import * as JSProcessorModule from "keyman/engine/js-processor"; -import * as KeyboardModule from "keyman/engine/keyboard"; -const KMWString = KeyboardModule.KMWString; +import { DEFAULT_PROCESSOR_INIT_OPTIONS } from 'keyman/test/resources'; +import { JSKeyboardProcessor } from "keyman/engine/js-processor"; +import { JSKeyboard, SyntheticTextStore } from "keyman/engine/keyboard"; +import { KMWString, Version } from 'keyman/common/web-utils'; // A few small tests to ensure that the ES Module bundle was successfully constructed and is usable. -var toSupplementaryPairString = function(code){ - var H = Math.floor((code - 0x10000) / 0x400) + 0xD800; - var L = (code - 0x10000) % 0x400 + 0xDC00; +const toSupplementaryPairString = function(code){ + const H = Math.floor((code - 0x10000) / 0x400) + 0xD800; + const L = (code - 0x10000) % 0x400 + 0xDC00; return String.fromCharCode(H, L); } @@ -18,7 +18,7 @@ let u = toSupplementaryPairString; describe('Bundled ES Module for js-processor', function() { describe('JSKeyboardProcessor', function () { it('should initialize without errors', function () { - let kp = new JSProcessorModule.JSKeyboardProcessor(null, DEFAULT_PROCESSOR_INIT_OPTIONS); + let kp = new JSKeyboardProcessor(null, DEFAULT_PROCESSOR_INIT_OPTIONS); assert.isNotNull(kp); }); }); @@ -28,21 +28,21 @@ describe('Bundled ES Module for js-processor', function() { describe('Bundled ES Module for keyboard', function () { describe('Keyboard', function () { it('should initialize without errors', function () { - let kp = new KeyboardModule.JSKeyboard(); + let kp = new JSKeyboard(); assert.isNotNull(kp); }); }); describe("Imported `utils`", function () { it("should include `utils` package's Version class", () => { - let v16 = new KeyboardModule.Version([16, 1]); + let v16 = new Version([16, 1]); assert.equal(v16.toString(), "16.1"); }); }); describe('SyntheticTextStore', () => { it('basic functionality test', () => { - let textStore = new KeyboardModule.SyntheticTextStore("aple", 2); // ap | le + let textStore = new SyntheticTextStore("aple", 2); // ap | le textStore.insertTextBeforeCaret('p'); assert.equal(textStore.getText(), "apple"); }); @@ -50,7 +50,7 @@ describe('Bundled ES Module for keyboard', function () { it('smp test', () => { KMWString.enableSupplementaryPlane(true); // Declared & defined in web-utils. try { - let textStore = new KeyboardModule.SyntheticTextStore(u(0x1d5ba) + u(0x1d5c9) + u(0x1d5c5) + u(0x1d5be), 2); // ap | le + let textStore = new SyntheticTextStore(u(0x1d5ba) + u(0x1d5c9) + u(0x1d5c5) + u(0x1d5be), 2); // ap | le textStore.insertTextBeforeCaret(u(0x1d5c9)); assert.equal(textStore.getText(), u(0x1d5ba) + u(0x1d5c9) + u(0x1d5c9) + u(0x1d5c5) + u(0x1d5be)); } finally { diff --git a/web/src/test/auto/headless/engine/js-processor/chirality.tests.js b/web/src/test/auto/headless/engine/js-processor/chirality.tests.js index 1c7b48cdcc7..f99428c4134 100644 --- a/web/src/test/auto/headless/engine/js-processor/chirality.tests.js +++ b/web/src/test/auto/headless/engine/js-processor/chirality.tests.js @@ -6,12 +6,16 @@ const require = createRequire(import.meta.url); import { MinimalKeymanGlobal } from 'keyman/engine/keyboard'; import { JSKeyboardInterface } from 'keyman/engine/js-processor'; -import { NodeKeyboardLoader } from '../../../resources/loader/nodeKeyboardLoader.js'; +import { NodeKeyboardLoader } from 'keyman/test/resources'; import { KeyboardTest, NodeProctor } from '@keymanapp/recorder-core'; import { ModifierKeyConstants } from '@keymanapp/common-types'; import { env } from 'node:process'; -const KEYMAN_ROOT = env.KEYMAN_ROOT; +import { fileURLToPath } from 'node:url'; +import { dirname } from 'node:path'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const KEYMAN_ROOT = env.KEYMAN_ROOT ?? (__dirname + '/../../../../../../../'); describe('Engine - Chirality', function() { let testJSONtext = fs.readFileSync(require.resolve('@keymanapp/common-test-resources/json/engine_tests/chirality.json')); diff --git a/web/src/test/auto/headless/engine/js-processor/deadkeys.tests.js b/web/src/test/auto/headless/engine/js-processor/deadkeys.tests.js index 15bb2e824f6..e02fb1adaf7 100644 --- a/web/src/test/auto/headless/engine/js-processor/deadkeys.tests.js +++ b/web/src/test/auto/headless/engine/js-processor/deadkeys.tests.js @@ -6,11 +6,15 @@ const require = createRequire(import.meta.url); import { MinimalKeymanGlobal } from 'keyman/engine/keyboard'; import { JSKeyboardInterface } from 'keyman/engine/js-processor'; -import { NodeKeyboardLoader } from '../../../resources/loader/nodeKeyboardLoader.js'; +import { NodeKeyboardLoader } from 'keyman/test/resources'; import { KeyboardTest, NodeProctor } from '@keymanapp/recorder-core'; import { env } from 'node:process'; -const KEYMAN_ROOT = env.KEYMAN_ROOT; +import { fileURLToPath } from 'node:url'; +import { dirname } from 'node:path'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const KEYMAN_ROOT = env.KEYMAN_ROOT ?? (__dirname + '/../../../../../../../'); describe('Engine - Deadkeys', function() { let testJSONtext = fs.readFileSync(require.resolve('@keymanapp/common-test-resources/json/engine_tests/deadkeys.json')); diff --git a/web/src/test/auto/headless/engine/js-processor/engine/context.tests.js b/web/src/test/auto/headless/engine/js-processor/engine/context.tests.js index 0105eb4d95f..fa61b3feb38 100644 --- a/web/src/test/auto/headless/engine/js-processor/engine/context.tests.js +++ b/web/src/test/auto/headless/engine/js-processor/engine/context.tests.js @@ -5,8 +5,7 @@ const require = createRequire(import.meta.url); import { MinimalKeymanGlobal, SyntheticTextStore } from 'keyman/engine/keyboard'; import { JSKeyboardInterface, JSKeyboardProcessor } from 'keyman/engine/js-processor'; -import { NodeKeyboardLoader } from '../../../resources/loader/nodeKeyboardLoader.js'; -import { DEFAULT_PROCESSOR_INIT_OPTIONS } from '../../../resources/defaultProcessorInitOptions.js'; +import { DEFAULT_PROCESSOR_INIT_OPTIONS, NodeKeyboardLoader } from 'keyman/test/resources'; import { NodeProctor, RecordedKeystrokeSequence } from '@keymanapp/recorder-core'; diff --git a/web/src/test/auto/headless/engine/js-processor/engine/notany_context.tests.js b/web/src/test/auto/headless/engine/js-processor/engine/notany_context.tests.js index 4676860f2f2..edcbbd6492f 100644 --- a/web/src/test/auto/headless/engine/js-processor/engine/notany_context.tests.js +++ b/web/src/test/auto/headless/engine/js-processor/engine/notany_context.tests.js @@ -5,7 +5,7 @@ const require = createRequire(import.meta.url); import { MinimalKeymanGlobal, SyntheticTextStore } from 'keyman/engine/keyboard'; import { JSKeyboardInterface } from 'keyman/engine/js-processor'; -import { NodeKeyboardLoader } from '../../../resources/loader/nodeKeyboardLoader.js'; +import { NodeKeyboardLoader } from 'keyman/test/resources'; import { NodeProctor, RecordedKeystrokeSequence } from '@keymanapp/recorder-core'; const device = { diff --git a/web/src/test/auto/headless/engine/js-processor/engine/stores.tests.js b/web/src/test/auto/headless/engine/js-processor/engine/stores.tests.js index ebf2c976000..eeb976a0964 100644 --- a/web/src/test/auto/headless/engine/js-processor/engine/stores.tests.js +++ b/web/src/test/auto/headless/engine/js-processor/engine/stores.tests.js @@ -1,8 +1,9 @@ import { assert } from 'chai'; -import { JSKeyboard, KMWString } from 'keyman/engine/keyboard'; +import { KMWString } from 'keyman/common/web-utils'; +import { JSKeyboard } from 'keyman/engine/keyboard'; import { JSKeyboardProcessor } from 'keyman/engine/js-processor'; -import { DEFAULT_PROCESSOR_INIT_OPTIONS } from '../../../resources/defaultProcessorInitOptions.js'; +import { DEFAULT_PROCESSOR_INIT_OPTIONS } from 'keyman/test/resources'; let device = { formFactor: 'desktop', diff --git a/web/src/test/auto/headless/engine/js-processor/engine/unmatched_final_group.tests.js b/web/src/test/auto/headless/engine/js-processor/engine/unmatched_final_group.tests.js index 61fd93c3e0a..d558d898303 100644 --- a/web/src/test/auto/headless/engine/js-processor/engine/unmatched_final_group.tests.js +++ b/web/src/test/auto/headless/engine/js-processor/engine/unmatched_final_group.tests.js @@ -6,18 +6,22 @@ const require = createRequire(import.meta.url); import { MinimalKeymanGlobal } from 'keyman/engine/keyboard'; import { JSKeyboardInterface } from 'keyman/engine/js-processor'; -import { NodeKeyboardLoader } from '../../../resources/loader/nodeKeyboardLoader.js'; +import { NodeKeyboardLoader } from 'keyman/test/resources'; import { KeyboardTest, NodeProctor } from '@keymanapp/recorder-core'; import { env } from 'node:process'; -const KEYMAN_ROOT = env.KEYMAN_ROOT; +import { fileURLToPath } from 'node:url'; +import { dirname } from 'node:path'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const KEYMAN_ROOT = env.KEYMAN_ROOT ?? (__dirname + '/../../../../../../../../'); describe('Engine - Unmatched Final Groups', function() { let testJSONtext = fs.readFileSync(require.resolve('@keymanapp/common-test-resources/json/engine_tests/ghp_enter.json')); // Common test suite setup. let testSuite = new KeyboardTest(JSON.parse(testJSONtext)); - var keyboardWithHarness; + let keyboardWithHarness; let device = { formFactor: 'desktop', OS: 'windows', diff --git a/web/src/test/auto/headless/engine/js-processor/kbdInterface.tests.ts b/web/src/test/auto/headless/engine/js-processor/kbdInterface.tests.ts index a1cf76ca7aa..872697cc125 100644 --- a/web/src/test/auto/headless/engine/js-processor/kbdInterface.tests.ts +++ b/web/src/test/auto/headless/engine/js-processor/kbdInterface.tests.ts @@ -6,7 +6,7 @@ const require = createRequire(import.meta.url); import { DeviceSpec } from 'keyman/common/web-utils'; import { JSKeyboard, MinimalKeymanGlobal, SyntheticTextStore } from 'keyman/engine/keyboard'; import { JSKeyboardInterface } from 'keyman/engine/js-processor'; -import { NodeKeyboardLoader } from '../../../resources/loader/nodeKeyboardLoader.js'; +import { NodeKeyboardLoader } from 'keyman/test/resources'; describe('Headless keyboard loading', function () { const laoPath = require.resolve('@keymanapp/common-test-resources/keyboards/lao_2008_basic.js'); diff --git a/web/src/test/auto/headless/engine/js-processor/non-positional-rules.tests.js b/web/src/test/auto/headless/engine/js-processor/non-positional-rules.tests.js index 9a11fc686fe..53620b8b090 100644 --- a/web/src/test/auto/headless/engine/js-processor/non-positional-rules.tests.js +++ b/web/src/test/auto/headless/engine/js-processor/non-positional-rules.tests.js @@ -6,7 +6,7 @@ const require = createRequire(import.meta.url); import { Codes, KeyEvent, MinimalKeymanGlobal, SyntheticTextStore } from 'keyman/engine/keyboard'; import { JSKeyboardInterface } from 'keyman/engine/js-processor'; -import { NodeKeyboardLoader } from '../../../resources/loader/nodeKeyboardLoader.js'; +import { NodeKeyboardLoader } from 'keyman/test/resources'; // Compare and contrast the unit tests here with those for app/browser key-event unit testing // in the hardware-event-processing set; the output objects there should have the same format diff --git a/web/src/test/auto/headless/engine/js-processor/specialized-backspace.tests.js b/web/src/test/auto/headless/engine/js-processor/specialized-backspace.tests.ts similarity index 77% rename from web/src/test/auto/headless/engine/js-processor/specialized-backspace.tests.js rename to web/src/test/auto/headless/engine/js-processor/specialized-backspace.tests.ts index 4357cf59689..581b1810e00 100644 --- a/web/src/test/auto/headless/engine/js-processor/specialized-backspace.tests.js +++ b/web/src/test/auto/headless/engine/js-processor/specialized-backspace.tests.ts @@ -3,12 +3,11 @@ import { assert } from 'chai'; import { createRequire } from 'module'; const require = createRequire(import.meta.url); -import { KMWString } from 'keyman/common/web-utils'; -import { Codes, KeyEvent, MinimalKeymanGlobal, SyntheticTextStore } from 'keyman/engine/keyboard'; +import { DeviceSpec, KMWString } from 'keyman/common/web-utils'; +import { Codes, DefaultOutputRules, JSKeyboard, KeyEvent, MinimalKeymanGlobal, SyntheticTextStore } from 'keyman/engine/keyboard'; import { JSKeyboardInterface, JSKeyboardProcessor } from 'keyman/engine/js-processor'; -import { NodeKeyboardLoader } from '../../../resources/loader/nodeKeyboardLoader.js'; +import { NodeKeyboardLoader } from 'keyman/test/resources'; import { ModifierKeyConstants } from '@keymanapp/common-types'; -import { DEFAULT_PROCESSOR_INIT_OPTIONS } from '../../../resources/defaultProcessorInitOptions.js'; const TEST_DEVICE = { @@ -16,45 +15,56 @@ const TEST_DEVICE = { OS: 'windows', browser: 'native', touchable: false -} +} as DeviceSpec; // Basic scaffolding necessary to use special, locally-defined test keyboards. -const COMMON_KBD_SCRIPT_PROPS = new (function (){ - this.KMINVER="10.0"; +class CommonKbdScriptProps { + KMINVER = "10.0"; // this.KV left empty - we aren't doing layout stuff for this test, so it's "fine". // - also this.KV.KLS // - also this.KV.BK - this.KH=''; - this.KM=0; - this.KBVER="0.0.1"; - this.KMBM=ModifierKeyConstants.K_SHIFTFLAG /* 0x0010 */; - this.gs=function(t,e) { - return this.g_main(t,e); - }; -})(); + KH = ''; + KM = 0; + KBVER = "0.0.1"; + KMBM = ModifierKeyConstants.K_SHIFTFLAG /* 0x0010 */; + gs(t: any, e: any) { + return (this as any).g_main(t, e); + } +} + +const COMMON_KBD_SCRIPT_PROPS = new CommonKbdScriptProps(); -const DUMMIED_KEYS_KEYBOARD_SCRIPT = function keyboard_core () { +const DUMMIED_KEYS_KEYBOARD_SCRIPT = function keyboard_core (this: any) { Object.assign(this, COMMON_KBD_SCRIPT_PROPS); this.KI="Keyboard_dummied_keys"; this.KN="Dummied Keys"; - this.g_main=function(t,e) { + this.g_main=function(t:any, e:any) { // All keys match but do nothing. return 1; } + this.gs=function(t:any, e:any) { + return this.g_main(t, e); + } } -const DOUBLED_BKSP_KEYBOARD_SCRIPT = function keyboard_core () { +const DOUBLED_BKSP_KEYBOARD_SCRIPT = function keyboard_core (this: any) { Object.assign(this, COMMON_KBD_SCRIPT_PROPS); this.KI="Keyboard_doubled_backspace"; this.KN="Doubled Backspace"; - this.g_main=function(t,e) { - var k=KeymanWeb; + this.KO=function(count: number, t: any, output: string) { + // Delete 'count' characters from the text store and output the replacement + t.deleteCharsBeforeCaret(count); + if(output) { + t.insertTextBeforeCaret(output); + } + }; + this.g_main=function(t: { getTextBeforeCaret: () => string; }, e: { Lcode: number; }) { // Standard compiled keyboards do not directly use any methods on `t`. if(e.Lcode == Codes.keyCodes.K_BKSP && KMWString.length(t.getTextBeforeCaret()) >= 2){ // If the context has at least two characters, delete two. - k.KO(2, t, '') + this.KO(2, t, '') // Our rule matched, so signal that. return 1; } else { @@ -62,22 +72,26 @@ const DOUBLED_BKSP_KEYBOARD_SCRIPT = function keyboard_core () { return 0; } } + this.gs=function(t:any, e:any) { + return this.g_main(t, e); + } } describe('Engine - specialized backspace handling', function() { const ipaPath = require.resolve('@keymanapp/common-test-resources/keyboards/sil_ipa.js'); const angkorPath = require.resolve('@keymanapp/common-test-resources/keyboards/khmer_angkor.js'); - let device = { + const device = { formFactor: 'desktop', OS: 'windows', - browser: 'native' - } + browser: 'native', + touchable: false + } as DeviceSpec; - let ipaWithHarness; - let angkorWithHarness; - let dummiedWithHarness; - let bksp2xWithHarness; + let ipaWithHarness: JSKeyboardInterface; + let angkorWithHarness: JSKeyboardInterface; + let dummiedWithHarness: JSKeyboardInterface; + let bksp2xWithHarness: JSKeyboardInterface; before(async () => { // -- START: Standard keyboard unit test loading boilerplate -- @@ -89,7 +103,7 @@ describe('Engine - specialized backspace handling', function() { // This part provides extra assurance that the keyboard properly loaded. assert.equal(keyboard.id, "Keyboard_sil_ipa"); - harness.activeKeyboard = keyboard; + harness.activeKeyboard = keyboard as JSKeyboard; ipaWithHarness = harness; // -------------- @@ -103,7 +117,7 @@ describe('Engine - specialized backspace handling', function() { // This part provides extra assurance that the keyboard properly loaded. assert.equal(keyboard.id, "Keyboard_khmer_angkor"); - harness.activeKeyboard = keyboard; + harness.activeKeyboard = keyboard as JSKeyboard; angkorWithHarness = harness; // -------------- @@ -111,7 +125,7 @@ describe('Engine - specialized backspace handling', function() { harness = new JSKeyboardInterface(globalThis, MinimalKeymanGlobal); harness.install(); // Sets the keyboard as the harness's "loaded" keyboard, but not "active". - harness.KR(new DUMMIED_KEYS_KEYBOARD_SCRIPT()); + harness.KR(new (DUMMIED_KEYS_KEYBOARD_SCRIPT as any)()); harness.activeKeyboard = harness.loadedKeyboard; assert.isOk(harness.activeKeyboard); dummiedWithHarness = harness; @@ -121,27 +135,29 @@ describe('Engine - specialized backspace handling', function() { harness = new JSKeyboardInterface(globalThis, MinimalKeymanGlobal); harness.install(); // Sets the keyboard as the harness's "loaded" keyboard, but not "active". - harness.KR(new DOUBLED_BKSP_KEYBOARD_SCRIPT()); + harness.KR(new (DOUBLED_BKSP_KEYBOARD_SCRIPT as any)()); harness.activeKeyboard = harness.loadedKeyboard; assert.isOk(harness.activeKeyboard); bksp2xWithHarness = harness; }); it('empty context, positional keyboard', () => { - let contextSource = new SyntheticTextStore(''); - let event = new KeyEvent({ + const contextSource = new SyntheticTextStore(''); + const event = new KeyEvent({ Lcode: Codes.keyCodes.K_BKSP, Lmodifiers: 0, Lstates: ModifierKeyConstants.NOTCAPITALFLAG | ModifierKeyConstants.NOTNUMLOCKFLAG | ModifierKeyConstants.NOTSCROLLFLAG, LisVirtualKey: true, kName: '', vkCode: Codes.keyCodes.K_BKSP, - device: device + device }); const processor = new JSKeyboardProcessor(TEST_DEVICE, { - keyboardInterface: angkorWithHarness - }, DEFAULT_PROCESSOR_INIT_OPTIONS); + baseLayout: 'us', + keyboardInterface: angkorWithHarness, + defaultOutputRules: new DefaultOutputRules() + }); const result = processor.processKeystroke(event, contextSource); assert.isTrue(result.triggerKeyDefault); @@ -156,8 +172,8 @@ describe('Engine - specialized backspace handling', function() { }); it("empty context, positional keyboard, outputless-key that's not BKSP", () => { - let contextSource = new SyntheticTextStore(''); - let event = new KeyEvent({ + const contextSource = new SyntheticTextStore(''); + const event = new KeyEvent({ Lcode: Codes.keyCodes.K_A, Lmodifiers: 0, Lstates: ModifierKeyConstants.NOTCAPITALFLAG | ModifierKeyConstants.NOTNUMLOCKFLAG | ModifierKeyConstants.NOTSCROLLFLAG, @@ -171,8 +187,10 @@ describe('Engine - specialized backspace handling', function() { // We want to ensure error cases without output, on null context, don't act // like backspaces. const processor = new JSKeyboardProcessor(TEST_DEVICE, { - keyboardInterface: dummiedWithHarness - }, DEFAULT_PROCESSOR_INIT_OPTIONS); + baseLayout: 'us', + keyboardInterface: dummiedWithHarness, + defaultOutputRules: new DefaultOutputRules() + }); const result = processor.processKeystroke(event, contextSource); // Did match a keyboard rule. @@ -189,10 +207,10 @@ describe('Engine - specialized backspace handling', function() { }); it('empty context, positional keyboard, but text is selected', () => { - let contextSource = new SyntheticTextStore('selected text', 0); + const contextSource = new SyntheticTextStore('selected text', 0); contextSource.setSelection(0, KMWString.length(contextSource.getText())); - let event = new KeyEvent({ + const event = new KeyEvent({ Lcode: Codes.keyCodes.K_BKSP, Lmodifiers: 0, Lstates: ModifierKeyConstants.NOTCAPITALFLAG | ModifierKeyConstants.NOTNUMLOCKFLAG | ModifierKeyConstants.NOTSCROLLFLAG, @@ -203,8 +221,10 @@ describe('Engine - specialized backspace handling', function() { }); const processor = new JSKeyboardProcessor(TEST_DEVICE, { - keyboardInterface: angkorWithHarness - }, DEFAULT_PROCESSOR_INIT_OPTIONS); + baseLayout: 'us', + keyboardInterface: angkorWithHarness, + defaultOutputRules: new DefaultOutputRules() + }); const result = processor.processKeystroke(event, contextSource); assert.isFalse(result.triggerKeyDefault); @@ -226,8 +246,8 @@ describe('Engine - specialized backspace handling', function() { }); it('empty left-context, positional keyboard', () => { - let contextSource = new SyntheticTextStore('post-caret text', 0); - let event = new KeyEvent({ + const contextSource = new SyntheticTextStore('post-caret text', 0); + const event = new KeyEvent({ Lcode: Codes.keyCodes.K_BKSP, Lmodifiers: 0, Lstates: ModifierKeyConstants.NOTCAPITALFLAG | ModifierKeyConstants.NOTNUMLOCKFLAG | ModifierKeyConstants.NOTSCROLLFLAG, @@ -238,8 +258,10 @@ describe('Engine - specialized backspace handling', function() { }); const processor = new JSKeyboardProcessor(TEST_DEVICE, { - keyboardInterface: angkorWithHarness - }, DEFAULT_PROCESSOR_INIT_OPTIONS); + baseLayout: 'us', + keyboardInterface: angkorWithHarness, + defaultOutputRules: new DefaultOutputRules() + }); const result = processor.processKeystroke(event, contextSource); assert.isTrue(result.triggerKeyDefault); @@ -254,8 +276,8 @@ describe('Engine - specialized backspace handling', function() { }); it('empty context, mnemonic keyboard', () => { - let contextSource = new SyntheticTextStore(''); - let event = new KeyEvent({ + const contextSource = new SyntheticTextStore(''); + const event = new KeyEvent({ Lcode: Codes.keyCodes.K_BKSP, Lmodifiers: 0, Lstates: ModifierKeyConstants.NOTCAPITALFLAG | ModifierKeyConstants.NOTNUMLOCKFLAG | ModifierKeyConstants.NOTSCROLLFLAG, @@ -266,8 +288,10 @@ describe('Engine - specialized backspace handling', function() { }); const processor = new JSKeyboardProcessor(TEST_DEVICE, { - keyboardInterface: ipaWithHarness - }, DEFAULT_PROCESSOR_INIT_OPTIONS); + baseLayout: 'us', + keyboardInterface: ipaWithHarness, + defaultOutputRules: new DefaultOutputRules() + }); const result = processor.processKeystroke(event, contextSource); assert.isTrue(result.triggerKeyDefault); @@ -282,8 +306,8 @@ describe('Engine - specialized backspace handling', function() { }); it('final empty context, positional keyboard, rule-handled BKSP', () => { - let contextSource = new SyntheticTextStore('abc', 2); - let event = new KeyEvent({ + const contextSource = new SyntheticTextStore('abc', 2); + const event = new KeyEvent({ Lcode: Codes.keyCodes.K_BKSP, Lmodifiers: 0, Lstates: ModifierKeyConstants.NOTCAPITALFLAG | ModifierKeyConstants.NOTNUMLOCKFLAG | ModifierKeyConstants.NOTSCROLLFLAG, @@ -297,8 +321,10 @@ describe('Engine - specialized backspace handling', function() { // context exists. const processor = new JSKeyboardProcessor(TEST_DEVICE, { - keyboardInterface: bksp2xWithHarness - }, DEFAULT_PROCESSOR_INIT_OPTIONS); + baseLayout: 'us', + keyboardInterface: bksp2xWithHarness, + defaultOutputRules: new DefaultOutputRules() + }); const result = processor.processKeystroke(event, contextSource); // Did match a keyboard rule. @@ -317,8 +343,8 @@ describe('Engine - specialized backspace handling', function() { // Special case: BKSP rule-matches with empty left-context. it("empty context, positional keyboard, outputless BKSP rule", () => { - let contextSource = new SyntheticTextStore(''); - let event = new KeyEvent({ + const contextSource = new SyntheticTextStore(''); + const event = new KeyEvent({ Lcode: Codes.keyCodes.K_BKSP, Lmodifiers: 0, Lstates: ModifierKeyConstants.NOTCAPITALFLAG | ModifierKeyConstants.NOTNUMLOCKFLAG | ModifierKeyConstants.NOTSCROLLFLAG, @@ -332,8 +358,10 @@ describe('Engine - specialized backspace handling', function() { // We want to ensure error cases without output, on null context, don't act // like backspaces. const processor = new JSKeyboardProcessor(TEST_DEVICE, { - keyboardInterface: dummiedWithHarness - }, DEFAULT_PROCESSOR_INIT_OPTIONS); + baseLayout: 'us', + keyboardInterface: dummiedWithHarness, + defaultOutputRules: new DefaultOutputRules() + }); const result = processor.processKeystroke(event, contextSource); assert.isFalse(result.triggerKeyDefault); diff --git a/web/src/test/auto/headless/engine/js-processor/transcriptions.tests.js b/web/src/test/auto/headless/engine/js-processor/transcriptions.tests.js index 6275d800612..ab1403f2fa6 100644 --- a/web/src/test/auto/headless/engine/js-processor/transcriptions.tests.js +++ b/web/src/test/auto/headless/engine/js-processor/transcriptions.tests.js @@ -175,8 +175,8 @@ describe("Transcriptions and Transforms", function() { it("handles context-free single-char output rules", function() { // We have other texts validating SyntheticTextStores; by using them as our base 'element', this unit test file // could eventually run in 'headless' mode. - const textStore = new SyntheticTextStore("apple"); - const originalTextStore = SyntheticTextStore.from(textStore); + let textStore = new SyntheticTextStore("apple"); + let originalTextStore = SyntheticTextStore.from(textStore); textStore.insertTextBeforeCaret("s"); /* It's not exactly black box, but presently we don't NEED the keyEvent object for the method to work. @@ -441,7 +441,7 @@ but not himself.`; // Sheev Palpatine, in the Star Wars prequels. const originalTextStore = SyntheticTextStore.from(textStore); textStore.clearSelection(); - const transform = textStore.textStore(originalTextStore); + const transform = textStore.buildTransformFrom(originalTextStore); assert.deepEqual(transform, { insert: '', deleteLeft: 0, diff --git a/web/src/test/auto/headless/engine/keyboard-storage/cloudQueries.tests.js b/web/src/test/auto/headless/engine/keyboard-storage/cloudQueries.tests.js index 7892178dfc0..2033794572f 100644 --- a/web/src/test/auto/headless/engine/keyboard-storage/cloudQueries.tests.js +++ b/web/src/test/auto/headless/engine/keyboard-storage/cloudQueries.tests.js @@ -2,9 +2,9 @@ import { assert } from 'chai'; import sinon from 'sinon'; import { ManagedPromise } from 'keyman/common/web-utils'; -import { CloudQueryEngine, StubAndKeyboardCache, toPrefixedKeyboardId as prefixed } from 'keyman/engine/keyboard-storage'; +import { CloudQueryEngine, toPrefixedKeyboardId as prefixed } from 'keyman/engine/keyboard-storage'; import { PathConfiguration } from 'keyman/engine/interfaces'; -import NodeCloudRequester from '../../../resources/loader/nodeCloudRequester.js'; +import { NodeCloudRequester } from 'keyman/test/resources'; import path from 'path'; import { fileURLToPath } from 'url'; diff --git a/web/src/test/auto/headless/engine/keyboard-storage/keyboardRequisitioner.tests.js b/web/src/test/auto/headless/engine/keyboard-storage/keyboardRequisitioner.tests.js index ee93c0eb99f..5d740b7c1c4 100644 --- a/web/src/test/auto/headless/engine/keyboard-storage/keyboardRequisitioner.tests.js +++ b/web/src/test/auto/headless/engine/keyboard-storage/keyboardRequisitioner.tests.js @@ -2,14 +2,11 @@ import { assert } from 'chai'; import sinon from 'sinon'; import fs from 'fs'; -import { KeyboardHarness, ManagedPromise, MinimalKeymanGlobal } from 'keyman/engine/keyboard'; -import { NodeKeyboardLoader } from '../../../resources/loader/nodeKeyboardLoader.js'; -import { - KeyboardRequisitioner, - toPrefixedKeyboardId as prefixed -} from 'keyman/engine/keyboard-storage'; +import { ManagedPromise } from 'keyman/common/web-utils'; +import { KeyboardHarness, MinimalKeymanGlobal } from 'keyman/engine/keyboard'; +import { NodeKeyboardLoader, NodeCloudRequester } from 'keyman/test/resources'; +import { KeyboardRequisitioner, toPrefixedKeyboardId } from 'keyman/engine/keyboard-storage'; import { PathConfiguration } from 'keyman/engine/interfaces'; -import NodeCloudRequester from '../../../resources/loader/nodeCloudRequester.js'; import path from 'path'; import { fileURLToPath } from 'url'; @@ -197,7 +194,7 @@ describe("KeyboardRequisitioner", () => { assert.equal(stubs.length, 2); for(let stub of stubs) { - assert.equal(stub.KI, prefixed('sil_euro_latin')); + assert.equal(stub.KI, toPrefixedKeyboardId('sil_euro_latin')); assert.equal(stub.KN, "EuroLatin (SIL)"); } @@ -216,7 +213,7 @@ describe("KeyboardRequisitioner", () => { assert.equal(stubs.length, 278); for(let stub of stubs) { - assert.equal(stub.KI, prefixed('sil_cameroon_azerty')); + assert.equal(stub.KI, toPrefixedKeyboardId('sil_cameroon_azerty')); assert.equal(stub.KN, "Cameroon AZERTY"); } diff --git a/web/src/test/auto/headless/engine/keyboard-storage/keyboardStub.tests.js b/web/src/test/auto/headless/engine/keyboard-storage/keyboardStub.tests.js index 96b67828922..40a3f17827d 100644 --- a/web/src/test/auto/headless/engine/keyboard-storage/keyboardStub.tests.js +++ b/web/src/test/auto/headless/engine/keyboard-storage/keyboardStub.tests.js @@ -2,7 +2,7 @@ import { assert } from 'chai'; import sinon from 'sinon'; import { KeyboardStub } from 'keyman/engine/keyboard-storage'; -import NodeCloudRequester from '../../../resources/loader/nodeCloudRequester.js'; +import { NodeCloudRequester } from 'keyman/test/resources'; import path from 'path'; import { fileURLToPath } from 'url'; diff --git a/web/src/test/auto/headless/engine/keyboard-storage/nodeCloudRequester.tests.js b/web/src/test/auto/headless/engine/keyboard-storage/nodeCloudRequester.tests.js index 468906b1fc6..7659495da34 100644 --- a/web/src/test/auto/headless/engine/keyboard-storage/nodeCloudRequester.tests.js +++ b/web/src/test/auto/headless/engine/keyboard-storage/nodeCloudRequester.tests.js @@ -1,7 +1,7 @@ import { assert } from 'chai'; import sinon from 'sinon'; -import NodeCloudRequester from '../../../resources/loader/nodeCloudRequester.js'; +import { NodeCloudRequester } from 'keyman/test/resources'; import path from 'path'; import { fileURLToPath } from 'url'; diff --git a/web/src/test/auto/headless/engine/keyboard-storage/stubAndKeyboardCache.tests.js b/web/src/test/auto/headless/engine/keyboard-storage/stubAndKeyboardCache.tests.js index 9b120d01e63..106c76b202e 100644 --- a/web/src/test/auto/headless/engine/keyboard-storage/stubAndKeyboardCache.tests.js +++ b/web/src/test/auto/headless/engine/keyboard-storage/stubAndKeyboardCache.tests.js @@ -4,7 +4,7 @@ import fs from 'fs'; import { KeyboardStub, StubAndKeyboardCache } from 'keyman/engine/keyboard-storage'; -import { NodeKeyboardLoader } from '../../../resources/loader/nodeKeyboardLoader.js'; +import { NodeKeyboardLoader } from 'keyman/test/resources'; import { KeyboardHarness, MinimalKeymanGlobal } from 'keyman/engine/keyboard'; import path from 'path'; diff --git a/web/src/test/auto/headless/engine/keyboard/keyboard-loading.tests.js b/web/src/test/auto/headless/engine/keyboard/keyboard-loading.tests.js index e4c206d5f50..62a145f392f 100644 --- a/web/src/test/auto/headless/engine/keyboard/keyboard-loading.tests.js +++ b/web/src/test/auto/headless/engine/keyboard/keyboard-loading.tests.js @@ -5,7 +5,7 @@ const require = createRequire(import.meta.url); import { KeyboardHarness, MinimalKeymanGlobal, SyntheticTextStore } from 'keyman/engine/keyboard'; import { JSKeyboardInterface } from 'keyman/engine/js-processor'; -import { NodeKeyboardLoader } from '../../../resources/loader/nodeKeyboardLoader.js'; +import { NodeKeyboardLoader } from 'keyman/test/resources'; describe('Headless keyboard loading', function() { const laoPath = require.resolve('@keymanapp/common-test-resources/keyboards/lao_2008_basic.js'); diff --git a/web/src/test/auto/headless/engine/keyboard/keyboard.tests.ts b/web/src/test/auto/headless/engine/keyboard/keyboard.tests.ts index aae762bc703..ddd4e9e2e40 100644 --- a/web/src/test/auto/headless/engine/keyboard/keyboard.tests.ts +++ b/web/src/test/auto/headless/engine/keyboard/keyboard.tests.ts @@ -5,7 +5,7 @@ const require = createRequire(import.meta.url); import { DeviceSpec } from 'keyman/common/web-utils'; import { KeyboardHarness, MinimalKeymanGlobal, JSKeyboard } from 'keyman/engine/keyboard'; -import { NodeKeyboardLoader } from '../../../resources/loader/nodeKeyboardLoader.js'; +import { NodeKeyboardLoader } from 'keyman/test/resources'; describe('Keyboard tests', function () { diff --git a/web/src/test/auto/headless/engine/keyboard/keyboardLoaderBase.tests.ts b/web/src/test/auto/headless/engine/keyboard/keyboardLoaderBase.tests.ts index a5d4cad68d2..62b0e7319bd 100644 --- a/web/src/test/auto/headless/engine/keyboard/keyboardLoaderBase.tests.ts +++ b/web/src/test/auto/headless/engine/keyboard/keyboardLoaderBase.tests.ts @@ -6,7 +6,7 @@ const require = createRequire(import.meta.url); import { DeviceSpec } from 'keyman/common/web-utils'; import { KeyboardHarness, MinimalKeymanGlobal, KeyboardDownloadError, InvalidKeyboardError, JSKeyboard, SyntheticTextStore } from 'keyman/engine/keyboard'; import { JSKeyboardInterface } from 'keyman/engine/js-processor'; -import { NodeKeyboardLoader } from '../../../resources/loader/nodeKeyboardLoader.js'; +import { NodeKeyboardLoader } from 'keyman/test/resources'; import { assertThrowsAsync, assertThrows } from 'keyman/tools/testing/test-utils'; describe('Headless keyboard loading', function() { diff --git a/web/src/test/auto/headless/engine/main/headless/inputProcessor.tests.js b/web/src/test/auto/headless/engine/main/headless/inputProcessor.tests.js index c871be3b0fb..85a5c262462 100644 --- a/web/src/test/auto/headless/engine/main/headless/inputProcessor.tests.js +++ b/web/src/test/auto/headless/engine/main/headless/inputProcessor.tests.js @@ -6,11 +6,11 @@ const require = createRequire(import.meta.url); import { InputProcessor } from 'keyman/engine/main'; import { JSKeyboardInterface } from 'keyman/engine/js-processor'; -import { MinimalKeymanGlobal, SyntheticTextStore } from 'keyman/engine/keyboard'; -import { NodeKeyboardLoader } from '../../../resources/loader/nodeKeyboardLoader.js'; +import { DefaultOutputRules, MinimalKeymanGlobal, SyntheticTextStore } from 'keyman/engine/keyboard'; +import { DEFAULT_PROCESSOR_INIT_OPTIONS, NodeKeyboardLoader } from 'keyman/test/resources'; import { KeyboardTest } from '@keymanapp/recorder-core'; -import { Worker } from '@keymanapp/lexical-model-layer/node'; +import { NodeWorker } from '@keymanapp/lexical-model-layer/node'; import * as utils from 'keyman/common/web-utils'; const KMWString = utils.KMWString; @@ -31,7 +31,7 @@ KMWString.enableSupplementaryPlane(false); describe('InputProcessor', function() { describe('[[constructor]]', function () { it('should initialize without errors', function () { - let core = new InputProcessor(device); + let core = new InputProcessor(device, null, DEFAULT_PROCESSOR_INIT_OPTIONS); assert.isNotNull(core); }); @@ -40,7 +40,11 @@ describe('InputProcessor', function() { try { // Can construct without the second parameter; if so, the final assertion - .mayPredict // will be invalidated. (No worker, no ability to predict.) - core = new InputProcessor(device, Worker); + core = new InputProcessor(device, NodeWorker, { + baseLayout: 'us', + keyboardInterface: new JSKeyboardInterface({}, null, null), + defaultOutputRules: new DefaultOutputRules() + }); assert.isOk(core.keyboardProcessor); assert.isDefined(core.keyboardProcessor.contextDevice); @@ -103,7 +107,7 @@ describe('InputProcessor', function() { describe('without fat-fingering', function() { it('with minimal context (no fat-fingers)', function() { this.timeout(32); // ms - let core = new InputProcessor(device); + let core = new InputProcessor(device, null, DEFAULT_PROCESSOR_INIT_OPTIONS); let context = new SyntheticTextStore("", 0); core.keyboardProcessor.keyboardInterface = keyboardWithHarness; @@ -123,7 +127,7 @@ describe('InputProcessor', function() { this.timeout(500); // 500 ms, excluding text import. // These often run on VMs, so we'll be a bit generous. - let core = new InputProcessor(device); // I mean, it IS long context, and time + let core = new InputProcessor(device, null, DEFAULT_PROCESSOR_INIT_OPTIONS); // I mean, it IS long context, and time // thresholding is disabled within Node. core.keyboardProcessor.keyboardInterface = keyboardWithHarness; @@ -140,7 +144,7 @@ describe('InputProcessor', function() { describe('with fat-fingering', function() { it('with minimal context (with fat-fingers)', function() { this.timeout(32); // ms - let core = new InputProcessor(device); + let core = new InputProcessor(device, null, DEFAULT_PROCESSOR_INIT_OPTIONS); let context = new SyntheticTextStore("", 0); core.keyboardProcessor.keyboardInterface = keyboardWithHarness; @@ -164,7 +168,7 @@ describe('InputProcessor', function() { // Keep at the same 'order of magnitude' as the // 'without fat-fingers' test. - let core = new InputProcessor(device); // It IS long context, and time + let core = new InputProcessor(device, null, DEFAULT_PROCESSOR_INIT_OPTIONS); // It IS long context, and time // thresholding is disabled within Node. core.keyboardProcessor.keyboardInterface = keyboardWithHarness; @@ -201,7 +205,7 @@ describe('InputProcessor', function() { for (let testSet of testDefinitions.inputTestSets[0]['testSet']) { it(testSet.msg ?? 'test', function() { this.timeout(32); // ms - let core = new InputProcessor(device); + let core = new InputProcessor(device, null, DEFAULT_PROCESSOR_INIT_OPTIONS); let context = new SyntheticTextStore("", 0); core.keyboardProcessor.keyboardInterface = keyboardWithHarness; diff --git a/web/src/test/auto/headless/engine/main/headless/languageProcessor.tests.js b/web/src/test/auto/headless/engine/main/headless/languageProcessor.tests.js index a8b524f6b2e..13f6458c6c3 100644 --- a/web/src/test/auto/headless/engine/main/headless/languageProcessor.tests.js +++ b/web/src/test/auto/headless/engine/main/headless/languageProcessor.tests.js @@ -13,7 +13,11 @@ import path from 'path'; import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers'; import { env } from 'node:process'; -const KEYMAN_ROOT = env.KEYMAN_ROOT; +import { fileURLToPath } from 'node:url'; +import { dirname } from 'node:path'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const KEYMAN_ROOT = env.KEYMAN_ROOT ?? (__dirname + '/../../../../../../../../'); // Required initialization setup. global.keyman = {}; // So that keyboard-based checks against the global `keyman` succeed. diff --git a/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/gestureMatcher.tests.ts b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/gestureMatcher.tests.ts index a06ae76657d..4211c4573a5 100644 --- a/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/gestureMatcher.tests.ts +++ b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/gestureMatcher.tests.ts @@ -2,14 +2,13 @@ import { assert } from 'chai' import sinon from 'sinon'; import * as PromiseStatusModule from 'promise-status-async'; -const PromiseStatuses = PromiseStatusModule.PromiseStatuses; -import { assertingPromiseStatus as promiseStatus } from '../../../../../resources/assertingPromiseStatus.js'; +const PromiseStatuses = PromiseStatusModule.PromiseStatuses; import { InputSample, gestures, GestureDebugPath } from 'keyman/engine/gesture-processor'; import { TouchpathTurtle } from '#gesture-tools'; -import { simulateMultiSourceMatcherInput } from "../../../../../resources/simulateMultiSourceInput.js"; +import { assertingPromiseStatus as promiseStatus, simulateMultiSourceMatcherInput } from 'keyman/test/resources'; import { FlickEndModel, diff --git a/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/gestureSequence.tests.ts b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/gestureSequence.tests.ts index 2b0fbd32ded..8460a640f6a 100644 --- a/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/gestureSequence.tests.ts +++ b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/gestureSequence.tests.ts @@ -2,7 +2,6 @@ import { assert } from 'chai' import sinon from 'sinon'; import * as PromiseStatusModule from 'promise-status-async'; -import { assertingPromiseStatus as promiseStatus } from '../../../../../resources/assertingPromiseStatus.js'; import { GestureModelDefs, buildGestureMatchInspector, gestures } from 'keyman/engine/gesture-processor'; const { matchers } = gestures; @@ -19,7 +18,7 @@ const modelSetForAction = gestures.matchers.modelSetForAction; import { HeadlessInputEngine, TouchpathTurtle } from '#gesture-tools'; import { ManagedPromise, timedPromise } from 'keyman/common/web-utils'; -import { assertGestureSequence, SequenceAssertion } from "../../../../../resources/sequenceAssertions.js"; +import { assertingPromiseStatus as promiseStatus, assertGestureSequence, SequenceAssertion } from 'keyman/test/resources'; import { LongpressModel, diff --git a/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/matcherSelector.tests.ts b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/matcherSelector.tests.ts index 9ed3b846a07..51c69d8f5c3 100644 --- a/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/matcherSelector.tests.ts +++ b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/matcherSelector.tests.ts @@ -3,9 +3,8 @@ import sinon from 'sinon'; import * as PromiseStatusModule from 'promise-status-async'; const PromiseStatuses = PromiseStatusModule.PromiseStatuses; -import { assertingPromiseStatus as promiseStatus } from '../../../../../resources/assertingPromiseStatus.js'; -import { simulateMultiSourceMatcherInput, simulateSelectorInput } from "../../../../../resources/simulateMultiSourceInput.js"; +import { assertingPromiseStatus as promiseStatus, simulateMultiSourceMatcherInput, simulateSelectorInput } from 'keyman/test/resources'; import { timedPromise } from 'keyman/common/web-utils'; import { gestures } from 'keyman/engine/gesture-processor'; diff --git a/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/pathMatcher.tests.ts b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/pathMatcher.tests.ts index 703057edb1e..c9ad7bdef54 100644 --- a/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/pathMatcher.tests.ts +++ b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/pathMatcher.tests.ts @@ -3,7 +3,7 @@ import sinon from 'sinon'; import * as PromiseStatusModule from 'promise-status-async'; const PromiseStatuses = PromiseStatusModule.PromiseStatuses; -import { assertingPromiseStatus as promiseStatus } from '../../../../../resources/assertingPromiseStatus.js'; +import { assertingPromiseStatus as promiseStatus } from 'keyman/test/resources'; import { InputSample, GestureSource, gestures, CumulativePathStats } from 'keyman/engine/gesture-processor'; import { timedPromise } from 'keyman/common/web-utils'; diff --git a/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/touchpointCoordinator.tests.ts b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/touchpointCoordinator.tests.ts index 0deb01224cf..a37a27871a6 100644 --- a/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/touchpointCoordinator.tests.ts +++ b/web/src/test/auto/headless/engine/osk/gesture-processor/gestures/touchpointCoordinator.tests.ts @@ -2,7 +2,7 @@ import { assert } from 'chai' import sinon from 'sinon'; import * as PromiseStatusModule from 'promise-status-async'; -import { assertingPromiseStatus as promiseStatus } from '../../../../../resources/assertingPromiseStatus.js'; +import { assertingPromiseStatus as promiseStatus, assertGestureSequence, SequenceAssertion } from 'keyman/test/resources'; import { GestureModelDefs, GestureSource, gestures, TouchpointCoordinator } from 'keyman/engine/gesture-processor'; const { matchers } = gestures; @@ -14,8 +14,6 @@ type GestureSequence = gestures.matchers.GestureSequence; import { HeadlessInputEngine, TouchpathTurtle } from '#gesture-tools'; import { ManagedPromise, timedPromise } from 'keyman/common/web-utils'; -import { assertGestureSequence, SequenceAssertion } from "../../../../../resources/sequenceAssertions.js"; - import { LongpressModel, ModipressEndModel, diff --git a/web/src/test/auto/resources/index.ts b/web/src/test/auto/resources/index.ts new file mode 100644 index 00000000000..8c176d04b3a --- /dev/null +++ b/web/src/test/auto/resources/index.ts @@ -0,0 +1,6 @@ +export { assertingPromiseStatus } from './assertingPromiseStatus.js'; +export { DEFAULT_PROCESSOR_INIT_OPTIONS } from './defaultProcessorInitOptions.js'; +export { NodeKeyboardLoader } from './loader/nodeKeyboardLoader.js'; +export { NodeCloudRequester } from './loader/nodeCloudRequester.js'; +export { StageReportAssertion, SequenceAssertion, assertGestureSequence } from './sequenceAssertions.js'; +export { simulateMultiSourceMatcherInput, simulateSelectorInput } from './simulateMultiSourceInput.js'; \ No newline at end of file diff --git a/web/src/test/auto/resources/loader/node-keyboard-loader.ts b/web/src/test/auto/resources/loader/node-keyboard-loader.ts deleted file mode 100644 index 9630e113b01..00000000000 --- a/web/src/test/auto/resources/loader/node-keyboard-loader.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './nodeKeyboardLoader.js'; \ No newline at end of file diff --git a/web/src/test/auto/resources/loader/nodeCloudRequester.ts b/web/src/test/auto/resources/loader/nodeCloudRequester.ts index cd287eb407b..2e654971f38 100644 --- a/web/src/test/auto/resources/loader/nodeCloudRequester.ts +++ b/web/src/test/auto/resources/loader/nodeCloudRequester.ts @@ -1,17 +1,16 @@ import { ManagedPromise } from 'keyman/common/web-utils'; -import { CloudRequesterInterface } from '../../../../engine/src/keyboard-storage/cloud/requesterInterface.js'; import { - CLOUD_TIMEOUT_ERR, - CLOUD_STUB_REGISTRATION_ERR, + CloudRequesterInterface, CloudQueryResult, - CloudQueryEngine -} from '../../../../engine/src/keyboard-storage/cloud/queryEngine.js'; + CloudQueryEngine, + unitTestEndpoints +} from 'keyman/engine/keyboard-storage'; import fs from 'node:fs'; import https from 'node:https'; import vm from 'node:vm'; -export default class NodeCloudRequester implements CloudRequesterInterface { +export class NodeCloudRequester implements CloudRequesterInterface { private static QUERY_SEED = 1; private readonly fileLocal: boolean; @@ -34,7 +33,7 @@ export default class NodeCloudRequester implements CloudRequesterInterface { // Set callback timer const timeoutObj = setTimeout(() => { - promise.reject(new Error(CLOUD_TIMEOUT_ERR)); + promise.reject(new Error(unitTestEndpoints.CLOUD_TIMEOUT_ERR)); }, 10000); const queryId = NodeCloudRequester.QUERY_SEED++; @@ -56,7 +55,7 @@ export default class NodeCloudRequester implements CloudRequesterInterface { }); if(!promise.isResolved) { - promise.reject(new Error(CLOUD_STUB_REGISTRATION_ERR)); + promise.reject(new Error(unitTestEndpoints.CLOUD_STUB_REGISTRATION_ERR)); } } diff --git a/web/src/test/auto/resources/loader/tsconfig.node.json b/web/src/test/auto/resources/loader/tsconfig.node.json deleted file mode 100644 index 0f657843ac3..00000000000 --- a/web/src/test/auto/resources/loader/tsconfig.node.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../../../../../../tsconfig.base.json", - "compilerOptions": { - "types": [ "node" ], - "outDir": "../../../../../../build/engine/keyboard/obj/keyboards/loaders/", - "tsBuildInfoFile": "../../../../../../build/engine/keyboard/obj/keyboards/loaders/tsconfig.node.tsbuildinfo", - "rootDir": "." - }, - "references": [ - { "path": "../../../tsconfig.json" } - ], - "include": ["node-keyboard-loader.ts", "nodeKeyboardLoader.ts"], -} diff --git a/web/src/test/auto/resources/simulateMultiSourceInput.ts b/web/src/test/auto/resources/simulateMultiSourceInput.ts index cf7c2516cdc..452cec92856 100644 --- a/web/src/test/auto/resources/simulateMultiSourceInput.ts +++ b/web/src/test/auto/resources/simulateMultiSourceInput.ts @@ -247,7 +247,7 @@ function simulateMultiSourceInput( // ------- - let flattenedSpecs = processedSetup.map( + const flattenedSpecs = processedSetup.map( (entry) => entry.sourceSpecs ).reduce((constructingArray, entries) => constructingArray.concat(entries), []); @@ -365,7 +365,7 @@ export function simulateSelectorInput( selectorPromise: Promise>, executor: () => Promise } { - let inputClone = [].concat(input); + const inputClone = [].concat(input); // We NEED the sequences specified to be in chronological order of their start. // We'll just check if it's done properly out-of-the-gate - by sorting a clone, then comparing. diff --git a/web/src/test/auto/resources/tsconfig.json b/web/src/test/auto/resources/tsconfig.json new file mode 100644 index 00000000000..7ed8bfc57e6 --- /dev/null +++ b/web/src/test/auto/resources/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "build/", + "rootDir": ".", + "tsBuildInfoFile": "build/tsconfig.tsbuildinfo", + "skipLibCheck": true, + "noEmitOnError": false + }, + + "include": [ "*.ts", "loader/*.ts", "@types/*.d.ts" ], + "exclude": [ "node_modules" ], + + "references": [ + { "path": "../../../common/web-utils" }, + { "path": "../../../engine" }, + ] +} diff --git a/web/src/test/auto/tsconfig.json b/web/src/test/auto/tsconfig.json index 506b0610d46..75f6a5d17a5 100644 --- a/web/src/test/auto/tsconfig.json +++ b/web/src/test/auto/tsconfig.json @@ -11,11 +11,12 @@ "dom/**/*.ts", "headless/**/*.ts", "integrated/**/*.ts", - "resources/**/*.ts", + "resources/@types/*.d.ts", "predictive-text/**/*.ts", ], "references": [ { "path": "../../engine" }, + { "path": "resources" } ] }