diff --git a/.gitignore b/.gitignore index d91d90e..2981d33 100644 --- a/.gitignore +++ b/.gitignore @@ -64,7 +64,6 @@ node_modules/ out/ test-dist/ test-esm/ -browser/ types/ build/ dist/ diff --git a/common/config/rush/npm-shrinkwrap.json b/common/config/rush/npm-shrinkwrap.json index 55abc76..266c17c 100644 --- a/common/config/rush/npm-shrinkwrap.json +++ b/common/config/rush/npm-shrinkwrap.json @@ -28,11 +28,7 @@ "grunt-cli": "^1.4.3", "karma": "^6.3.20", "karma-chrome-launcher": "^3.1.1", - "karma-coverage": "^2.2.0", - "karma-coverage-istanbul-reporter": "^3.0.3", "karma-mocha": "^2.0.1", - "karma-mocha-webworker": "^1.3.0", - "karma-rollup-preprocessor": "^7.0.8", "karma-spec-reporter": "^0.0.36", "karma-typescript": "^5.5.3", "mocha": "^10.0.0", @@ -101,6 +97,11 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -1120,7 +1121,7 @@ "node_modules/@rush-temp/ts-async": { "version": "0.0.0", "resolved": "file:projects/ts-async.tgz", - "integrity": "sha512-6NQSYX+FXFfMUD5f7WKKJ3ywWuIdmNsiJgaN3yx1yLVUlOTAB6tHc5lMk7b/Koanp+tYoHbQFLz53MucSf7F5g==", + "integrity": "sha512-tiw1ersuNxy54YNlDo6I4L0dn2ql3jXl01d0uIKxQ+TTjcVRZEWt8lCLnoz6kMSWLs35QYud47nnDaR0Vx2Uvg==", "dependencies": { "@istanbuljs/nyc-config-typescript": "^1.0.2", "@microsoft/api-extractor": "^7.48.1", @@ -1141,11 +1142,7 @@ "grunt-cli": "^1.4.3", "karma": "^6.3.20", "karma-chrome-launcher": "^3.1.1", - "karma-coverage": "^2.2.0", - "karma-coverage-istanbul-reporter": "^3.0.3", "karma-mocha": "^2.0.1", - "karma-mocha-webworker": "^1.3.0", - "karma-rollup-preprocessor": "^7.0.8", "karma-spec-reporter": "^0.0.36", "karma-typescript": "^5.5.3", "mocha": "^10.0.0", @@ -2579,9 +2576,9 @@ } }, "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, "node_modules/cookie": { "version": "0.7.2", @@ -2824,11 +2821,6 @@ "node": "*" } }, - "node_modules/debounce": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", - "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" - }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -4885,14 +4877,13 @@ } }, "node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", + "@babel/core": "^7.7.5", "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-coverage": "^3.0.0", "semver": "^6.3.0" }, "engines": { @@ -5072,16 +5063,6 @@ "node": ">=6" } }, - "node_modules/jsonbird": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/jsonbird/-/jsonbird-2.2.2.tgz", - "integrity": "sha512-48n9HTL6Vxhr6WqX78ROH5NddK//ZnSdu1ZnPyyOl9IzF2PyRmwC8nCKPiRFo1wx7/Byq5YezCqokq9T/McLhw==", - "dependencies": { - "jsonparse": "^1.2.0", - "readable-stream": "^2.1.4", - "shortid": "^2.2.6" - } - }, "node_modules/jsonfile": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", @@ -5093,14 +5074,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "engines": [ - "node >= 0.2.0" - ] - }, "node_modules/just-extend": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", @@ -5162,130 +5135,6 @@ "which": "bin/which" } }, - "node_modules/karma-coverage": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.2.1.tgz", - "integrity": "sha512-yj7hbequkQP2qOSb20GuNSIyE//PgJWHwC2IydLE6XRtsnaflv+/OSGNssPjobYUlhVVagy99TQpqUt3vAUG7A==", - "dependencies": { - "istanbul-lib-coverage": "^3.2.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.1", - "istanbul-reports": "^3.0.5", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/karma-coverage-istanbul-reporter": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-3.0.3.tgz", - "integrity": "sha512-wE4VFhG/QZv2Y4CdAYWDbMmcAHeS926ZIji4z+FkB2aF/EposRb6DP6G5ncT/wXhqUfAb/d7kZrNKPonbvsATw==", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^3.0.6", - "istanbul-reports": "^3.0.2", - "minimatch": "^3.0.4" - }, - "funding": { - "url": "https://github.com/sponsors/mattlewis92" - } - }, - "node_modules/karma-coverage-istanbul-reporter/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/karma-coverage-istanbul-reporter/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/karma-coverage-istanbul-reporter/node_modules/istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/karma-coverage-istanbul-reporter/node_modules/istanbul-lib-source-maps/node_modules/istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/karma-coverage-istanbul-reporter/node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/karma-coverage-istanbul-reporter/node_modules/minimatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.3.tgz", - "integrity": "sha512-M2GCs7Vk83NxkUyQV1bkABc4yxgz9kILhHImZiBPAZ9ybuvCb0/H7lEl5XvIg3g+9d4eNotkZA5IWwYl0tibaA==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/karma-coverage-istanbul-reporter/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/karma-coverage/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/karma-coverage/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/karma-coverage/node_modules/minimatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.3.tgz", - "integrity": "sha512-M2GCs7Vk83NxkUyQV1bkABc4yxgz9kILhHImZiBPAZ9ybuvCb0/H7lEl5XvIg3g+9d4eNotkZA5IWwYl0tibaA==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/karma-mocha": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/karma-mocha/-/karma-mocha-2.0.1.tgz", @@ -5294,58 +5143,6 @@ "minimist": "^1.2.3" } }, - "node_modules/karma-mocha-webworker": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/karma-mocha-webworker/-/karma-mocha-webworker-1.3.0.tgz", - "integrity": "sha512-2DCnE7QkMblSHzm+ZphwdKgdURxoK4xrblNfryAB5PQ6ntpylY/dAGO1X0d1h+n6Qni8DT2AzpuwEfjpxAFHdg==", - "dependencies": { - "jsonbird": "^2.0.0", - "minimatch": "^3.0.3" - }, - "peerDependencies": { - "mocha": "*" - } - }, - "node_modules/karma-mocha-webworker/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/karma-mocha-webworker/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/karma-mocha-webworker/node_modules/minimatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.3.tgz", - "integrity": "sha512-M2GCs7Vk83NxkUyQV1bkABc4yxgz9kILhHImZiBPAZ9ybuvCb0/H7lEl5XvIg3g+9d4eNotkZA5IWwYl0tibaA==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/karma-rollup-preprocessor": { - "version": "7.0.8", - "resolved": "https://registry.npmjs.org/karma-rollup-preprocessor/-/karma-rollup-preprocessor-7.0.8.tgz", - "integrity": "sha512-WiuBCS9qsatJuR17dghiTARBZ7LF+ml+eb7qJXhw7IbsdY0lTWELDRQC/93J9i6636CsAXVBL3VJF4WtaFLZzA==", - "dependencies": { - "chokidar": "^3.3.1", - "debounce": "^1.2.0" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": ">= 1.0.0" - } - }, "node_modules/karma-spec-reporter": { "version": "0.0.36", "resolved": "https://registry.npmjs.org/karma-spec-reporter/-/karma-spec-reporter-0.0.36.tgz", @@ -5433,11 +5230,6 @@ "concat-map": "0.0.1" } }, - "node_modules/karma-typescript/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" - }, "node_modules/karma-typescript/node_modules/diff": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", @@ -5446,20 +5238,6 @@ "node": ">=0.3.1" } }, - "node_modules/karma-typescript/node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/karma-typescript/node_modules/minimatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.3.tgz", @@ -5492,14 +5270,6 @@ "node": ">= 6" } }, - "node_modules/karma-typescript/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/karma-typescript/node_modules/source-map": { "version": "0.7.6", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", @@ -6061,23 +5831,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -6248,11 +6001,6 @@ "wrap-ansi": "^6.2.0" } }, - "node_modules/nyc/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" - }, "node_modules/nyc/node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -6853,14 +6601,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "engines": { - "node": ">=6" - } - }, "node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -7732,14 +7472,6 @@ "node": ">=8" } }, - "node_modules/shortid": { - "version": "2.2.17", - "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.17.tgz", - "integrity": "sha512-GpbM3gLF1UUXZvQw6MCyulHkWbRseNO4cyBEZresZRorwl1+SLu1ZdqgVtuwqz8mB6RpwPkm541mYSqrKyJSaA==", - "dependencies": { - "nanoid": "^3.3.8" - } - }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", diff --git a/common/test/worker-adapter.js b/common/test/worker-adapter.js new file mode 100644 index 0000000..4cc2bfb --- /dev/null +++ b/common/test/worker-adapter.js @@ -0,0 +1,190 @@ +/* + * @nevware21/ts-async + * https://github.com/nevware21/ts-async + * + * Copyright (c) 2026 NevWare21 Solutions LLC + * Licensed under the MIT license. + */ + +/** + * Worker Test Adapter - Runs in main page context + * Creates Web Worker, loads tests, and reports results to Karma + */ + +(function() { + "use strict"; + + function initWorkerAdapter() { + var karma = window.__karma__; + + if (!karma) { + console.log("[worker-adapter] __karma__ not available yet, will retry"); + setTimeout(initWorkerAdapter, 50); + return; + } + + console.log("[worker-adapter] Starting worker test setup"); + + // Override mocha.run to prevent normal test execution and run tests in worker instead + if (window.mocha && typeof window.mocha.run === "function") { + window.mocha.run = function() { + console.log("[worker-adapter] Mocha.run intercepted - running tests in worker"); + startWorkerTests(); + + // Return a mock runner to satisfy Mocha's expectations + return { + on: function() { return this; } + }; + }; + } else { + console.log("[worker-adapter] Mocha not found"); + } + + function startWorkerTests() { + console.log("[worker-adapter] Initializing worker tests"); + + var bundleFiles = []; + var moduleShims = []; + var jsFiles = []; + var files = karma.files; + var mochaFile = null; + var commonjsFile = null; + + console.log("[worker-adapter] Total files from karma: " + Object.keys(files).length); + + for (var file in files) { + if (!files.hasOwnProperty(file)) { + continue; + } + + // Collect karma-typescript bundles + if (/karma-typescript-bundle-.*\.js(\?|$)/.test(file)) { + bundleFiles.push(file); + continue; + } + + // Detect Mocha runtime file + if (!mochaFile && /\/node_modules\/mocha\/mocha\.js(\?|$)/.test(file)) { + mochaFile = file; + continue; + } + + // Detect karma-typescript commonjs runtime file + if (!commonjsFile && /\/node_modules\/karma-typescript\/dist\/client\/commonjs\.js(\?|$)/.test(file)) { + commonjsFile = file; + continue; + } + + // Collect all JS files + if (/\.js(\?|$)/.test(file) && file.indexOf("/base/") === 0) { + jsFiles.push(file); + continue; + } + + // Collect module shims + if (file.indexOf("/node_modules/@nevware21/ts-utils/dist/es5/main/ts-utils.js") !== -1) { + moduleShims.push({ name: "ts-utils", file: file }); + continue; + } + } + + // Filter jsFiles to find test files, source files, and test support files + var testFiles = []; + var sourceFiles = []; + var testSupportFiles = []; + + for (var i = 0; i < jsFiles.length; i++) { + if (/\/test\/src\/.*\.test\.js(\?|$)/.test(jsFiles[i])) { + testFiles.push(jsFiles[i]); + } else if (/^\/base\/src\/.*\.js(\?|$)/.test(jsFiles[i])) { + sourceFiles.push(jsFiles[i]); + } else if (/^\/base\/test\/src\/.*\.js(\?|$)/.test(jsFiles[i])) { + testSupportFiles.push(jsFiles[i]); + } + } + + console.log("[worker-adapter] Found " + bundleFiles.length + " bundle files, " + + sourceFiles.length + " source files, " + + testSupportFiles.length + " support files, " + testFiles.length + " test files, and " + + moduleShims.length + " module shims"); + + // Find the worker runner + var workerScript = null; + for (var fileName in files) { + if (files.hasOwnProperty(fileName) && fileName.indexOf("worker-test-runner.js") !== -1) { + workerScript = fileName; + break; + } + } + + if (!workerScript) { + console.error("[worker-adapter] Could not find worker-test-runner.js"); + karma.error("[worker-test] Worker runner not found"); + karma.complete({}); + return; + } + + console.log("[worker-adapter] Found worker script at: " + workerScript); + + // Create the worker + try { + var worker = new Worker(workerScript); + console.log("[worker-adapter] Worker created"); + + worker.onmessage = function(event) { + var msg = event.data; + + switch (msg.type) { + case "log": + console.log("[worker] " + msg.message); + break; + + case "ready": + console.log("[worker-adapter] Worker ready, sending files"); + + // Send all files: bundle, source, support, and test files + var filesToSend = bundleFiles.concat(sourceFiles, testSupportFiles, testFiles); + console.log("[worker-adapter] Sending " + filesToSend.length + " total files to worker"); + worker.postMessage({ + type: "loadTests", + files: filesToSend, + entrypoints: [], + moduleShims: moduleShims, + basePath: (karma.config && karma.config.basePath) ? karma.config.basePath : "", + mochaUrl: mochaFile || "/base/node_modules/mocha/mocha.js", + commonjsUrl: commonjsFile || "/base/node_modules/karma-typescript/dist/client/commonjs.js" + }); + break; + + case "result": + karma.result(msg.result); + break; + + case "complete": + karma.complete(msg.coverage ? { coverage: msg.coverage } : {}); + break; + + case "error": + console.error("[worker-adapter] Worker error: " + msg.error); + karma.error("[worker-test] " + msg.error); + karma.complete({}); + break; + } + }; + + worker.onerror = function(error) { + console.error("[worker-adapter] Worker error event: " + error.message); + karma.error("[worker-test] Worker error: " + error.message); + karma.complete({}); + }; + } catch (err) { + console.error("[worker-adapter] Failed to create worker: " + err.message); + karma.error("[worker-test] Failed to create worker: " + err.message); + karma.complete({}); + } + } + } + + // Start worker adapter initialization + initWorkerAdapter(); +})(); diff --git a/common/test/worker-test-runner.js b/common/test/worker-test-runner.js new file mode 100644 index 0000000..7e2b2b0 --- /dev/null +++ b/common/test/worker-test-runner.js @@ -0,0 +1,229 @@ +/* + * @nevware21/ts-async + * https://github.com/nevware21/ts-async + * + * Copyright (c) 2026 NevWare21 Solutions LLC + * Licensed under the MIT license. + */ + +/** + * Worker Test Runner - Runs in Web Worker context + * Loads and executes test files in worker environment + */ + +(function() { + "use strict"; + + if (typeof self.process === "undefined") { + self.process = { + env: {}, + versions: {}, + emit: function() {}, + on: function() {}, + off: function() {} + }; + } + + function sendMessage(msg) { + self.postMessage(msg); + } + + function workerLog(message) { + sendMessage({ + type: "log", + message: message + }); + } + + self.onmessage = function(event) { + var msg = event.data; + if (msg.type === "loadTests") { + loadAndRunTests(msg); + } + }; + + function loadAndRunTests(payload) { + var files = payload.files || []; + var requestedEntrypoints = payload.entrypoints || []; + var moduleShims = payload.moduleShims || []; + var basePath = payload.basePath || ""; + var mochaUrl = payload.mochaUrl; + var commonjsUrl = payload.commonjsUrl; + + workerLog("Loading " + files.length + " files and running " + requestedEntrypoints.length + " entrypoints"); + + if (!mochaUrl || !commonjsUrl) { + sendMessage({ + type: "error", + error: "Missing mocha or commonjs runtime URL" + }); + return; + } + + try { + // Load Mocha into worker and expose BDD globals + importScripts(mochaUrl); + if (!self.mocha || !self.mocha.setup) { + throw new Error("Mocha did not load in worker"); + } + + self.mocha.setup({ + ui: "bdd", + reporter: function() {} + }); + + // Prepare karma-typescript runtime globals + self.wrappers = self.wrappers || {}; + + // Load UMD module shims and register wrappers + moduleShims.forEach(function(shim) { + importScripts(shim.file); + registerShimWrapper(shim.name, shim.file, basePath); + }); + + // Load all source + test wrappers + for (var i = 0; i < files.length; i++) { + importScripts(files[i]); + if (i % 50 === 0 || i === files.length - 1) { + workerLog("Loaded " + (i + 1) + "/" + files.length + " files"); + } + } + + // Resolve entrypoints from actual wrapper keys + var wrapperKeys = Object.keys(self.wrappers || {}); + workerLog("Available wrappers: " + wrapperKeys.length); + if (wrapperKeys.length > 0) { + workerLog("Sample wrappers: " + wrapperKeys.slice(0, 3).join(", ")); + } + + var resolvedEntrypoints = wrapperKeys.filter(function(key) { + return /\/test\/src\/.*\.test\.(ts|js)$/.test(key); + }); + workerLog("Found " + resolvedEntrypoints.length + " test wrappers"); + + if (resolvedEntrypoints.length === 0 && requestedEntrypoints.length > 0) { + workerLog("No wrapper entrypoints found; falling back to requested entrypoints"); + self.entrypointFilenames = requestedEntrypoints.slice(); + } else { + self.entrypointFilenames = resolvedEntrypoints; + } + + // Execute entrypoints via karma-typescript commonjs runtime + importScripts(commonjsUrl); + + // Run Mocha and report results back to Karma + var runner = self.mocha.run(); + + function getSuiteTitles(test) { + var titles = []; + var parent = test && test.parent; + + while (parent) { + if (parent.title) { + titles.unshift(parent.title); + } + parent = parent.parent; + } + + return titles; + } + + runner.on("pass", function(test) { + var suiteTitles = getSuiteTitles(test); + sendMessage({ + type: "result", + result: { + description: test.title, + suite: suiteTitles, + success: true, + skipped: false, + time: test.duration, + log: [] + } + }); + }); + + runner.on("pending", function(test) { + var suiteTitles = getSuiteTitles(test); + sendMessage({ + type: "result", + result: { + description: test.title, + suite: suiteTitles, + success: true, + skipped: true, + log: [] + } + }); + }); + + runner.on("fail", function(test, err) { + var suiteTitles = getSuiteTitles(test); + sendMessage({ + type: "result", + result: { + description: test.title, + suite: suiteTitles, + success: false, + skipped: false, + log: [err && err.message ? err.message : "Test failed"], + time: test.duration + } + }); + }); + + runner.on("end", function() { + sendMessage({ + type: "complete", + coverage: self.__coverage__ + }); + }); + } catch (err) { + sendMessage({ + type: "error", + error: err && err.message ? err.message : String(err) + }); + } + } + + function registerShimWrapper(name, file, basePath) { + var exportsObj = resolveShimExport(name); + if (!exportsObj) { + workerLog("Shim export not found for " + name); + return; + } + + var absPath = toAbsolutePath(basePath, file); + self.wrappers[absPath] = [function(require, module, exports) { + module.exports = exportsObj; + }, absPath, {}]; + } + + function resolveShimExport(name) { + if (name === "ts-utils") { + return self.nevware21 && self.nevware21["ts-utils"]; + } + + if (name === "ts-async") { + return self.nevware21 && self.nevware21["ts-async"]; + } + + return null; + } + + function toAbsolutePath(basePath, file) { + if (!basePath) { + return file; + } + + var normalizedBase = basePath.replace(/\\/g, "/").replace(/\/$/, ""); + if (file.indexOf("/base/") === 0) { + return normalizedBase + file.substring("/base".length); + } + + return file; + } + + // Signal to adapter that worker is ready + sendMessage({ type: "ready" }); +})(); diff --git a/lib/karma.browser.conf.js b/lib/karma.browser.conf.js index 300ae36..53b913b 100644 --- a/lib/karma.browser.conf.js +++ b/lib/karma.browser.conf.js @@ -21,7 +21,7 @@ module.exports = function (config) { frameworks: [ "mocha", "karma-typescript" ], files: [ { pattern: "src/**/*.ts" }, - { pattern: "test/src/**/*.ts" } + { pattern: "test/src/!(node|worker)/**/*.ts" } ], preprocessors: { "**/*.ts": [ "karma-typescript" ] diff --git a/lib/karma.debug.worker.conf.js b/lib/karma.debug.worker.conf.js index ec2fea2..b5263ba 100644 --- a/lib/karma.debug.worker.conf.js +++ b/lib/karma.debug.worker.conf.js @@ -1,57 +1,62 @@ -process.env.CHROME_BIN = require('puppeteer').executablePath() +/* + * @nevware21/ts-async + * https://github.com/nevware21/ts-async + * + * Copyright (c) 2026 NevWare21 Solutions LLC + * Licensed under the MIT license. + * + * Fast worker debug configuration using: + * - karma-typescript for fast compilation + * - Custom worker-test framework for worker execution + * - Chrome with debugger (not headless) + */ + +// Default to using edge locally -- choose your own browser as required +process.env.CHROME_BIN = "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe"; module.exports = function (config) { - const typescript = require("@rollup/plugin-typescript"); - const plugin = require("@rollup/plugin-node-resolve"); - const commonjs = require("@rollup/plugin-commonjs"); config.set({ - browsers: ["Chromium_without_security"], - listenAddress: 'localhost', - hostname: 'localhost', - frameworks: [ "mocha-webworker" ], + browsers: [ "Chromium_without_security" ], + listenAddress: "localhost", + hostname: "localhost", + + // Use mocha + karma-typescript (same fast setup that works for browser) + frameworks: [ "mocha", "karma-typescript" ], files: [ - { pattern: "test/src/**/*.ts", included: false } + { pattern: "src/**/*.ts" }, + { pattern: "../common/test/worker-adapter.js" }, + { pattern: "test/src/!(browser|esnext|node)/**/*.ts" }, + { pattern: "../common/test/worker-test-runner.js", included: false, served: true, watched: false } ], preprocessors: { - "**/*.ts": [ "rollup" ] - }, - rollupPreprocessor: { - plugins: [ - typescript({ - tsconfig: "./test/tsconfig.worker.karma.json" - }), - plugin.nodeResolve({ - browser: true - }), - commonjs() - ], - output: { - format: "iife", - dir: "./test-dist", - sourcemap: true - } + "src/**/*.ts": [ "karma-typescript" ], + "test/src/**/*.ts": [ "karma-typescript" ] }, - client: { - mochaWebWorker: { - pattern: [ - "test/**/*.js" - ] + karmaTypescriptConfig: { + tsconfig: "./test/tsconfig.worker.karma.json", + compilerOptions: { + sourceMap: false, + inlineSourceMap: true, + inlineSources: true, + module: "commonjs" + }, + bundlerOptions: { + sourceMap: false + }, + coverageOptions: { + instrumentation: false, + sourceMap: true } }, - coverageIstanbulReporter: { - reports: ["html", "json"], - dir: "../.nyc_output" - }, - - reporters: [ "spec", "coverage-istanbul" ], - - logLevel: config.LOG_INFO, - + reporters: [ "spec" ], customLaunchers: { Chromium_without_security: { - base: 'Chrome', - flags: ['--disable-web-security', '--disable-site-isolation-trials'] + base: "Chrome", + flags: [ "--disable-web-security", "--disable-site-isolation-trials", "--no-sandbox" ] } - } - }) -}; \ No newline at end of file + }, + logLevel: config.LOG_INFO, + captureTimeout: 60000, + browserNoActivityTimeout: 60000 + }); +}; diff --git a/lib/karma.worker.conf.js b/lib/karma.worker.conf.js index 4d19e02..ea6ce70 100644 --- a/lib/karma.worker.conf.js +++ b/lib/karma.worker.conf.js @@ -1,74 +1,65 @@ -process.env.CHROME_BIN = require('puppeteer').executablePath() +process.env.CHROME_BIN = require('puppeteer').executablePath(); module.exports = function (config) { - const typescript = require("@rollup/plugin-typescript"); - const plugin = require("@rollup/plugin-node-resolve"); - const commonjs = require("@rollup/plugin-commonjs"); - const istanbul = require("rollup-plugin-istanbul"); - const process = require('process'); - process.env.CHROME_BIN = require('puppeteer').executablePath(); - process.env.CHROMIUM_BIN = require('puppeteer').executablePath(); - config.set({ browsers: [ "ChromeHeadlessNoSandbox" ], customLaunchers: { ChromeHeadlessNoSandbox: { base: "ChromeHeadless", - flags: [ - "--no-sandbox", - "--disable-gpu", - "--disable-web-security", - "--disable-dev-shm-usage" - ] + flags: [ "--disable-web-security", "--disable-site-isolation-trials", "--no-sandbox" ] } }, - listenAddress: 'localhost', - hostname: 'localhost', - frameworks: [ "mocha-webworker" ], + listenAddress: "localhost", + hostname: "localhost", + + // Use mocha + karma-typescript (same fast setup that works for browser) + frameworks: [ "mocha", "karma-typescript" ], files: [ - { pattern: "src/**/*.ts", included: false }, - { pattern: "test/src/**/*.ts", included: false } + { pattern: "src/**/*.ts" }, + { pattern: "../common/test/worker-adapter.js" }, + { pattern: "test/src/!(browser|node)/**/*.ts" }, + { pattern: "../common/test/worker-test-runner.js", included: false, served: true, watched: false } ], preprocessors: { - "**/*.ts": [ "rollup" ] + "src/**/*.ts": [ "karma-typescript" ], + "test/src/**/*.ts": [ "karma-typescript" ] }, - rollupPreprocessor: { - plugins: [ - typescript({ - tsconfig: "./test/tsconfig.worker.karma.json" - }), - plugin.nodeResolve({ - browser: true - }), - commonjs(), - istanbul({ - exclude: [ "**/test/**", "**/node_modules/**" ] - }) - ], - output: { - format: "iife", - dir: "../test-dist", - sourcemap: true - } - }, - client: { - mochaWebWorker: { - pattern: [ - "test/src/**/*.js", + karmaTypescriptConfig: { + tsconfig: "./test/tsconfig.worker.karma.json", + compilerOptions: { + sourceMap: false, + inlineSourceMap: false, + inlineSources: false, + module: "commonjs" + }, + bundlerOptions: { + sourceMap: false + }, + coverageOptions: { + instrumentation: true, + exclude: [ + /\.(d|spec|test)\.ts$/i, + /index\.ts$/i, + /checkError\.ts$/i, + /\/node_modules\//i ] + }, + reports: { + "html": { + "directory": "../coverage/worker", + "subdirectory": "./html" + }, + "json": { + "directory": "../coverage/worker", + "subdirectory": "./", + "filename": "coverage-final.json" + }, + "text": "" } }, - coverageReporter: { - dir: "../coverage/worker", - includeAllSources: true, - reporters: [ - { type: "text" }, - { type: "html", subdir: "html" }, - { type: "json", subdir: "./", file: "coverage-final.json" } - ], - }, - reporters: ["spec", "coverage" ], - - logLevel: config.LOG_DEBUG - }) -}; \ No newline at end of file + reporters: [ "spec", "karma-typescript" ], + logLevel: config.LOG_INFO, + captureTimeout: 60000, + browserNoActivityTimeout: 60000 + }); +}; diff --git a/lib/package.json b/lib/package.json index b49f148..f5ed97c 100644 --- a/lib/package.json +++ b/lib/package.json @@ -55,11 +55,11 @@ "rebuild": "npm run build && npm run test", "package": "rollup -c rollup.config.js --bundleConfigAsCjs", "test": "npm run preproc test && grunt ts_async-test && npm run test:node && npm run test:browser && npm run test:worker && npm run coverage:report&& npm run preproc -- -restore", - "test:node": "nyc ts-mocha --type-check -p ./test/tsconfig.test.json ./test/**/*.test.ts --trace-uncaught", + "test:node": "nyc ts-mocha --type-check -p ./test/tsconfig.test.json \"./test/src/!(browser|worker)/**/*.test.ts\" --trace-uncaught", "test:browser": "karma start karma.browser.conf.js --single-run", - "test:worker": "cross-env NODE_OPTIONS=--max-old-space-size=8192 karma start karma.worker.conf.js --single-run", + "test:worker": "karma start karma.worker.conf.js --single-run", "debug:browser": "karma start karma.debug.browser.conf.js --watch", - "debug:worker": "cross-env NODE_OPTIONS=--max-old-space-size=8192 karma start karma.debug.worker.conf.js --watch", + "debug:worker": "karma start karma.debug.worker.conf.js --watch", "lint": "grunt ts_async-lint", "coverage:report": "npm run coverage:nyc && npm run coverage:merge", "coverage:nyc": "nyc report --reporter=json", @@ -94,11 +94,7 @@ "grunt-cli": "^1.4.3", "karma": "^6.3.20", "karma-chrome-launcher": "^3.1.1", - "karma-coverage": "^2.2.0", - "karma-coverage-istanbul-reporter": "^3.0.3", "karma-mocha": "^2.0.1", - "karma-mocha-webworker": "^1.3.0", - "karma-rollup-preprocessor": "^7.0.8", "karma-spec-reporter": "^0.0.36", "karma-typescript": "^5.5.3", "mocha": "^10.0.0", diff --git a/lib/test/src/browser/isBrowser.test.ts b/lib/test/src/browser/isBrowser.test.ts new file mode 100644 index 0000000..74e9ef9 --- /dev/null +++ b/lib/test/src/browser/isBrowser.test.ts @@ -0,0 +1,30 @@ +/* + * @nevware21/ts-async + * https://github.com/nevware21/ts-async + * + * Copyright (c) 2026 NevWare21 Solutions LLC + * Licensed under the MIT license. + */ + +import { assert } from "@nevware21/tripwire"; +import { hasDocument, hasWindow, isNode, isWebWorker } from "@nevware21/ts-utils"; + +// Define the test suite +describe("** Ensure running in a browser environment **", () => { + + it("hasWindow", () => { + assert.equal(hasWindow(), true, "Validate that we have a window object available"); + }); + + it("hasDocument", () => { + assert.equal(hasDocument(), true, "Validate that we have a document object available"); + }); + + it("not isNode", () => { + assert.equal(isNode(), false, "Validate that we are not running in a node environment"); + }); + + it ("not isWorker", () => { + assert.equal(isWebWorker(), false, "Validate that we are not running in a worker environment"); + }); +}); \ No newline at end of file diff --git a/lib/test/src/node/isNode.test.ts b/lib/test/src/node/isNode.test.ts new file mode 100644 index 0000000..c686f32 --- /dev/null +++ b/lib/test/src/node/isNode.test.ts @@ -0,0 +1,29 @@ +/* + * @nevware21/ts-async + * https://github.com/nevware21/ts-async + * + * Copyright (c) 2026 NevWare21 Solutions LLC + * Licensed under the MIT license. + */ + +import { assert } from "@nevware21/tripwire"; +import { hasDocument, hasWindow, isNode, isWebWorker } from "@nevware21/ts-utils"; + +// Define the test suite +describe("** Ensure we are running in a node environment **", () => { + it("not hasWindow", () => { + assert.equal(hasWindow(), false, "Validate that we do not have a window object available"); + }); + + it("not hasDocument", () => { + assert.equal(hasDocument(), false, "Validate that we do not have a document object available"); + }); + + it("isNode", () => { + assert.equal(isNode(), true, "Validate that we are running in a node environment"); + }); + + it ("not isWorker", () => { + assert.equal(isWebWorker(), false, "Validate that we are not running in a worker environment"); + }); +}); \ No newline at end of file diff --git a/lib/test/src/worker/isWorker.test.ts b/lib/test/src/worker/isWorker.test.ts new file mode 100644 index 0000000..cdb4353 --- /dev/null +++ b/lib/test/src/worker/isWorker.test.ts @@ -0,0 +1,31 @@ +/* + * @nevware21/ts-async + * https://github.com/nevware21/ts-async + * + * Copyright (c) 2026 NevWare21 Solutions LLC + * Licensed under the MIT license. + */ + +import { assert } from "@nevware21/tripwire"; +import { hasDocument, hasWindow, isNode, isWebWorker } from "@nevware21/ts-utils"; + +// Define the test suite +describe("** Ensure we are running in a web worker environment **", () => { + + it("not hasWindow", () => { + assert.equal(hasWindow(), false, "Validate that we do not have a window object available"); + }); + + it("not hasDocument", () => { + assert.equal(hasDocument(), false, "Validate that we do not have a document object available"); + }); + + it("not isNode", () => { + assert.equal(isNode(), false, "Validate that we are not running in a node environment"); + }); + + it ("isWorker", () => { + assert.equal(isWebWorker(), true, "Validate that we are running in a worker environment"); + }); +}); + diff --git a/package.json b/package.json index 93a72be..a07705c 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,6 @@ "@size-limit/time": "^12.0.0", "@types/eslint": "^8.56.10", "@types/estree": "^1.0.0", - "@types/jquery": "^3.5.14", "@types/mocha": "^10.0.1", "@types/sinon": "^10.0.11", "@typescript-eslint/eslint-plugin": "^7.14.1",