maint(web): address code review comments

- inline 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.
This commit is contained in:
Eberhard Beilharz 2026-01-29 15:41:58 +01:00
parent e2b31c488b
commit 1d9b8cc883
No known key found for this signature in database
GPG key ID: E9140597606020D3
18 changed files with 81 additions and 287 deletions

155
package-lock.json generated
View file

@ -1360,19 +1360,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/@cspotcode/source-map-support": {
"version": "0.8.1",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jridgewell/trace-mapping": "0.3.9"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz",
@ -1652,17 +1639,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.9",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jridgewell/resolve-uri": "^3.0.3",
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"node_modules/@keymanapp/auto-history-action": {
"resolved": "resources/build/version",
"link": true
@ -3272,34 +3248,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/@tsconfig/node10": {
"version": "1.0.8",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/@tsconfig/node12": {
"version": "1.0.9",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/@tsconfig/node14": {
"version": "1.0.1",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/@tsconfig/node16": {
"version": "1.0.2",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/@types/accepts": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/@types/accepts/-/accepts-1.3.7.tgz",
@ -4552,16 +4500,6 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
"node_modules/acorn-walk": {
"version": "8.2.0",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/agent-base": {
"version": "6.0.2",
"dev": true,
@ -4741,13 +4679,6 @@
"integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==",
"license": "MIT"
},
"node_modules/arg": {
"version": "4.1.3",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/argparse": {
"version": "2.0.1",
"dev": true,
@ -5911,13 +5842,6 @@
"version": "1.0.3",
"license": "MIT"
},
"node_modules/create-require": {
"version": "1.1.1",
"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",
@ -9920,13 +9844,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/make-error": {
"version": "1.3.6",
"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",
@ -13020,61 +12937,6 @@
"typescript": ">=4.2.0"
}
},
"node_modules/ts-node": {
"version": "10.9.1",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
"integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
"@tsconfig/node12": "^1.0.7",
"@tsconfig/node14": "^1.0.0",
"@tsconfig/node16": "^1.0.2",
"acorn": "^8.4.1",
"acorn-walk": "^8.1.1",
"arg": "^4.1.0",
"create-require": "^1.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"v8-compile-cache-lib": "^3.0.1",
"yn": "3.1.1"
},
"bin": {
"ts-node": "dist/bin.js",
"ts-node-cwd": "dist/bin-cwd.js",
"ts-node-esm": "dist/bin-esm.js",
"ts-node-script": "dist/bin-script.js",
"ts-node-transpile-only": "dist/bin-transpile.js",
"ts-script": "dist/bin-script-deprecated.js"
},
"peerDependencies": {
"@swc/core": ">=1.2.50",
"@swc/wasm": ">=1.2.50",
"@types/node": "*",
"typescript": ">=2.7"
},
"peerDependenciesMeta": {
"@swc/core": {
"optional": true
},
"@swc/wasm": {
"optional": true
}
}
},
"node_modules/ts-node/node_modules/diff": {
"version": "4.0.2",
"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,
@ -13458,13 +13320,6 @@
"uuid": "dist/bin/uuid"
}
},
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/v8-to-istanbul": {
"version": "9.0.1",
"dev": true,
@ -13922,16 +13777,6 @@
"node": ">= 4.0.0"
}
},
"node_modules/yn": {
"version": "3.1.1",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=6"
}
},
"node_modules/yocto-queue": {
"version": "0.1.0",
"dev": true,

View file

@ -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

View file

@ -69,26 +69,21 @@ do_build () {
}
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:
# 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"
# 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
# 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
}

View file

@ -7,15 +7,6 @@ import { LanguageAPIPropertySpec } from 'keyman/engine/keyboard';
import { CloudRequesterInterface } from './requesterInterface.js';
import { ManagedPromise, Version } from 'keyman/common/web-utils';
// For when the API call straight-up times out.
export const CLOUD_TIMEOUT_ERR = "The Cloud API request timed out.";
// Currently cannot distinguish between "no matching keyboard" and other script-load errors.
export const CLOUD_MALFORMED_OBJECT_ERR = "Could not find a keyboard with that ID.";
// Represents unspecified errors that occur when registering the results of a successful API call.
export const CLOUD_STUB_REGISTRATION_ERR = "The Cloud API failed to find an appropriate keyboard.";
// Represents custom, specified KMW errors that occur when registering the results of a successful API call.
export const CLOUD_REGISTRATION_ERR = "Error occurred while registering keyboards: ";
export const MISSING_KEYBOARD = function(kbdid: string) {
return kbdid + ' keyboard not found.';
}
@ -139,7 +130,7 @@ export class CloudQueryEngine extends EventEmitter<EventMap> {
try {
result = this._registerCore(x);
} catch(err) {
result = new Error(CLOUD_REGISTRATION_ERR + err);
result = new Error(`Error occurred while registering keyboards: ${err}`);
}
if(!promiseid) {
@ -199,7 +190,7 @@ export class CloudQueryEngine extends EventEmitter<EventMap> {
// Ignore callback unless the context is defined
if(typeof(options) == 'undefined' || typeof(options['context']) == 'undefined') {
return new Error(CLOUD_MALFORMED_OBJECT_ERR);
return new Error('Could not find a keyboard with that ID.');
}
// Register each keyboard for the specified language codes

View file

@ -1,6 +1,5 @@
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/cloudQueryEngine.js';
export class DOMCloudRequester implements CloudRequesterInterface {
private readonly fileLocal: boolean;
@ -14,7 +13,7 @@ export class DOMCloudRequester implements CloudRequesterInterface {
// Set callback timer
const timeoutID = window.setTimeout(() => {
promise.reject(new Error(CLOUD_TIMEOUT_ERR));
promise.reject(new Error('The Cloud API request timed out.'));
}, 10000);
const tFlag='&timerid='+ timeoutID;
@ -28,7 +27,7 @@ export class DOMCloudRequester implements CloudRequesterInterface {
// script does not ever call `register`. Also provides default handling
// should `register` fail to report results/failure correctly.
if(!promise.isResolved) {
promise.reject(new Error(CLOUD_STUB_REGISTRATION_ERR));
promise.reject(new Error('The Cloud API failed to find an appropriate keyboard.'));
}
};
@ -42,7 +41,8 @@ export class DOMCloudRequester implements CloudRequesterInterface {
lineno?: number, colno?: number, error?: Error) => {
window.clearTimeout(timeoutID);
let msg = CLOUD_MALFORMED_OBJECT_ERR;
// Currently cannot distinguish between "no matching keyboard" and other script-load errors.
let msg = 'Could not find a keyboard with that ID.';
if(error) {
msg = msg + ": " + error.message;
}

View file

@ -13,10 +13,3 @@ export { CloudRequesterInterface } from './cloud/requesterInterface.js';
export { KeyboardRequisitioner } from './keyboardRequisitioner.js';
export { ModelCache } from './modelCache.js';
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
};

View file

@ -7,15 +7,10 @@ const require = createRequire(import.meta.url);
import { MinimalKeymanGlobal } from 'keyman/engine/keyboard';
import { JSKeyboardInterface } from 'keyman/engine/js-processor';
import { NodeKeyboardLoader } from 'keyman/test/resources';
import { NodeKeyboardLoader, getKeymanRoot } from 'keyman/test/resources';
import { KeyboardTest, NodeProctor } from '@keymanapp/recorder-core';
import { env } from 'node:process';
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
const __dirname = dirname(fileURLToPath(import.meta.url));
const KEYMAN_ROOT = env.KEYMAN_ROOT ?? (__dirname + '/../../../../../../../');
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'));

View file

@ -6,16 +6,11 @@ const require = createRequire(import.meta.url);
import { MinimalKeymanGlobal } from 'keyman/engine/keyboard';
import { JSKeyboardInterface } from 'keyman/engine/js-processor';
import { NodeKeyboardLoader } from 'keyman/test/resources';
import { NodeKeyboardLoader, getKeymanRoot } from 'keyman/test/resources';
import { KeyboardTest, NodeProctor } from '@keymanapp/recorder-core';
import { ModifierKeyConstants } from '@keymanapp/common-types';
import { env } from 'node:process';
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
const __dirname = dirname(fileURLToPath(import.meta.url));
const KEYMAN_ROOT = env.KEYMAN_ROOT ?? (__dirname + '/../../../../../../../');
const KEYMAN_ROOT = getKeymanRoot();
describe('Engine - Chirality', function() {
let testJSONtext = fs.readFileSync(require.resolve('@keymanapp/common-test-resources/json/engine_tests/chirality.json'));

View file

@ -6,15 +6,10 @@ const require = createRequire(import.meta.url);
import { MinimalKeymanGlobal } from 'keyman/engine/keyboard';
import { JSKeyboardInterface } from 'keyman/engine/js-processor';
import { NodeKeyboardLoader } from 'keyman/test/resources';
import { NodeKeyboardLoader, getKeymanRoot } from 'keyman/test/resources';
import { KeyboardTest, NodeProctor } from '@keymanapp/recorder-core';
import { env } from 'node:process';
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
const __dirname = dirname(fileURLToPath(import.meta.url));
const KEYMAN_ROOT = env.KEYMAN_ROOT ?? (__dirname + '/../../../../../../../');
const KEYMAN_ROOT = getKeymanRoot();
describe('Engine - Deadkeys', function() {
let testJSONtext = fs.readFileSync(require.resolve('@keymanapp/common-test-resources/json/engine_tests/deadkeys.json'));

View file

@ -6,15 +6,11 @@ const require = createRequire(import.meta.url);
import { MinimalKeymanGlobal } from 'keyman/engine/keyboard';
import { JSKeyboardInterface } from 'keyman/engine/js-processor';
import { NodeKeyboardLoader } from 'keyman/test/resources';
import { NodeKeyboardLoader, getKeymanRoot } from 'keyman/test/resources';
import { KeyboardTest, NodeProctor } from '@keymanapp/recorder-core';
import { env } from 'node:process';
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
const __dirname = dirname(fileURLToPath(import.meta.url));
const KEYMAN_ROOT = env.KEYMAN_ROOT ?? (__dirname + '/../../../../../../../../');
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'));

View file

@ -4,13 +4,7 @@ import sinon from 'sinon';
import { ManagedPromise } from 'keyman/common/web-utils';
import { CloudQueryEngine, toPrefixedKeyboardId as prefixed } from 'keyman/engine/keyboard-storage';
import { PathConfiguration } from 'keyman/engine/interfaces';
import { NodeCloudRequester } from 'keyman/test/resources';
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';
const pathConfig = new PathConfiguration({
root: '',
@ -159,7 +153,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 +170,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 +186,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 +203,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;

View file

@ -4,15 +4,11 @@ import fs from 'fs';
import { ManagedPromise } from 'keyman/common/web-utils';
import { KeyboardHarness, MinimalKeymanGlobal } from 'keyman/engine/keyboard';
import { NodeKeyboardLoader, NodeCloudRequester } from 'keyman/test/resources';
import { NodeKeyboardLoader, NodeCloudRequester, getWebTestResourcesPath } from 'keyman/test/resources';
import { KeyboardRequisitioner, toPrefixedKeyboardId } from 'keyman/engine/keyboard-storage';
import { PathConfiguration } from 'keyman/engine/interfaces';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
@ -157,7 +153,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;
@ -187,7 +183,7 @@ 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;
@ -206,7 +202,7 @@ 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;
@ -224,7 +220,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;
@ -241,12 +237,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);
@ -268,7 +264,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) => {
@ -304,7 +300,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']);

View file

@ -2,13 +2,7 @@ import { assert } from 'chai';
import sinon from 'sinon';
import { KeyboardStub } from 'keyman/engine/keyboard-storage';
import { NodeCloudRequester } from 'keyman/test/resources';
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 +75,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);

View file

@ -1,13 +1,7 @@
import { assert } from 'chai';
import sinon from 'sinon';
import { NodeCloudRequester } from 'keyman/test/resources';
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 +32,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 +52,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 +69,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);

View file

@ -4,12 +4,10 @@
import fs from 'node:fs';
import { pathToFileURL } from 'node:url';
import { getKeymanRoot } from 'keyman/test/resources';
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
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) {

View file

@ -1,5 +1,6 @@
import { assert } from 'chai';
import path from 'path';
import { LanguageProcessor, TranscriptionCache } from 'keyman/engine/main';
import { SourcemappedWorker as LMWorker } from "@keymanapp/lexical-model-layer/node";
import { SyntheticTextStore } from 'keyman/engine/keyboard';
@ -9,15 +10,10 @@ import { SyntheticTextStore } from 'keyman/engine/keyboard';
*/
import { LexicalModelCompiler } from '@keymanapp/kmc-model';
import path from 'path';
import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers';
import { getKeymanRoot } from 'keyman/test/resources';
import { env } from 'node:process';
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
const __dirname = dirname(fileURLToPath(import.meta.url));
const KEYMAN_ROOT = env.KEYMAN_ROOT ?? (__dirname + '/../../../../../../../../');
const KEYMAN_ROOT = getKeymanRoot();
// Required initialization setup.
global.keyman = {}; // So that keyboard-based checks against the global `keyman` succeed.

View file

@ -3,4 +3,16 @@ 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';
export { simulateMultiSourceMatcherInput, simulateSelectorInput } from './simulateMultiSourceInput.js';
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
export function getKeymanRoot(): string {
const __dirname = dirname(fileURLToPath(import.meta.url));
return process.env['KEYMAN_ROOT'] ?? (__dirname + '/../../../../../../');
}
export function getWebTestResourcesPath(): string {
return getKeymanRoot() + '/web/src/test/auto/resources';
}

View file

@ -2,8 +2,7 @@ import { ManagedPromise } from 'keyman/common/web-utils';
import {
CloudRequesterInterface,
CloudQueryResult,
CloudQueryEngine,
unitTestEndpoints
CloudQueryEngine
} from 'keyman/engine/keyboard-storage';
import fs from 'node:fs';
@ -33,7 +32,7 @@ export class NodeCloudRequester implements CloudRequesterInterface {
// Set callback timer
const timeoutObj = setTimeout(() => {
promise.reject(new Error(unitTestEndpoints.CLOUD_TIMEOUT_ERR));
promise.reject(new Error('The Cloud API request timed out.'));
}, 10000);
const queryId = NodeCloudRequester.QUERY_SEED++;
@ -55,7 +54,7 @@ export class NodeCloudRequester implements CloudRequesterInterface {
});
if(!promise.isResolved) {
promise.reject(new Error(unitTestEndpoints.CLOUD_STUB_REGISTRATION_ERR));
promise.reject(new Error('The Cloud API failed to find an appropriate keyboard.'));
}
}