Skip to content

maint(web): re-add engine .js tests 🎼#15497

Merged
ermshiperete merged 5 commits intoepic/web-corefrom
maint/web/jstests
Mar 23, 2026
Merged

maint(web): re-add engine .js tests 🎼#15497
ermshiperete merged 5 commits intoepic/web-corefrom
maint/web/jstests

Conversation

@ermshiperete
Copy link
Copy Markdown
Contributor

@ermshiperete ermshiperete commented Jan 26, 2026

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 fix(web): fix problem with tests if KEYMAN_ROOT is not set 🎼 #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
Test-bot: skip

@keymanapp-test-bot
Copy link
Copy Markdown

keymanapp-test-bot Bot commented Jan 26, 2026

User Test Results

Test specification and instructions

User tests are not required

Test Artifacts

  • Android
    • KeyboardHarness apk - build : all tests passed (no artifacts on BuildLevel "build")
    • KMSample1 apk - build : all tests passed (no artifacts on BuildLevel "build")
    • KMSample2 apk - build : all tests passed (no artifacts on BuildLevel "build")
  • Developer
    • Keyman Developer - build : all tests passed (no artifacts on BuildLevel "build")
    • Compiler Regression Tests - build : all tests passed (no artifacts on BuildLevel "build")
    • Keyman Developer (old PRs) - build : all tests passed (no artifacts on BuildLevel "build")
    • kmcomp.zip - build : all tests passed (no artifacts on BuildLevel "build")
    • kmcomp.zip (old PRs) - build : all tests passed (no artifacts on BuildLevel "build")
  • iOS
    • Keyman for iOS (simulator image) - build : all tests passed (no artifacts on BuildLevel "build")
    • FirstVoices Keyboards for iOS (simulator image) - build : all tests passed (no artifacts on BuildLevel "build")
    • FirstVoices Keyboards for iOS (simulator image) (old PRs) - build : all tests passed (no artifacts on BuildLevel "build")
    • Keyman for iOS (simulator image) (old PRs) - build : all tests passed (no artifacts on BuildLevel "build")
  • Keyboards
    • Test Keyboards - build : all tests passed (no artifacts on BuildLevel "build")
  • Web
    • KeymanWeb Test Home - build : all tests passed (no artifacts on BuildLevel "build")

@keymanapp-test-bot keymanapp-test-bot Bot changed the title maint(web): re-add engine .js tests maint(web): re-add engine .js tests 🎼 Jan 26, 2026
@keymanapp-test-bot keymanapp-test-bot Bot added this to the A19S21 milestone Jan 26, 2026
@github-actions github-actions Bot added web/ maint Maintenance work -- continuous integration, build scripts, infrastructure labels Jan 26, 2026
@ermshiperete ermshiperete requested a review from mcdurdin January 26, 2026 16:54
@ermshiperete ermshiperete marked this pull request as ready for review January 26, 2026 16:54
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.
- apply fix from #15477 if KEYMAN_ROOT is not set

I'm not happy to put the compiled files 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`.

Also, running the .js tests succeeded but then creating the coverage
report failed. I was not able to find the reason or a fix for that. As a
hack to work around this problem we check the number of failed tests
instead of relying on the exit code of the test.

Follows: #15093
Test-bot: skip
Copy link
Copy Markdown
Member

@mcdurdin mcdurdin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should have another go at sorting the locations of files. And a few more changes requested. Happy to rubber-ducky if that makes it easier.

Comment on lines +17 to +22
import { CLOUD_TIMEOUT_ERR, CLOUD_STUB_REGISTRATION_ERR } from './cloud/cloudQueryEngine.js';

export const unitTestEndpoints = {
CLOUD_TIMEOUT_ERR,
CLOUD_STUB_REGISTRATION_ERR
};
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't feel right. unitTestEndpoints are intended for targets for unit tests, not for sharing variables. There's no need for these to be exported for their usages in unit tests -- they are both used just one time in nodeCloudeRequester.ts (tests):

// Set callback timer
const timeoutObj = setTimeout(() => {
promise.reject(new Error(CLOUD_TIMEOUT_ERR));
}, 10000);

if(!promise.isResolved) {
promise.reject(new Error(CLOUD_STUB_REGISTRATION_ERR));
}

IMHO, those errors should just be plain strings in the unit testing code -- it's not deployed, there's no localization need, etc, etc. Just KISS. We can then eliminate the messiness of exporting these two constants.

Suggested change
import { CLOUD_TIMEOUT_ERR, CLOUD_STUB_REGISTRATION_ERR } from './cloud/cloudQueryEngine.js';
export const unitTestEndpoints = {
CLOUD_TIMEOUT_ERR,
CLOUD_STUB_REGISTRATION_ERR
};

Copy link
Copy Markdown
Contributor Author

@ermshiperete ermshiperete Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, inlined those consts.

Comment thread web/src/engine/build.sh Outdated
Comment on lines +76 to +90
# Unfortunately we get an error from the coverage report generation:
# "TypeError [ERR_INVALID_URL_SCHEME]: The URL must be of scheme file"
# The following lines ignore the exit code and instead check the number
# of failed tests from the output.
set +e
OUTPUT_FILE=$(mktemp)
test-headless engine "" 2>&1 | tee "${OUTPUT_FILE}"
set -e

FAILURE_COUNT=$(grep ' failing' "${OUTPUT_FILE}" | xargs | cut -f 1 -d' ')
rm "${OUTPUT_FILE}"
builder_echo "(The 'TypeError [ERR_INVALID_URL_SCHEME]: The URL must be of scheme file' is expected)"
if ((FAILURE_COUNT > 0)); then
builder_die "Headless engine tests failed (.js tests)"
fi
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem right. We are running code coverage tests elsewhere just fine.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turns out previously we didn't run the tests with coverage for engine/main. The reason c8 coverage report generation fails is a data:text/javascript URL coming from web/src/engine/predictive-text/worker-main/src/node/mappedWorker.ts. I changed it so that languageProcessor.tests.js which imports mappedWorker runs without test coverage.

Comment on lines +12 to +17
import { env } from 'node:process';
const KEYMAN_ROOT = env.KEYMAN_ROOT;
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';

const __dirname = dirname(fileURLToPath(import.meta.url));
const KEYMAN_ROOT = env.KEYMAN_ROOT ?? (__dirname + '/../../../../../../../../');
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we put this into a helper module in keyman/test/resources and avoid repeating it?

@keyman-server keyman-server modified the milestones: A19S21, A19S22 Jan 31, 2026
@keyman-server keyman-server modified the milestones: A19S22, A19S23 Feb 13, 2026
@keyman-server keyman-server modified the milestones: A19S23, A19S24 Feb 27, 2026
@keyman-server keyman-server modified the milestones: A19S24, A19S25 Mar 14, 2026
- 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.
@ermshiperete ermshiperete requested a review from mcdurdin March 20, 2026 15:01
@ermshiperete ermshiperete force-pushed the maint/web/jstests branch 2 times, most recently from 6ac2b79 to 745fa36 Compare March 20, 2026 17:26
@ermshiperete ermshiperete dismissed mcdurdin’s stale review March 20, 2026 17:29

Requesting re-review

Copy link
Copy Markdown
Member

@mcdurdin mcdurdin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Minor nits only

// Set callback timer
const timeoutID = window.setTimeout(() => {
promise.reject(new Error(CLOUD_TIMEOUT_ERR));
promise.reject(new Error('The Cloud API request timed out.'));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why you are removing the constants?

import { PathConfiguration } from 'keyman/engine/interfaces';
import NodeCloudRequester from '../../../resources/loader/nodeCloudRequester.js';

import path from 'path';
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import path from 'path';
import path from 'node:path';

Trying to make this more consistent over time

@@ -2,20 +2,13 @@ import { assert } from 'chai';
import sinon from 'sinon';
import fs from 'fs';
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import fs from 'fs';
import fs from 'node:fs';

Also see our import order at https://github.com/keymanapp/keyman/wiki/Keyman-Code-Style-Guide#imports-typescript-nodejs-etc

@@ -1,5 +1,6 @@
import { assert } from 'chai';

import path from 'path';
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import path from 'path';
import path from 'mode:path';

Comment thread web/src/test/auto/resources/index.ts Outdated

export function getKeymanRoot(): string {
const __dirname = dirname(fileURLToPath(import.meta.url));
return process.env['KEYMAN_ROOT'] ?? (__dirname + '/../../../../../../');
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we just use:

Suggested change
return process.env['KEYMAN_ROOT'] ?? (__dirname + '/../../../../../../');
return __dirname + '/../../../../../../';

And never reference the KEYMAN_ROOT variable at all? I don't see any benefit to having both methods here.

Co-authored-by: Marc Durdin <marc@durdin.net>
For the files touched in this PR:

- fix the order of the imports according to style guide
- use `node:` prefix for node modules
- add header
@ermshiperete ermshiperete merged commit 66c5f12 into epic/web-core Mar 23, 2026
15 of 16 checks passed
@ermshiperete ermshiperete deleted the maint/web/jstests branch March 23, 2026 17:15
@github-project-automation github-project-automation Bot moved this from Todo to Done in Keyman Mar 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

epic-web-core maint Maintenance work -- continuous integration, build scripts, infrastructure web/

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

3 participants