From 229bdf8270cf6a77eec985a26d13035643853c46 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Tue, 30 Sep 2025 17:01:52 +0200 Subject: [PATCH] maint(resources): nest unit tests under parent block This adds a modified `mocha-teamcity-reporter` that allows to nest the unit tests under the parent block. Fixes: #14839 Test-bot: skip --- .../mocha-teamcity-reporter/README.md | 8 + .../mocha-teamcity-reporter/teamcity.cjs | 259 ++++++++++++++++++ .../sourcemap-path-remapper/package.json | 1 - package-lock.json | 19 -- package.json | 3 +- .../build/pr-build-status/package-lock.json | 16 +- resources/build/pr-build-status/package.json | 5 +- resources/build/typescript.inc.sh | 12 +- web/common.inc.sh | 20 +- web/src/engine/common/web-utils/build.sh | 14 +- web/src/engine/common/web-utils/package.json | 1 - .../engine/osk/gesture-processor/package.json | 1 - .../predictive-text/templates/package.json | 1 - .../predictive-text/wordbreakers/build.sh | 14 +- .../predictive-text/wordbreakers/package.json | 1 - .../predictive-text/worker-main/package.json | 1 - .../worker-main/unit_tests/test.sh | 11 +- .../worker-thread/package.json | 1 - 18 files changed, 321 insertions(+), 67 deletions(-) create mode 100644 common/test/resources/mocha-teamcity-reporter/README.md create mode 100644 common/test/resources/mocha-teamcity-reporter/teamcity.cjs diff --git a/common/test/resources/mocha-teamcity-reporter/README.md b/common/test/resources/mocha-teamcity-reporter/README.md new file mode 100644 index 0000000000..6060f53a5d --- /dev/null +++ b/common/test/resources/mocha-teamcity-reporter/README.md @@ -0,0 +1,8 @@ +# Custom mocha reporter for TeamCity + +This is an enhanced version of the [mocha-teamcity-reporter](https://github.com/travisjeffery/mocha-teamcity-reporter) +(renamed to *.cjs) that allows to specify the parent flowId so that the tests +can be grouped together under the parent block in TeamCity. + +If [travisjeffery/mocha-teamcity-reporter#69](https://github.com/travisjeffery/mocha-teamcity-reporter/issues/69) +gets fixed one day, we can go back to using the original version. diff --git a/common/test/resources/mocha-teamcity-reporter/teamcity.cjs b/common/test/resources/mocha-teamcity-reporter/teamcity.cjs new file mode 100644 index 0000000000..24c76a5f2b --- /dev/null +++ b/common/test/resources/mocha-teamcity-reporter/teamcity.cjs @@ -0,0 +1,259 @@ +/* eslint-disable complexity */ +/** + * Teamcity doc reference https://confluence.jetbrains.com/display/TCD10/Build+Script+Interaction+with+TeamCity + * + * Module dependencies. + */ +'use strict'; + +const processPID = process.pid.toString(); +const TEST_IGNORED = `##teamcity[testIgnored name='%s' message='%s']`; +const SUITE_START = `##teamcity[testSuiteStarted name='%s']`; +const SUITE_END = `##teamcity[testSuiteFinished name='%s' duration='%s']`; +const SUITE_END_NO_DURATION = `##teamcity[testSuiteFinished name='%s']`; +const TEST_START = `##teamcity[testStarted name='%s' captureStandardOutput='true']`; +const TEST_FAILED = `##teamcity[testFailed name='%s' message='%s' details='%s' captureStandardOutput='true']`; +const TEST_FAILED_COMPARISON = `##teamcity[testFailed type='comparisonFailure' name='%s' message='%s' \ +details='%s' captureStandardOutput='true' actual='%s' expected='%s']`; +const TEST_END = `##teamcity[testFinished name='%s' duration='%s']`; +const TEST_END_NO_DURATION = `##teamcity[testFinished name='%s']`; +const FLOW_START = `##teamcity[flowStarted flowId='%s' parent='%s']`; +const FLOW_END = `##teamcity[flowFinished flowId='%s']`; + +const Mocha = require('mocha'); +const { + EVENT_SUITE_BEGIN, + EVENT_TEST_BEGIN, + EVENT_TEST_FAIL, + EVENT_TEST_PENDING, + EVENT_TEST_END, + EVENT_HOOK_BEGIN, + EVENT_HOOK_END, + EVENT_SUITE_END, + EVENT_RUN_END +} = Mocha.Runner.constants; + +const util = require('util'); + +let Base, log, logError; + +Base = require('mocha').reporters.Base; +log = console.log; +logError = console.error; + +let flowIds = []; + +/** + * Escape the given `str`. + */ + +function escape(str) { + if (!str) return ''; + return str + .toString() + .replace(/\x1B.*?m/g, '') // eslint-disable-line no-control-regex + .replace(/\|/g, '||') + .replace(/\n/g, '|n') + .replace(/\r/g, '|r') + .replace(/\[/g, '|[') + .replace(/\]/g, '|]') + .replace(/\u0085/g, '|x') + .replace(/\u2028/g, '|l') + .replace(/\u2029/g, '|p') + .replace(/'/g, '|\''); +} + +function isNil(value) { + return value == null; // eslint-disable-line +} + +function formatString() { + let formattedArguments = []; + const args = Array.prototype.slice.call(arguments, 0); + // Format all arguments for TC display (it escapes using the pipe char). + let tcMessage = args.shift(); + args.forEach((param) => { + formattedArguments.push(escape(param)); + }); + formattedArguments.unshift(tcMessage); + return util.format.apply(util, formattedArguments); +} + +function handleFlow(isStarted, nestFlows) { + if (!nestFlows) { + return; + } + if (isStarted) { + flowIds.push(Math.floor(Math.random() * 100000 + 1)); + log(formatString(FLOW_START, flowIds[flowIds.length - 1], flowIds[flowIds.length - 2])); + } else { + log(formatString(FLOW_END, flowIds[flowIds.length - 1])); + flowIds.pop(); + } +} + +function getFlowId() { + return flowIds[flowIds.length - 1]; +} + +/** + * Initialize a new `Teamcity` reporter. + * + * @param {Runner} runner + * @param {options} options + * @api public + */ + +function Teamcity(runner, options) { + options = options || {}; + const reporterOptions = options.reporterOptions || {}; + let flowIdOpt, useStdError, recordHookFailures, actualVsExpected, ignoreHookWithName, displayIgnoredAsIgnored; + (reporterOptions.flowId) ? flowIdOpt = reporterOptions.flowId : flowIdOpt = process.env['MOCHA_TEAMCITY_FLOWID'] || processPID; + (reporterOptions.useStdError) ? useStdError = reporterOptions.useStdError : useStdError = process.env['USE_STD_ERROR']; + (reporterOptions.recordHookFailures) ? recordHookFailures = reporterOptions.recordHookFailures : recordHookFailures = process.env['RECORD_HOOK_FAILURES']; + (reporterOptions.actualVsExpected) ? actualVsExpected = reporterOptions.actualVsExpected : actualVsExpected = process.env['ACTUAL_VS_EXPECTED']; + (reporterOptions.ignoreHookWithName) ? ignoreHookWithName = reporterOptions.ignoreHookWithName : ignoreHookWithName = process.env['IGNORE_HOOK_WITH_NAME']; + (reporterOptions.displayIgnoredAsIgnored) + ? displayIgnoredAsIgnored = reporterOptions.displayIgnoredAsIgnored + : displayIgnoredAsIgnored = process.env['DISPLAY_IGNORED_AS_IGNORED']; + (useStdError) ? useStdError = (useStdError.toLowerCase() === 'true') : useStdError = false; + (recordHookFailures) ? recordHookFailures = (recordHookFailures.toLowerCase() === 'true') : recordHookFailures = false; + (displayIgnoredAsIgnored) ? displayIgnoredAsIgnored = (displayIgnoredAsIgnored.toLowerCase() === 'true') : displayIgnoredAsIgnored = false; + (ignoreHookWithName) ? ignoreHookWithName : null; + actualVsExpected ? actualVsExpected = (actualVsExpected.toLowerCase() === 'true') : actualVsExpected = false; + Base.call(this, runner); + let stats = this.stats; + const topLevelSuite = reporterOptions.topLevelSuite || process.env['MOCHA_TEAMCITY_TOP_LEVEL_SUITE']; + const parentFlowId = reporterOptions.parentFlowId || process.env['MOCHA_TEAMCITY_PARENT_FLOW_ID']; + if (parentFlowId) { + flowIds.push(parentFlowId); + } else { + flowIds.push(flowIdOpt); + } + const hasParentFlowId = !!parentFlowId; + + const ignoredTests = {}; + const testState = { pending: 0 }; + + runner.on(EVENT_SUITE_BEGIN, function (suite) { + handleFlow(true, hasParentFlowId); + if (suite.root) { + if (topLevelSuite) { + log(formatString(SUITE_START, topLevelSuite)); + } + return; + } + suite.startDate = new Date(); + log(formatString(SUITE_START, suite.title)); + }); + + runner.on(EVENT_TEST_BEGIN, function (test) { + if (displayIgnoredAsIgnored && ignoredTests[`${test.title}-${getFlowId()}`] === testState.pending) { + return; + } + handleFlow(true, hasParentFlowId); + log(formatString(TEST_START, test.title)); + }); + + runner.on(EVENT_TEST_FAIL, function (test, err) { + let isHook = false; + if (test.title.includes(`"before all" hook`) || + test.title.includes(`"before each" hook`) || + test.title.includes(`"after all" hook`) || + test.title.includes(`"after each" hook`) + ) { + isHook = true; + } + + if(actualVsExpected && (err.actual && err.expected)){ + if (useStdError) { + logError(formatString(TEST_FAILED_COMPARISON, + test.title, err.message, err.stack, err.actual, err.expected)); + } else { + log(formatString(TEST_FAILED_COMPARISON, test.title, err.message, err.stack, err.actual, err.expected)); + } + } else{ + if (useStdError) { + logError(formatString(TEST_FAILED, test.title, err.message, err.stack)); + } else { + log(formatString(TEST_FAILED, test.title, err.message, err.stack)); + } + } + // Log testFinished for failed hook (hook end event is not fired for failed hook) + if (recordHookFailures && !ignoreHookWithName || recordHookFailures && ignoreHookWithName && !test.title.includes(ignoreHookWithName)) { + if (isHook) { + if(isNil(test.duration)){ + log(formatString(TEST_END_NO_DURATION, test.title)); + } else { + log(formatString(TEST_END, test.title, test.duration.toString())); + } + handleFlow(false, hasParentFlowId); + } + } + }); + + runner.on(EVENT_TEST_PENDING, function (test) { + log(formatString(TEST_IGNORED, test.title, test.title)); + if (displayIgnoredAsIgnored) { + ignoredTests[`${test.title}-${getFlowId()}`] = testState.pending; + } else { + handleFlow(true, hasParentFlowId) + } + }); + + runner.on(EVENT_TEST_END, function (test) { + if (displayIgnoredAsIgnored && ignoredTests[`${test.title}-${getFlowId()}`] === testState.pending) { + delete ignoredTests[`${test.title}-${getFlowId()}`]; + return; + } + if(isNil(test.duration)){ + log(formatString(TEST_END_NO_DURATION, test.title)); + } else { + log(formatString(TEST_END, test.title, test.duration.toString())); + } + handleFlow(false, hasParentFlowId); + }); + + runner.on(EVENT_HOOK_BEGIN, function (test) { + if (recordHookFailures && !ignoreHookWithName || recordHookFailures && ignoreHookWithName && !test.title.includes(ignoreHookWithName)) { + handleFlow(true, hasParentFlowId); + log(formatString(TEST_START, test.title)); + } + }); + + runner.on(EVENT_HOOK_END, function (test) { + if (recordHookFailures && !ignoreHookWithName || recordHookFailures && ignoreHookWithName && !test.title.includes(ignoreHookWithName)) { + if(isNil(test.duration)){ + log(formatString(TEST_END_NO_DURATION, test.title)); + } else { + log(formatString(TEST_END, test.title, test.duration.toString())); + } + handleFlow(false, hasParentFlowId); + } + }); + + runner.on(EVENT_SUITE_END, function (suite) { + if (!suite.root) { + log(formatString(SUITE_END, suite.title, new Date() - suite.startDate)); + } + handleFlow(false, hasParentFlowId); + }); + + runner.on(EVENT_RUN_END, function () { + let duration; + (typeof stats === 'undefined') ? duration = null : duration = stats.duration; + if (topLevelSuite) { + isNil(duration) + ? log(formatString(SUITE_END_NO_DURATION, topLevelSuite)) + : log(formatString(SUITE_END, topLevelSuite, duration)); + handleFlow(false, hasParentFlowId); + } + }); +} + + +/** + * Expose `Teamcity`. + */ + +exports = module.exports = Teamcity; diff --git a/common/tools/sourcemap-path-remapper/package.json b/common/tools/sourcemap-path-remapper/package.json index 88aaae8296..21252bfee0 100644 --- a/common/tools/sourcemap-path-remapper/package.json +++ b/common/tools/sourcemap-path-remapper/package.json @@ -18,7 +18,6 @@ "homepage": "https://github.com/keymanapp/keyman#readme", "devDependencies": { "@keymanapp/resources-gosh": "*", - "mocha-teamcity-reporter": "^4.0.0", "typescript": "^5.4.5" }, "dependencies": { diff --git a/package-lock.json b/package-lock.json index c5286e36b4..7618527727 100644 --- a/package-lock.json +++ b/package-lock.json @@ -64,7 +64,6 @@ "eslint-plugin-n": "^15.7.0", "eslint-plugin-promise": "^6.1.1", "mocha": "^11.2.2", - "mocha-teamcity-reporter": "^4.0.0", "playwright": "^1.46.1", "sinon": "^17.0.1", "source-map-support": "^0.5.21", @@ -109,7 +108,6 @@ }, "devDependencies": { "@keymanapp/resources-gosh": "*", - "mocha-teamcity-reporter": "^4.0.0", "typescript": "^5.4.5" } }, @@ -10251,17 +10249,6 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/mocha-teamcity-reporter": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "mocha": ">=6" - } - }, "node_modules/mocha/node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -14235,7 +14222,6 @@ "@keymanapp/keyman-version": "*", "@keymanapp/resources-gosh": "*", "c8": "^7.12.0", - "mocha-teamcity-reporter": "^4.0.0", "typescript": "^5.4.5" } }, @@ -14247,7 +14233,6 @@ }, "devDependencies": { "@keymanapp/resources-gosh": "*", - "mocha-teamcity-reporter": "^4.0.0", "promise-status-async": "^1.2.10", "typescript": "^5.4.5" } @@ -14266,7 +14251,6 @@ "@keymanapp/web-utils": "*", "@types/mocha": "^7.0.2", "c8": "^7.12.0", - "mocha-teamcity-reporter": "^4.0.0", "typescript": "^5.4.5" } }, @@ -14285,7 +14269,6 @@ "@keymanapp/resources-gosh": "*", "@types/mocha": "^7.0.2", "c8": "^7.12.0", - "mocha-teamcity-reporter": "^4.0.0", "typescript": "^5.4.5" } }, @@ -14303,7 +14286,6 @@ "devDependencies": { "@keymanapp/common-types": "*", "@keymanapp/resources-gosh": "*", - "mocha-teamcity-reporter": "^4.0.0", "typescript": "^5.4.5" } }, @@ -14325,7 +14307,6 @@ "@keymanapp/resources-gosh": "*", "c8": "^7.12.0", "combine-source-map": "^0.8.0", - "mocha-teamcity-reporter": "^4.0.0", "typescript": "^5.4.5" } }, diff --git a/package.json b/package.json index ed22577419..9ce87b3f12 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,6 @@ "eslint-plugin-n": "^15.7.0", "eslint-plugin-promise": "^6.1.1", "mocha": "^11.2.2", - "mocha-teamcity-reporter": "^4.0.0", "playwright": "^1.46.1", "sinon": "^17.0.1", "source-map-support": "^0.5.21", @@ -61,11 +60,11 @@ ], "dependencies": { "@keymanapp/common-types": "file:common/web/types", - "@keymanapp/langtags": "file:common/web/langtags", "@keymanapp/developer-test-helpers": "file:developer/src/common/web/test-helpers", "@keymanapp/developer-utils": "file:developer/src/common/web/utils", "@keymanapp/hextobin": "file:common/tools/hextobin", "@keymanapp/keyman-version": "file:common/web/keyman-version", + "@keymanapp/langtags": "file:common/web/langtags", "@keymanapp/ldml-keyboard-constants": "file:core/include/ldml" }, "overrides": { diff --git a/resources/build/pr-build-status/package-lock.json b/resources/build/pr-build-status/package-lock.json index ff65ee2506..4fbde7f3ba 100644 --- a/resources/build/pr-build-status/package-lock.json +++ b/resources/build/pr-build-status/package-lock.json @@ -12,8 +12,7 @@ }, "devDependencies": { "chai": "^5.1.0", - "mocha": "^11.2.2", - "mocha-teamcity-reporter": "^4.0.0" + "mocha": "^11.2.2" } }, "node_modules/@actions/core": { @@ -904,19 +903,6 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/mocha-teamcity-reporter": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/mocha-teamcity-reporter/-/mocha-teamcity-reporter-4.2.0.tgz", - "integrity": "sha512-H08IvAIsiCcdXAEObzp/VvJHFfLummxt5wpr0gU4yxx6pTb7ZmKnVjyXkFi+3gYi3bu/j2iJdoK9Aknz16mbBg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "mocha": ">=6" - } - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", diff --git a/resources/build/pr-build-status/package.json b/resources/build/pr-build-status/package.json index 5e9dc1bc70..1d57f981a5 100644 --- a/resources/build/pr-build-status/package.json +++ b/resources/build/pr-build-status/package.json @@ -6,9 +6,8 @@ "@actions/github": "^6.0.1" }, "devDependencies": { - "mocha": "^11.2.2", - "mocha-teamcity-reporter": "^4.0.0", - "chai": "^5.1.0" + "chai": "^5.1.0", + "mocha": "^11.2.2" }, "license": "MIT", "main": "pr-build-status.mjs", diff --git a/resources/build/typescript.inc.sh b/resources/build/typescript.inc.sh index 6cefab98ac..ef6f58d68a 100644 --- a/resources/build/typescript.inc.sh +++ b/resources/build/typescript.inc.sh @@ -10,12 +10,13 @@ # 1: coverage_threshold optional, minimum coverage for c8 to pass tests, # defaults to 90 (percent) typescript_run_eslint_mocha_tests() { - local MOCHA_FLAGS= + local MOCHA_FLAGS=() local TEST_DIR if builder_is_running_on_teamcity; then # we're running in TeamCity - MOCHA_FLAGS="-reporter mocha-teamcity-reporter" + MOCHA_FLAGS+=(--reporter "${KEYMAN_ROOT}/common/test/resources/mocha-teamcity-reporter/teamcity.cjs" --reporter-options parentFlowId="unit_tests") + echo "##teamcity[flowStarted flowId='unit_tests']" fi eslint . @@ -45,10 +46,15 @@ typescript_run_eslint_mocha_tests() { THRESHOLD_PARAMS="--lines 90 --statements 90 --branches 80 --functions 80" fi - c8 --reporter=lcov --reporter=text --exclude-after-remap --check-coverage $THRESHOLD_PARAMS mocha ${MOCHA_FLAGS} "${builder_extra_params[@]}" + c8 --reporter=lcov --reporter=text --exclude-after-remap --check-coverage ${THRESHOLD_PARAMS} mocha "${MOCHA_FLAGS[@]}" "${builder_extra_params[@]}" if [[ ! -z "${C8_THRESHOLD}" ]]; then builder_echo warning "Coverage thresholds are currently ${C8_THRESHOLD}%, which is lower than ideal." builder_echo warning "Please increase threshold in build.sh as test coverage improves." fi + + if builder_is_running_on_teamcity; then + # we're running in TeamCity + echo "##teamcity[flowFinished flowId='unit_tests']" + fi } diff --git a/web/common.inc.sh b/web/common.inc.sh index fed2af8c7b..32249094a3 100644 --- a/web/common.inc.sh +++ b/web/common.inc.sh @@ -100,18 +100,24 @@ function test-headless() { tsc --project "${KEYMAN_ROOT}/web/src/test/auto/tsconfig.json" fi - TEST_OPTS= - if builder_is_ci_build; then - TEST_OPTS="--reporter mocha-teamcity-reporter" + 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']" fi - if [[ -n "$TEST_EXTENSIONS" ]]; then - TEST_OPTS="$TEST_OPTS --extension $TEST_EXTENSIONS" + if [[ -n "${TEST_EXTENSIONS}" ]]; then + TEST_OPTS+=(--extension "${TEST_EXTENSIONS}") fi if [[ -e .c8rc.json ]]; then - c8 mocha --recursive "${TEST_BASE}${TEST_FOLDER}" $TEST_OPTS + c8 mocha --recursive "${TEST_BASE}${TEST_FOLDER}" "${TEST_OPTS[@]}" else - mocha --recursive "${TEST_BASE}${TEST_FOLDER}" $TEST_OPTS + mocha --recursive "${TEST_BASE}${TEST_FOLDER}" "${TEST_OPTS[@]}" + fi + + if builder_is_running_on_teamcity; then + # we're running in TeamCity + echo "##teamcity[flowFinished flowId='unit_tests']" fi } diff --git a/web/src/engine/common/web-utils/build.sh b/web/src/engine/common/web-utils/build.sh index 9d9114986f..23d38cb952 100755 --- a/web/src/engine/common/web-utils/build.sh +++ b/web/src/engine/common/web-utils/build.sh @@ -48,13 +48,19 @@ function do_build() { function do_test() { builder_heading "Running web-utils test suite" - local FLAGS= - if builder_is_ci_build; then + local FLAGS=() + if builder_is_running_on_teamcity; then echo "Replacing user-friendly test reports with CI-friendly versions." - FLAGS="$FLAGS --reporter mocha-teamcity-reporter" + FLAGS+=(--reporter "${KEYMAN_ROOT}/common/test/resources/mocha-teamcity-reporter/teamcity.cjs" --reporter-options parentFlowId="unit_tests") + echo "##teamcity[flowStarted flowId='unit_tests']" fi - c8 mocha --recursive $FLAGS ./src/tests/ + c8 mocha --recursive "${FLAGS[@]}" ./src/tests/ + + if builder_is_running_on_teamcity; then + # we're running in TeamCity + echo "##teamcity[flowFinished flowId='unit_tests']" + fi } builder_run_action configure node_select_version_and_npm_ci diff --git a/web/src/engine/common/web-utils/package.json b/web/src/engine/common/web-utils/package.json index 85e194a648..557878d43e 100644 --- a/web/src/engine/common/web-utils/package.json +++ b/web/src/engine/common/web-utils/package.json @@ -27,7 +27,6 @@ "@keymanapp/keyman-version": "*", "@keymanapp/resources-gosh": "*", "c8": "^7.12.0", - "mocha-teamcity-reporter": "^4.0.0", "typescript": "^5.4.5" }, "type": "module", diff --git a/web/src/engine/osk/gesture-processor/package.json b/web/src/engine/osk/gesture-processor/package.json index 8aad89f94c..c74ff5a3de 100644 --- a/web/src/engine/osk/gesture-processor/package.json +++ b/web/src/engine/osk/gesture-processor/package.json @@ -3,7 +3,6 @@ "description": "The core gesture-recognition engine used by Keyman's Web-based OSKs.", "devDependencies": { "@keymanapp/resources-gosh": "*", - "mocha-teamcity-reporter": "^4.0.0", "promise-status-async": "^1.2.10", "typescript": "^5.4.5" }, diff --git a/web/src/engine/predictive-text/templates/package.json b/web/src/engine/predictive-text/templates/package.json index fd80f2d43e..cbe3fb8747 100644 --- a/web/src/engine/predictive-text/templates/package.json +++ b/web/src/engine/predictive-text/templates/package.json @@ -55,7 +55,6 @@ "@keymanapp/web-utils": "*", "@types/mocha": "^7.0.2", "c8": "^7.12.0", - "mocha-teamcity-reporter": "^4.0.0", "typescript": "^5.4.5" }, "dependencies": { diff --git a/web/src/engine/predictive-text/wordbreakers/build.sh b/web/src/engine/predictive-text/wordbreakers/build.sh index 21617a89ed..8deb49493e 100755 --- a/web/src/engine/predictive-text/wordbreakers/build.sh +++ b/web/src/engine/predictive-text/wordbreakers/build.sh @@ -48,13 +48,19 @@ function do_build() { } function do_test() { - local FLAGS= + local FLAGS=() - if builder_is_ci_build; then - FLAGS="-reporter mocha-teamcity-reporter" + if builder_is_running_on_teamcity; then + FLAGS+=(--reporter "${KEYMAN_ROOT}/common/test/resources/mocha-teamcity-reporter/teamcity.cjs" --reporter-options parentFlowId="unit_tests") + echo "##teamcity[flowStarted flowId='unit_tests']" fi - c8 mocha ${FLAGS} tests + c8 mocha "${FLAGS[@]}" tests + + if builder_is_running_on_teamcity; then + # we're running in TeamCity + echo "##teamcity[flowFinished flowId='unit_tests']" + fi } builder_run_action configure do_configure diff --git a/web/src/engine/predictive-text/wordbreakers/package.json b/web/src/engine/predictive-text/wordbreakers/package.json index c3eebde3be..0f73f19f69 100644 --- a/web/src/engine/predictive-text/wordbreakers/package.json +++ b/web/src/engine/predictive-text/wordbreakers/package.json @@ -58,7 +58,6 @@ "@keymanapp/resources-gosh": "*", "@types/mocha": "^7.0.2", "c8": "^7.12.0", - "mocha-teamcity-reporter": "^4.0.0", "typescript": "^5.4.5" }, "type": "module" diff --git a/web/src/engine/predictive-text/worker-main/package.json b/web/src/engine/predictive-text/worker-main/package.json index 2ef91e27f7..535532d680 100644 --- a/web/src/engine/predictive-text/worker-main/package.json +++ b/web/src/engine/predictive-text/worker-main/package.json @@ -44,7 +44,6 @@ "devDependencies": { "@keymanapp/common-types": "*", "@keymanapp/resources-gosh": "*", - "mocha-teamcity-reporter": "^4.0.0", "typescript": "^5.4.5" }, "dependencies": { diff --git a/web/src/engine/predictive-text/worker-main/unit_tests/test.sh b/web/src/engine/predictive-text/worker-main/unit_tests/test.sh index ac74abd590..96176c7c0b 100755 --- a/web/src/engine/predictive-text/worker-main/unit_tests/test.sh +++ b/web/src/engine/predictive-text/worker-main/unit_tests/test.sh @@ -26,14 +26,19 @@ builder_describe "Runs all tests for the language-modeling / predictive-text lay builder_parse "$@" function do_test_headless() { - MOCHA_FLAGS=${FLAGS} + MOCHA_FLAGS=(${FLAGS}) if builder_is_running_on_teamcity; then - MOCHA_FLAGS="${MOCHA_FLAGS} --reporter mocha-teamcity-reporter" + MOCHA_FLAGS+=(--reporter "${KEYMAN_ROOT}/common/test/resources/mocha-teamcity-reporter/teamcity.cjs" --reporter-options parentFlowId="unit_tests") + echo "##teamcity[flowStarted flowId='unit_tests']" fi - mocha --recursive ${MOCHA_FLAGS} ./headless/*.js ./headless/**/*.js + mocha --recursive "${MOCHA_FLAGS[@]}" ./headless/*.js ./headless/**/*.js + if builder_is_running_on_teamcity; then + # we're running in TeamCity + echo "##teamcity[flowFinished flowId='unit_tests']" + fi } function do_test_browser() { diff --git a/web/src/engine/predictive-text/worker-thread/package.json b/web/src/engine/predictive-text/worker-thread/package.json index f210f51000..f0807d074e 100644 --- a/web/src/engine/predictive-text/worker-thread/package.json +++ b/web/src/engine/predictive-text/worker-thread/package.json @@ -33,7 +33,6 @@ "@keymanapp/resources-gosh": "*", "c8": "^7.12.0", "combine-source-map": "^0.8.0", - "mocha-teamcity-reporter": "^4.0.0", "typescript": "^5.4.5" }, "dependencies": {