mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-05 00:15:32 +00:00
Merge pull request #15497 from keymanapp/maint/web/jstests
Some checks failed
Keyman Build Summary / Summarize build status checks (push) Has been cancelled
Some checks failed
Keyman Build Summary / Summarize build status checks (push) Has been cancelled
maint(web): re-add engine .js tests PR #15093 merged multiple engine modules into one. However, in doing so we lost the .js tests and ran only the .ts ones. This change re-adds the .js tests and fixes them where the code diverged since then. Other changes: - rename `queryEngine.ts` to `cloudQueryEngine.ts` to match the class name - remove unused `keyboard-storage/cloud/index.ts` - expose `CLOUD_TIMEOUT_ERR` and `CLOUD_STUB_REGISTRATION_ERR` as `unitTestEndpoints` - add `test/resources` to exports in `web/package.json`. This was necessary because the compiled .ts test files are under `web/build` whereas the .js test files are under `web/src` and so the relative paths in imports no longer work. Also fix the imports in test files. - remove `node-keyboard-loader.ts` which was just a wrapper around `NodeKeyboardLoader`. - some cleanup and removal of default exports and aliases. - moved `specialized-backspace.tests.js` to `specialized-backspace.tests.ts` and fixed resulting issues/warnings. - apply fix from #15477 if KEYMAN_ROOT is not set - inline some consts so that we don't have to export them for unit testing - create `getKeymanRoot` and `getWebTestResourcesPath` helper functions to DRY out the code - run `languageProcessortests.js` without coverage to prevent a failure creating the coverage report I'm not happy to put the compiled files for `test/auto/resources` under `web/src/test/auto/resources/build`, but that's the only way I got it to work. If I put the compiled files in `web/build/test/resources` it couldn't find the types for `promise-status-async`. Follows: #15093
This commit is contained in:
commit
66c5f124cf
46 changed files with 369 additions and 362 deletions
80
package-lock.json
generated
80
package-lock.json
generated
|
|
@ -4811,15 +4811,6 @@
|
|||
"integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/arg": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
|
||||
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"dev": true,
|
||||
|
|
@ -5943,15 +5934,6 @@
|
|||
"version": "1.0.3",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/create-require": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
|
||||
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
|
|
@ -9870,15 +9852,6 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/make-error": {
|
||||
"version": "1.3.6",
|
||||
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
|
||||
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/make-fetch-happen": {
|
||||
"version": "13.0.1",
|
||||
"resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz",
|
||||
|
|
@ -12883,47 +12856,6 @@
|
|||
"typescript": ">=4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-node": {
|
||||
"version": "9.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz",
|
||||
"integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"arg": "^4.1.0",
|
||||
"create-require": "^1.1.0",
|
||||
"diff": "^4.0.1",
|
||||
"make-error": "^1.1.1",
|
||||
"source-map-support": "^0.5.17",
|
||||
"yn": "3.1.1"
|
||||
},
|
||||
"bin": {
|
||||
"ts-node": "dist/bin.js",
|
||||
"ts-node-script": "dist/bin-script.js",
|
||||
"ts-node-transpile-only": "dist/bin-transpile.js",
|
||||
"ts-script": "dist/bin-script-deprecated.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=2.7"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-node/node_modules/diff": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz",
|
||||
"integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/tsc-watch": {
|
||||
"version": "4.6.2",
|
||||
"dev": true,
|
||||
|
|
@ -13760,18 +13692,6 @@
|
|||
"node": ">= 4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/yn": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
|
||||
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/yocto-queue": {
|
||||
"version": "0.1.0",
|
||||
"dev": true,
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
@ -88,17 +88,19 @@ function prepare() {
|
|||
# test-headless engine/osk
|
||||
# ```
|
||||
function test-headless() {
|
||||
TEST_FOLDER=$1
|
||||
TEST_BASE="${KEYMAN_ROOT}/web/src/test/auto/headless/"
|
||||
TEST_EXTENSIONS=${2:-}
|
||||
if [[ ! -z "${2:-}" ]]; then
|
||||
local TEST_FOLDER=$1
|
||||
local TEST_BASE="${KEYMAN_ROOT}/web/src/test/auto/headless/"
|
||||
local TEST_EXTENSIONS=${2:-}
|
||||
shift $(( $# < 2 ? $# : 2 ))
|
||||
|
||||
if [[ ! -z "${TEST_EXTENSIONS}" ]]; then
|
||||
TEST_BASE="${KEYMAN_ROOT}/web/build/test/headless/"
|
||||
|
||||
# Ensure the compiled tests are available.
|
||||
tsc --project "${KEYMAN_ROOT}/web/src/test/auto/tsconfig.json"
|
||||
fi
|
||||
|
||||
TEST_OPTS=()
|
||||
local TEST_OPTS=()
|
||||
if builder_is_running_on_teamcity; then
|
||||
TEST_OPTS+=(--reporter "${KEYMAN_ROOT}/common/test/resources/mocha-teamcity-reporter/teamcity.cjs" --reporter-options parentFlowId="unit_tests")
|
||||
echo "##teamcity[flowStarted flowId='unit_tests']"
|
||||
|
|
@ -108,10 +110,14 @@ function test-headless() {
|
|||
TEST_OPTS+=(--extension "${TEST_EXTENSIONS}")
|
||||
fi
|
||||
|
||||
builder_echo '> ' mocha --recursive "${TEST_BASE}${TEST_FOLDER}" "${TEST_OPTS[@]}"
|
||||
if [[ -e .c8rc.json ]]; then
|
||||
# Add any remaining arguments directly to Mocha.
|
||||
TEST_OPTS+=("$@")
|
||||
|
||||
if [[ -e .c8rc.json && -z "${SKIP_C8:-}" ]]; then
|
||||
builder_echo '> ' c8 mocha --recursive "${TEST_BASE}${TEST_FOLDER}" "${TEST_OPTS[@]}"
|
||||
c8 mocha --recursive "${TEST_BASE}${TEST_FOLDER}" "${TEST_OPTS[@]}"
|
||||
else
|
||||
builder_echo '> ' mocha --recursive "${TEST_BASE}${TEST_FOLDER}" "${TEST_OPTS[@]}"
|
||||
mocha --recursive "${TEST_BASE}${TEST_FOLDER}" "${TEST_OPTS[@]}"
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -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": {
|
||||
|
|
|
|||
|
|
@ -14,9 +14,11 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
|
|||
|
||||
# ################################ Main script ################################
|
||||
|
||||
# dependency on kmc required for tests
|
||||
builder_describe "Builds Keyman Engine for Web (KMW)" \
|
||||
"@/core:wasm build" \
|
||||
"@/common/tools/es-bundling build" \
|
||||
"@/developer/src/kmc build" \
|
||||
"@/web/src/common/web-utils build" \
|
||||
"clean" \
|
||||
"configure" \
|
||||
|
|
@ -68,11 +70,30 @@ do_build () {
|
|||
node src/osk/validate-gesture-specs.js
|
||||
}
|
||||
|
||||
builder_run_action clean rm -rf "$KEYMAN_ROOT/web/build/engine"
|
||||
run_tests() {
|
||||
# Run javascript tests
|
||||
#
|
||||
# Trying to run languageProcessor.tests.js with c8 coverage fails with:
|
||||
# "TypeError [ERR_INVALID_URL_SCHEME]: The URL must be of scheme file"
|
||||
# when c8 tries to create a report from the raw coverage data. The reason
|
||||
# is a URL starting with `data:text/javascript` coming from
|
||||
# `web/src/engine/predictive-text/worker-main/src/node/mappedWorker.ts`.
|
||||
#
|
||||
# So we first run all javascript tests except languageProcessor.tests.js
|
||||
# with coverage, and then in a second step run languageProcessor.tests.js
|
||||
# without coverage.
|
||||
test-headless engine "" "--exclude" "**/languageProcessor.tests.js"
|
||||
SKIP_C8=1 test-headless engine/main/headless/languageProcessor.tests.js
|
||||
|
||||
# Run typescript tests
|
||||
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
|
||||
|
|
@ -1,11 +1,14 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*/
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
|
||||
import { PathConfiguration } from 'keyman/engine/interfaces';
|
||||
|
||||
import { KeyboardStub, ErrorStub, KeyboardAPISpec } from '../keyboardStub.js';
|
||||
import { LanguageAPIPropertySpec } from 'keyman/engine/keyboard';
|
||||
import { CloudRequesterInterface } from './requesterInterface.js';
|
||||
import { ManagedPromise, Version } from 'keyman/common/web-utils';
|
||||
import { PathConfiguration } from 'keyman/engine/interfaces';
|
||||
import { LanguageAPIPropertySpec } from 'keyman/engine/keyboard';
|
||||
|
||||
import { ErrorStub, KeyboardAPISpec, KeyboardStub } from '../keyboardStub.js';
|
||||
import { CloudRequesterInterface } from './requesterInterface.js';
|
||||
|
||||
// For when the API call straight-up times out.
|
||||
export const CLOUD_TIMEOUT_ERR = "The Cloud API request timed out.";
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
export { CloudQueryResult, CloudQueryEngine as QueryEngine } from './queryEngine.js';
|
||||
export { CloudRequesterInterface as RequesterInterface } from './requesterInterface.js';
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*/
|
||||
import { ManagedPromise } from 'keyman/common/web-utils';
|
||||
|
||||
import { CLOUD_MALFORMED_OBJECT_ERR, CLOUD_STUB_REGISTRATION_ERR, CLOUD_TIMEOUT_ERR } from './cloud/cloudQueryEngine.js';
|
||||
import { CloudRequesterInterface } from './cloud/requesterInterface.js';
|
||||
import { CLOUD_MALFORMED_OBJECT_ERR, CLOUD_TIMEOUT_ERR, CLOUD_STUB_REGISTRATION_ERR } from './cloud/queryEngine.js';
|
||||
|
||||
export class DOMCloudRequester implements CloudRequesterInterface {
|
||||
private readonly fileLocal: boolean;
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ 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';
|
||||
export { DOMCloudRequester } from './domCloudRequester.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);
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*/
|
||||
import fs from 'node:fs';
|
||||
|
||||
import { assert } from 'chai';
|
||||
import fs from 'fs';
|
||||
|
||||
|
||||
import { createRequire } from 'module';
|
||||
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 { KeyboardTest, NodeProctor } from '@keymanapp/recorder-core';
|
||||
import { JSKeyboardInterface } from 'keyman/engine/js-processor';
|
||||
import { MinimalKeymanGlobal } from 'keyman/engine/keyboard';
|
||||
import { NodeKeyboardLoader, getKeymanRoot } from 'keyman/test/resources';
|
||||
|
||||
import { env } from 'node:process';
|
||||
const KEYMAN_ROOT = env.KEYMAN_ROOT;
|
||||
const require = createRequire(import.meta.url);
|
||||
const KEYMAN_ROOT = getKeymanRoot();
|
||||
|
||||
describe('Engine - Basic Simulation', function() {
|
||||
let testJSONtext = fs.readFileSync(require.resolve('@keymanapp/common-test-resources/json/engine_tests/basic_lao_simulation.json'));
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -1,17 +1,19 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*/
|
||||
import fs from 'node:fs';
|
||||
|
||||
import { assert } from 'chai';
|
||||
import fs from 'fs';
|
||||
|
||||
import { createRequire } from 'module';
|
||||
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 { KeyboardTest, NodeProctor } from '@keymanapp/recorder-core';
|
||||
import { ModifierKeyConstants } from '@keymanapp/common-types';
|
||||
import { KeyboardTest, NodeProctor } from '@keymanapp/recorder-core';
|
||||
import { JSKeyboardInterface } from 'keyman/engine/js-processor';
|
||||
import { MinimalKeymanGlobal } from 'keyman/engine/keyboard';
|
||||
import { NodeKeyboardLoader, getKeymanRoot } from 'keyman/test/resources';
|
||||
|
||||
import { env } from 'node:process';
|
||||
const KEYMAN_ROOT = env.KEYMAN_ROOT;
|
||||
const require = createRequire(import.meta.url);
|
||||
const KEYMAN_ROOT = getKeymanRoot();
|
||||
|
||||
describe('Engine - Chirality', function() {
|
||||
let testJSONtext = fs.readFileSync(require.resolve('@keymanapp/common-test-resources/json/engine_tests/chirality.json'));
|
||||
|
|
|
|||
|
|
@ -1,16 +1,18 @@
|
|||
import { assert } from 'chai';
|
||||
import fs from 'fs';
|
||||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*/
|
||||
import fs from 'node:fs';
|
||||
|
||||
import { assert } from 'chai';
|
||||
import { createRequire } from 'module';
|
||||
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, getKeymanRoot } from 'keyman/test/resources';
|
||||
import { KeyboardTest, NodeProctor } from '@keymanapp/recorder-core';
|
||||
|
||||
import { env } from 'node:process';
|
||||
const KEYMAN_ROOT = env.KEYMAN_ROOT;
|
||||
const require = createRequire(import.meta.url);
|
||||
const KEYMAN_ROOT = getKeymanRoot();
|
||||
|
||||
describe('Engine - Deadkeys', function() {
|
||||
let testJSONtext = fs.readFileSync(require.resolve('@keymanapp/common-test-resources/json/engine_tests/deadkeys.json'));
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -1,23 +1,25 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*/
|
||||
import fs from 'node:fs';
|
||||
|
||||
import { assert } from 'chai';
|
||||
import fs from 'fs';
|
||||
|
||||
import { createRequire } from 'module';
|
||||
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 { KeyboardTest, NodeProctor } from '@keymanapp/recorder-core';
|
||||
import { JSKeyboardInterface } from 'keyman/engine/js-processor';
|
||||
import { MinimalKeymanGlobal } from 'keyman/engine/keyboard';
|
||||
import { NodeKeyboardLoader, getKeymanRoot } from 'keyman/test/resources';
|
||||
|
||||
import { env } from 'node:process';
|
||||
const KEYMAN_ROOT = env.KEYMAN_ROOT;
|
||||
const require = createRequire(import.meta.url);
|
||||
const KEYMAN_ROOT = getKeymanRoot();
|
||||
|
||||
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',
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 DUMMIED_KEYS_KEYBOARD_SCRIPT = function keyboard_core () {
|
||||
const COMMON_KBD_SCRIPT_PROPS = new CommonKbdScriptProps();
|
||||
|
||||
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);
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -1,16 +1,13 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*/
|
||||
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 { PathConfiguration } from 'keyman/engine/interfaces';
|
||||
import NodeCloudRequester from '../../../resources/loader/nodeCloudRequester.js';
|
||||
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
import { CloudQueryEngine, toPrefixedKeyboardId as prefixed } from 'keyman/engine/keyboard-storage';
|
||||
import { NodeCloudRequester, getWebTestResourcesPath } from 'keyman/test/resources';
|
||||
|
||||
const pathConfig = new PathConfiguration({
|
||||
root: '',
|
||||
|
|
@ -159,7 +156,7 @@ describe("Cloud-query interface", () => {
|
|||
|
||||
describe('Stub fetching', () => {
|
||||
it('sil_euro_latin@no,sv', async () => {
|
||||
const querier = mockQuery(`${__dirname}/../../../resources/query-mock-results/sil_euro_latin@no_sv.js.fixture`);
|
||||
const querier = mockQuery(`${getWebTestResourcesPath()}/query-mock-results/sil_euro_latin@no_sv.js.fixture`);
|
||||
const promise = querier.fetchCloudStubs(['sil_euro_latin@no', 'sil_euro_latin@sv']);
|
||||
|
||||
const stubs = await promise;
|
||||
|
|
@ -176,7 +173,7 @@ describe("Cloud-query interface", () => {
|
|||
});
|
||||
|
||||
it('sil_cameroon_azerty', async () => {
|
||||
const querier = mockQuery(`${__dirname}/../../../resources/query-mock-results/sil_cameroon_azerty.js.fixture`);
|
||||
const querier = mockQuery(`${getWebTestResourcesPath()}/query-mock-results/sil_cameroon_azerty.js.fixture`);
|
||||
const promise = querier.fetchCloudStubs(['sil_cameroon_azerty']);
|
||||
|
||||
const stubs = await promise;
|
||||
|
|
@ -192,7 +189,7 @@ describe("Cloud-query interface", () => {
|
|||
});
|
||||
|
||||
it('@dz', async () => {
|
||||
const querier = mockQuery(`${__dirname}/../../../resources/query-mock-results/@dz.js.fixture`);
|
||||
const querier = mockQuery(`${getWebTestResourcesPath()}/query-mock-results/@dz.js.fixture`);
|
||||
const promise = querier.fetchCloudStubs(['@dz']);
|
||||
|
||||
const stubs = await promise;
|
||||
|
|
@ -209,7 +206,7 @@ describe("Cloud-query interface", () => {
|
|||
});
|
||||
|
||||
it('language list fetching', async () => {
|
||||
const querier = mockQuery(`${__dirname}/../../../resources/query-mock-results/languages.js.fixture`);
|
||||
const querier = mockQuery(`${getWebTestResourcesPath()}/query-mock-results/languages.js.fixture`);
|
||||
const promise = querier.languageListPromise;
|
||||
|
||||
const langList = await promise;
|
||||
|
|
|
|||
|
|
@ -1,23 +1,19 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*/
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
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 { PathConfiguration } from 'keyman/engine/interfaces';
|
||||
import NodeCloudRequester from '../../../resources/loader/nodeCloudRequester.js';
|
||||
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
import { createRequire } from 'module';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import { ManagedPromise } from 'keyman/common/web-utils';
|
||||
import { PathConfiguration } from 'keyman/engine/interfaces';
|
||||
import { KeyboardHarness, MinimalKeymanGlobal } from 'keyman/engine/keyboard';
|
||||
import { KeyboardRequisitioner, toPrefixedKeyboardId } from 'keyman/engine/keyboard-storage';
|
||||
import { NodeCloudRequester, NodeKeyboardLoader, getWebTestResourcesPath } from 'keyman/test/resources';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
let commonResourcesPackage = '@keymanapp/common-test-resources';
|
||||
|
|
@ -160,7 +156,7 @@ describe("KeyboardRequisitioner", () => {
|
|||
});
|
||||
|
||||
it('drops requests for already fetched stubs', async () => {
|
||||
let setupDB = mockedSetup(`${__dirname}/../../../resources/query-mock-results/sil_euro_latin@no_sv.js.fixture`);
|
||||
let setupDB = mockedSetup(`${getWebTestResourcesPath()}/query-mock-results/sil_euro_latin@no_sv.js.fixture`);
|
||||
let promise = setupDB.addKeyboardArray(['sil_euro_latin@no,sv']);
|
||||
|
||||
const setupStubs = await promise;
|
||||
|
|
@ -190,14 +186,14 @@ describe("KeyboardRequisitioner", () => {
|
|||
|
||||
describe('Stub fetching', () => {
|
||||
it('sil_euro_latin@no,sv', async () => {
|
||||
const keyboardRequisitioner = mockedSetup(`${__dirname}/../../../resources/query-mock-results/sil_euro_latin@no_sv.js.fixture`);
|
||||
const keyboardRequisitioner = mockedSetup(`${getWebTestResourcesPath()}/query-mock-results/sil_euro_latin@no_sv.js.fixture`);
|
||||
const promise = keyboardRequisitioner.addKeyboardArray(['sil_euro_latin@no,sv']);
|
||||
|
||||
const stubs = await promise;
|
||||
|
||||
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)");
|
||||
}
|
||||
|
||||
|
|
@ -209,14 +205,14 @@ describe("KeyboardRequisitioner", () => {
|
|||
});
|
||||
|
||||
it('sil_cameroon_azerty', async () => {
|
||||
const keyboardRequisitioner = mockedSetup(`${__dirname}/../../../resources/query-mock-results/sil_cameroon_azerty.js.fixture`);
|
||||
const keyboardRequisitioner = mockedSetup(`${getWebTestResourcesPath()}/query-mock-results/sil_cameroon_azerty.js.fixture`);
|
||||
const promise = keyboardRequisitioner.addKeyboardArray(['sil_cameroon_azerty']);
|
||||
|
||||
const stubs = await promise;
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
|
|
@ -227,7 +223,7 @@ describe("KeyboardRequisitioner", () => {
|
|||
});
|
||||
|
||||
it('@dz', async () => {
|
||||
const keyboardRequisitioner = mockedSetup(`${__dirname}/../../../resources/query-mock-results/@dz.js.fixture`);
|
||||
const keyboardRequisitioner = mockedSetup(`${getWebTestResourcesPath()}/query-mock-results/@dz.js.fixture`);
|
||||
const promise = keyboardRequisitioner.addKeyboardArray(['@dz']);
|
||||
|
||||
const stubs = await promise;
|
||||
|
|
@ -244,12 +240,12 @@ describe("KeyboardRequisitioner", () => {
|
|||
});
|
||||
|
||||
it('drops requests for already fetched stubs', async () => {
|
||||
let setupDB = mockedSetup(`${__dirname}/../../../resources/query-mock-results/sil_euro_latin@no_sv.js.fixture`);
|
||||
let setupDB = mockedSetup(`${getWebTestResourcesPath()}/query-mock-results/sil_euro_latin@no_sv.js.fixture`);
|
||||
let promise = setupDB.addKeyboardArray(['sil_euro_latin@no,sv']);
|
||||
|
||||
const setupStubs = await promise;
|
||||
|
||||
const precachedRequisitioner = mockedSetup(`${__dirname}/../../../resources/query-mock-results/@dz.js.fixture`);
|
||||
const precachedRequisitioner = mockedSetup(`${getWebTestResourcesPath()}/query-mock-results/@dz.js.fixture`);
|
||||
// Pre-load our 'setup' stubs into the query manager class before running the query.
|
||||
for(let stub of setupStubs) {
|
||||
precachedRequisitioner.cache.addStub(stub);
|
||||
|
|
@ -271,7 +267,7 @@ describe("KeyboardRequisitioner", () => {
|
|||
|
||||
describe('addLanguageKeyboards', function() {
|
||||
it('awaits the language list fetch + constructs a query for the requested language', async () => {
|
||||
const keyboardRequisitioner = mockedSetup(`${__dirname}/../../../resources/query-mock-results/languages.js.fixture`);
|
||||
const keyboardRequisitioner = mockedSetup(`${getWebTestResourcesPath()}/query-mock-results/languages.js.fixture`);
|
||||
const mockedRequester = keyboardRequisitioner.cloudQueryEngine.requestEngine;
|
||||
const originalRequest = mockedRequester.request;
|
||||
let swapFake = sinon.fake((query) => {
|
||||
|
|
@ -307,7 +303,7 @@ describe("KeyboardRequisitioner", () => {
|
|||
// https://api.keyman.com/cloud/4.0/keyboards?jsonp=keyman.register&languageidtype=bcp47&version=17.0&keyboardid=khmer_angkor&timerid=49.
|
||||
//
|
||||
// The edits are minimal and notated within the fixture file.
|
||||
const keyboardRequisitioner = mockedSetup(`${__dirname}/../../../resources/query-mock-results/khmer_angkor.hand-edited.js.fixture`);
|
||||
const keyboardRequisitioner = mockedSetup(`${getWebTestResourcesPath()}/query-mock-results/khmer_angkor.hand-edited.js.fixture`);
|
||||
|
||||
const cache = keyboardRequisitioner.cache;
|
||||
const [stub] = await keyboardRequisitioner.addKeyboardArray(['khmer_angkor']);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*/
|
||||
import { assert } from 'chai';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import { KeyboardStub } from 'keyman/engine/keyboard-storage';
|
||||
import NodeCloudRequester from '../../../resources/loader/nodeCloudRequester.js';
|
||||
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
import { NodeCloudRequester, getWebTestResourcesPath } from 'keyman/test/resources';
|
||||
|
||||
describe("KeyboardStub", () => {
|
||||
function performMockedRequest(mockedResultsFile) {
|
||||
|
|
@ -81,7 +78,7 @@ describe("KeyboardStub", () => {
|
|||
});
|
||||
|
||||
it('merge(): barebones stub + fetched sil_euro_latin@no', async () => {
|
||||
const query = performMockedRequest(`${__dirname}/../../../resources/query-mock-results/sil_euro_latin@no_sv.js.fixture`);
|
||||
const query = performMockedRequest(`${getWebTestResourcesPath()}/query-mock-results/sil_euro_latin@no_sv.js.fixture`);
|
||||
await query.promise;
|
||||
|
||||
assert.isTrue(query.mockedRegister.called);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*/
|
||||
import { assert } from 'chai';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import NodeCloudRequester from '../../../resources/loader/nodeCloudRequester.js';
|
||||
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
import { NodeCloudRequester, getWebTestResourcesPath } from 'keyman/test/resources';
|
||||
|
||||
describe("Mocked cloud query results in headless mode ('canary' testing)", () => {
|
||||
function performMockedRequest(mockedResultsFile) {
|
||||
|
|
@ -38,7 +35,7 @@ describe("Mocked cloud query results in headless mode ('canary' testing)", () =>
|
|||
}
|
||||
|
||||
it('sil_euro_latin@no,sv', async () => {
|
||||
const query = performMockedRequest(`${__dirname}/../../../resources/query-mock-results/sil_euro_latin@no_sv.js.fixture`);
|
||||
const query = performMockedRequest(`${getWebTestResourcesPath()}/query-mock-results/sil_euro_latin@no_sv.js.fixture`);
|
||||
await query.promise;
|
||||
|
||||
assert.isTrue(query.mockedRegister.called);
|
||||
|
|
@ -58,7 +55,7 @@ describe("Mocked cloud query results in headless mode ('canary' testing)", () =>
|
|||
});
|
||||
|
||||
it('sil_cameroon_azerty', async () => {
|
||||
const query = performMockedRequest(`${__dirname}/../../../resources/query-mock-results/sil_cameroon_azerty.js.fixture`);
|
||||
const query = performMockedRequest(`${getWebTestResourcesPath()}/query-mock-results/sil_cameroon_azerty.js.fixture`);
|
||||
await query.promise;
|
||||
|
||||
assert.isTrue(query.mockedRegister.called);
|
||||
|
|
@ -75,7 +72,7 @@ describe("Mocked cloud query results in headless mode ('canary' testing)", () =>
|
|||
});
|
||||
|
||||
it('@dz', async () => {
|
||||
const query = performMockedRequest(`${__dirname}/../../../resources/query-mock-results/@dz.js.fixture`);
|
||||
const query = performMockedRequest(`${getWebTestResourcesPath()}/query-mock-results/@dz.js.fixture`);
|
||||
await query.promise;
|
||||
|
||||
assert.isTrue(query.mockedRegister.called);
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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('JSKeyboard tests', function () {
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { createRequire } from 'module';
|
|||
const require = createRequire(import.meta.url);
|
||||
|
||||
import { KeyboardHarness, MinimalKeymanGlobal } from 'keyman/engine/keyboard';
|
||||
import { NodeKeyboardLoader } from '../../../resources/loader/nodeKeyboardLoader.js';
|
||||
import { NodeKeyboardLoader } from 'keyman/test/resources';
|
||||
|
||||
describe('KMXKeyboard tests', function () {
|
||||
// TODO-embed-osk-in-kmx: Enable when hooking up with RTL Core API (#15482)
|
||||
|
|
|
|||
|
|
@ -5,11 +5,10 @@
|
|||
import fs from 'node:fs';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname } from 'node:path';
|
||||
import { getKeymanRoot } from 'keyman/test/resources';
|
||||
|
||||
const KEYMAN_ROOT = getKeymanRoot();
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const KEYMAN_ROOT = process.env['KEYMAN_ROOT'] ?? (__dirname + '/../../../../../../');
|
||||
export const coreurl = pathToFileURL(`${KEYMAN_ROOT}/web/build/engine/obj/core-adapter/import/core`).toString();
|
||||
|
||||
export function loadKeyboardBlob(filename: string) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1,19 +1,20 @@
|
|||
import { assert } from 'chai';
|
||||
|
||||
import { LanguageProcessor, TranscriptionCache } from 'keyman/engine/main';
|
||||
import { SourcemappedWorker as LMWorker } from "@keymanapp/lexical-model-layer/node";
|
||||
import { SyntheticTextStore } from 'keyman/engine/keyboard';
|
||||
|
||||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*
|
||||
* Unit tests for the Dummy prediction model.
|
||||
*/
|
||||
import path from 'node:path';
|
||||
|
||||
import { assert } from 'chai';
|
||||
|
||||
import { LexicalModelCompiler } from '@keymanapp/kmc-model';
|
||||
import path from 'path';
|
||||
import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers';
|
||||
import { LexicalModelCompiler } from '@keymanapp/kmc-model';
|
||||
import { SourcemappedWorker as LMWorker } from "@keymanapp/lexical-model-layer/node";
|
||||
import { SyntheticTextStore } from 'keyman/engine/keyboard';
|
||||
import { LanguageProcessor, TranscriptionCache } from 'keyman/engine/main';
|
||||
import { getKeymanRoot } from 'keyman/test/resources';
|
||||
|
||||
import { env } from 'node:process';
|
||||
const KEYMAN_ROOT = env.KEYMAN_ROOT;
|
||||
const KEYMAN_ROOT = getKeymanRoot();
|
||||
|
||||
// Required initialization setup.
|
||||
global.keyman = {}; // So that keyboard-based checks against the global `keyman` succeed.
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ import * as PromiseStatusModule from 'promise-status-async';
|
|||
|
||||
import { InputSample, gestures, GestureDebugPath } from 'keyman/engine/gesture-processor';
|
||||
|
||||
import { assertingPromiseStatus as promiseStatus } from '#test-resources/assertingPromiseStatus.js';
|
||||
import { TouchpathTurtle } from '#gesture-tools';
|
||||
import { simulateMultiSourceMatcherInput } from "#test-resources/simulateMultiSourceInput.js";
|
||||
|
||||
import { assertingPromiseStatus as promiseStatus, simulateMultiSourceMatcherInput } from 'keyman/test/resources';
|
||||
|
||||
import {
|
||||
FlickEndModel,
|
||||
|
|
|
|||
|
|
@ -3,10 +3,18 @@ import sinon from 'sinon';
|
|||
import * as PromiseStatusModule from 'promise-status-async';
|
||||
|
||||
import { GestureModelDefs, buildGestureMatchInspector, gestures } from 'keyman/engine/gesture-processor';
|
||||
import { ManagedPromise, timedPromise } from 'keyman/common/web-utils';
|
||||
|
||||
import { HeadlessInputEngine, TouchpathTurtle } from '#gesture-tools';
|
||||
import { assertingPromiseStatus as promiseStatus } from '#test-resources/assertingPromiseStatus.js';
|
||||
import { assertGestureSequence, SequenceAssertion } from "#test-resources/sequenceAssertions.js";
|
||||
import { ManagedPromise, timedPromise } from 'keyman/common/web-utils';
|
||||
|
||||
import { assertingPromiseStatus as promiseStatus, assertGestureSequence, SequenceAssertion } from 'keyman/test/resources';
|
||||
|
||||
import {
|
||||
LongpressModel,
|
||||
MultitapModel,
|
||||
SimpleTapModel,
|
||||
SubkeySelectModel
|
||||
} from './isolatedGestureSpecs.js';
|
||||
|
||||
const { matchers } = gestures;
|
||||
|
||||
|
|
@ -19,13 +27,6 @@ type MatcherSelection<Type> = gestures.matchers.MatcherSelection<Type>;
|
|||
const getGestureModelSet = gestures.specs.getGestureModelSet;
|
||||
const modelSetForAction = gestures.matchers.modelSetForAction;
|
||||
|
||||
import {
|
||||
LongpressModel,
|
||||
MultitapModel,
|
||||
SimpleTapModel,
|
||||
SubkeySelectModel
|
||||
} from './isolatedGestureSpecs.js';
|
||||
|
||||
const TestGestureModelDefinitions: GestureModelDefs<string> = {
|
||||
gestures: [
|
||||
LongpressModel,
|
||||
|
|
|
|||
|
|
@ -2,13 +2,12 @@ import { assert } from 'chai'
|
|||
import sinon from 'sinon';
|
||||
|
||||
import * as PromiseStatusModule from 'promise-status-async';
|
||||
import { assertingPromiseStatus as promiseStatus, simulateMultiSourceMatcherInput, simulateSelectorInput } from 'keyman/test/resources';
|
||||
|
||||
import { timedPromise } from 'keyman/common/web-utils';
|
||||
import { gestures } from 'keyman/engine/gesture-processor';
|
||||
|
||||
import { TouchpathTurtle } from '#gesture-tools';
|
||||
import { assertingPromiseStatus as promiseStatus } from '#test-resources/assertingPromiseStatus.js';
|
||||
import { simulateMultiSourceMatcherInput, simulateSelectorInput } from "#test-resources/simulateMultiSourceInput.js";
|
||||
|
||||
import {
|
||||
LongpressModel,
|
||||
|
|
@ -56,7 +55,7 @@ describe("MatcherSelector", function () {
|
|||
specSet: [LongpressModel]
|
||||
}, this.fakeClock);
|
||||
|
||||
let completion = executor();
|
||||
const completion = executor();
|
||||
await selectorPromise;
|
||||
await Promise.race([completion, selectionPromises[0]]);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { assert } from 'chai'
|
||||
import sinon from 'sinon';
|
||||
import * as PromiseStatusModule from 'promise-status-async';
|
||||
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';
|
||||
|
||||
import { assertingPromiseStatus as promiseStatus } from '#test-resources/assertingPromiseStatus.js';
|
||||
|
||||
import {
|
||||
InstantRejectionModel,
|
||||
|
|
|
|||
|
|
@ -2,12 +2,11 @@ import { assert } from 'chai'
|
|||
import sinon from 'sinon';
|
||||
import * as PromiseStatusModule from 'promise-status-async';
|
||||
import { PROMISE_PENDING } from 'promise-status-async';
|
||||
import { assertingPromiseStatus as promiseStatus, assertGestureSequence, SequenceAssertion } from 'keyman/test/resources';
|
||||
|
||||
import { GestureModelDefs, GestureSource, gestures, TouchpointCoordinator } from 'keyman/engine/gesture-processor';
|
||||
import { ManagedPromise, timedPromise } from 'keyman/common/web-utils';
|
||||
import { HeadlessInputEngine, TouchpathTurtle } from '#gesture-tools';
|
||||
import { assertingPromiseStatus as promiseStatus } from '#test-resources/assertingPromiseStatus.js';
|
||||
import { assertGestureSequence, SequenceAssertion } from "#test-resources/sequenceAssertions.js";
|
||||
|
||||
import {
|
||||
LongpressModel,
|
||||
|
|
|
|||
21
web/src/test/auto/resources/index.ts
Normal file
21
web/src/test/auto/resources/index.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*/
|
||||
export { assertingPromiseStatus } from './assertingPromiseStatus.js';
|
||||
export { DEFAULT_PROCESSOR_INIT_OPTIONS } from './defaultProcessorInitOptions.js';
|
||||
export { NodeCloudRequester } from './loader/nodeCloudRequester.js';
|
||||
export { NodeKeyboardLoader } from './loader/nodeKeyboardLoader.js';
|
||||
export { assertGestureSequence, SequenceAssertion, StageReportAssertion } from './sequenceAssertions.js';
|
||||
export { simulateMultiSourceMatcherInput, simulateSelectorInput } from './simulateMultiSourceInput.js';
|
||||
|
||||
import { dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
export function getKeymanRoot(): string {
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
return __dirname + '/../../../../../../';
|
||||
}
|
||||
|
||||
export function getWebTestResourcesPath(): string {
|
||||
return getKeymanRoot() + '/web/src/test/auto/resources';
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
export * from './nodeKeyboardLoader.js';
|
||||
|
|
@ -1,17 +1,18 @@
|
|||
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,
|
||||
CloudQueryResult,
|
||||
CloudQueryEngine
|
||||
} from '../../../../engine/src/keyboard-storage/cloud/queryEngine.js';
|
||||
|
||||
/*
|
||||
* Keyman is copyright (C) SIL Global. MIT License.
|
||||
*/
|
||||
import fs from 'node:fs';
|
||||
import https from 'node:https';
|
||||
import vm from 'node:vm';
|
||||
|
||||
export default class NodeCloudRequester implements CloudRequesterInterface {
|
||||
import { ManagedPromise } from 'keyman/common/web-utils';
|
||||
import {
|
||||
CloudQueryEngine,
|
||||
CloudQueryResult,
|
||||
CloudRequesterInterface
|
||||
} from 'keyman/engine/keyboard-storage';
|
||||
|
||||
export class NodeCloudRequester implements CloudRequesterInterface {
|
||||
private static QUERY_SEED = 1;
|
||||
private readonly fileLocal: boolean;
|
||||
|
||||
|
|
@ -34,7 +35,7 @@ export default class NodeCloudRequester implements CloudRequesterInterface {
|
|||
|
||||
// Set callback timer
|
||||
const timeoutObj = setTimeout(() => {
|
||||
promise.reject(new Error(CLOUD_TIMEOUT_ERR));
|
||||
promise.reject(new Error('The Cloud API request timed out.'));
|
||||
}, 10000);
|
||||
|
||||
const queryId = NodeCloudRequester.QUERY_SEED++;
|
||||
|
|
@ -56,7 +57,7 @@ export default class NodeCloudRequester implements CloudRequesterInterface {
|
|||
});
|
||||
|
||||
if(!promise.isResolved) {
|
||||
promise.reject(new Error(CLOUD_STUB_REGISTRATION_ERR));
|
||||
promise.reject(new Error('The Cloud API failed to find an appropriate keyboard.'));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"],
|
||||
}
|
||||
|
|
@ -247,7 +247,7 @@ function simulateMultiSourceInput<OutputType, Type>(
|
|||
|
||||
// -------
|
||||
|
||||
let flattenedSpecs = processedSetup.map(
|
||||
const flattenedSpecs = processedSetup.map(
|
||||
(entry) => entry.sourceSpecs
|
||||
).reduce((constructingArray, entries) => constructingArray.concat(entries), []);
|
||||
|
||||
|
|
@ -365,7 +365,7 @@ export function simulateSelectorInput<Type>(
|
|||
selectorPromise: Promise<MatcherSelector<Type>>,
|
||||
executor: () => Promise<void>
|
||||
} {
|
||||
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.
|
||||
|
|
|
|||
18
web/src/test/auto/resources/tsconfig.json
Normal file
18
web/src/test/auto/resources/tsconfig.json
Normal file
|
|
@ -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" },
|
||||
]
|
||||
}
|
||||
|
|
@ -11,11 +11,12 @@
|
|||
"dom/**/*.ts",
|
||||
"headless/**/*.ts",
|
||||
"integrated/**/*.ts",
|
||||
"resources/**/*.ts",
|
||||
"resources/@types/*.d.ts",
|
||||
"predictive-text/**/*.ts",
|
||||
],
|
||||
|
||||
"references": [
|
||||
{ "path": "../../engine" },
|
||||
{ "path": "resources" }
|
||||
]
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue