From ec767cbc056f872563bcad81211493265ad581d3 Mon Sep 17 00:00:00 2001 From: Nev Date: Mon, 23 Feb 2026 22:04:45 -0800 Subject: [PATCH] perf: Fix worker test execution excessive delay - add shared worrker adapter/runner - switch worker Karma to mocha + karma-typescript and update globs - drop unused karma-* deps and refresh rush shrinkwrap --- common/test/worker-adapter.js | 171 +++++++++++++++++++ common/test/worker-test-runner.js | 218 +++++++++++++++++++++++++ karma.debug.worker.conf.js | 81 ++++----- karma.debug.worker.esnext.conf.js | 84 +++++----- karma.worker.conf.js | 118 +++++++------ karma.worker.esnext.conf.js | 121 +++++++------- lib/test/src/browser/isBrowser.test.ts | 30 ++++ lib/test/src/node/isNode.test.ts | 29 ++++ lib/test/src/worker/isWorker.test.ts | 31 ++++ package.json | 8 +- 10 files changed, 665 insertions(+), 226 deletions(-) create mode 100644 common/test/worker-adapter.js create mode 100644 common/test/worker-test-runner.js create mode 100644 lib/test/src/browser/isBrowser.test.ts create mode 100644 lib/test/src/node/isNode.test.ts create mode 100644 lib/test/src/worker/isWorker.test.ts diff --git a/common/test/worker-adapter.js b/common/test/worker-adapter.js new file mode 100644 index 00000000..cd4bf0bc --- /dev/null +++ b/common/test/worker-adapter.js @@ -0,0 +1,171 @@ +/* + * @nevware21/ts-utils + * https://github.com/nevware21/ts-utils + * + * 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"); + + 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 { + 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; + } + + if (/karma-typescript-bundle-.*\.js(\?|$)/.test(file)) { + bundleFiles.push(file); + continue; + } + + if (!mochaFile && /\/node_modules\/mocha\/mocha\.js(\?|$)/.test(file)) { + mochaFile = file; + continue; + } + + if (!commonjsFile && /\/node_modules\/karma-typescript\/dist\/client\/commonjs\.js(\?|$)/.test(file)) { + commonjsFile = file; + continue; + } + + if (/\.js(\?|$)/.test(file) && file.indexOf("/base/") === 0) { + jsFiles.push(file); + continue; + } + } + + var testFiles = []; + var sourceFiles = []; + var testSupportFiles = []; + for (var i = 0; i < jsFiles.length; i++) { + if (/\/lib\/test\/src\/.*\.test\.js(\?|$)/.test(jsFiles[i])) { + testFiles.push(jsFiles[i]); + } else if (/^\/base\/lib\/src\/.*\.js(\?|$)/.test(jsFiles[i])) { + sourceFiles.push(jsFiles[i]); + } else if (/^\/base\/lib\/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"); + + 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); + + 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"); + 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({}); + } + } + } + + initWorkerAdapter(); +})(); diff --git a/common/test/worker-test-runner.js b/common/test/worker-test-runner.js new file mode 100644 index 00000000..ebbcd2b9 --- /dev/null +++ b/common/test/worker-test-runner.js @@ -0,0 +1,218 @@ +/* + * @nevware21/ts-utils + * https://github.com/nevware21/ts-utils + * + * 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"; + + 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 { + // Polyfill process for karma-typescript commonjs runtime + if (typeof self.process === "undefined") { + self.process = { + env: { NODE_ENV: "test" }, + cwd: function () { return "/"; }, + browser: true + }; + } + + importScripts(mochaUrl); + if (!self.mocha || !self.mocha.setup) { + throw new Error("Mocha did not load in worker"); + } + self.mocha.setup({ + ui: "bdd", + reporter: function () {} + }); + + self.wrappers = self.wrappers || {}; + + moduleShims.forEach(function (shim) { + importScripts(shim.file); + registerShimWrapper(shim.name, shim.file, basePath); + }); + + 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"); + } + } + + 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 /\/lib\/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; + } + + importScripts(commonjsUrl); + + 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.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"]; + } + if (name === "chromacon") { + return self.nevware21 && self.nevware21.chromacon; + } + 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; + } + + sendMessage({ type: "ready" }); +})(); diff --git a/karma.debug.worker.conf.js b/karma.debug.worker.conf.js index 5bd341f3..d1629817 100644 --- a/karma.debug.worker.conf.js +++ b/karma.debug.worker.conf.js @@ -1,61 +1,52 @@ -process.env.CHROME_BIN = require('puppeteer').executablePath() +// Default to using edge locally -- choose your own browser as required +process.env.CHROME_BIN = "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe"; +//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"); config.set({ browsers: ["Chromium_without_security"], - listenAddress: 'localhost', - hostname: 'localhost', - frameworks: [ "mocha-webworker" ], + listenAddress: "localhost", + hostname: "localhost", + + frameworks: ["mocha", "karma-typescript"], files: [ - { pattern: "lib/test/src/common/**/*.ts", included: false }, - { pattern: "lib/test/src/worker/**/*.ts", included: false } + { pattern: "lib/src/**/*.ts" }, + { pattern: "common/test/worker-adapter.js" }, + { pattern: "lib/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: "./lib/test/tsconfig.worker.karma.json", - compilerOptions: { - sourceMap: true - }, - }), - plugin.nodeResolve({ - browser: true - }), - commonjs() - ], - output: { - format: "iife", - dir: "../test-dist", - sourcemap: true - } + "lib/src/**/*.ts": ["karma-typescript"], + "lib/test/src/**/*.ts": ["karma-typescript"] }, - client: { - mochaWebWorker: { - pattern: [ - "lib/test/**/*.js" - ] + karmaTypescriptConfig: { + tsconfig: "./lib/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"] } - } - }) + }, + + logLevel: config.LOG_INFO, + captureTimeout: 60000, + browserNoActivityTimeout: 60000 + }); }; \ No newline at end of file diff --git a/karma.debug.worker.esnext.conf.js b/karma.debug.worker.esnext.conf.js index c3fdcb46..eed24c3f 100644 --- a/karma.debug.worker.esnext.conf.js +++ b/karma.debug.worker.esnext.conf.js @@ -1,63 +1,53 @@ -process.env.CHROME_BIN = require('puppeteer').executablePath() +// Default to using edge locally -- choose your own browser as required +process.env.CHROME_BIN = "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe"; +//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"); config.set({ browsers: ["Chromium_without_security"], - listenAddress: 'localhost', - hostname: 'localhost', - frameworks: [ "mocha-webworker" ], + listenAddress: "localhost", + hostname: "localhost", + + frameworks: ["mocha", "karma-typescript"], files: [ - { pattern: "lib/test/src/common/**/*.ts", included: false }, - { pattern: "lib/test/src/worker/**/*.ts", included: false }, - { pattern: "lib/test/src/esnext/**/*.ts", included: false } + { pattern: "lib/src/**/*.ts" }, + { pattern: "common/test/worker-adapter.js" }, + { pattern: "lib/test/src/!(browser|node)/**/*.ts" }, + { pattern: "common/test/worker-test-runner.js", included: false, served: true, watched: false } ], preprocessors: { - "**/*.ts": [ "rollup" ] - }, - rollupPreprocessor: { - plugins: [ - typescript({ - tsconfig: "./lib/test/tsconfig.worker.karma.json", - compilerOptions: { - target: "ESNext", - sourceMap: true - }, - }), - plugin.nodeResolve({ - browser: true - }), - commonjs() - ], - output: { - format: "iife", - dir: "../test-dist", - sourcemap: true - } + "lib/src/**/*.ts": ["karma-typescript"], + "lib/test/src/**/*.ts": ["karma-typescript"] }, - client: { - mochaWebWorker: { - pattern: [ - "lib/test/**/*.js" - ] + karmaTypescriptConfig: { + tsconfig: "./lib/test/tsconfig.worker.karma.json", + compilerOptions: { + target: "ESNext", + 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"] } - } - }) + }, + + logLevel: config.LOG_INFO, + captureTimeout: 60000, + browserNoActivityTimeout: 60000 + }); }; \ No newline at end of file diff --git a/karma.worker.conf.js b/karma.worker.conf.js index 43a4a543..b1f5254f 100644 --- a/karma.worker.conf.js +++ b/karma.worker.conf.js @@ -1,75 +1,67 @@ -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() +process.env.CHROME_BIN = require("puppeteer").executablePath(); +module.exports = function (config) { config.set({ - browsers: [ "ChromeHeadlessNoSandbox" ], - customLaunchers: { - ChromeHeadlessNoSandbox: { - base: "ChromeHeadless", - flags: [ - "--no-sandbox", - "--disable-gpu", - "--disable-web-security", - "--disable-dev-shm-usage" - ] - } - }, - listenAddress: 'localhost', - hostname: 'localhost', - frameworks: [ "mocha-webworker" ], + browsers: ["Chromium_without_security"], + listenAddress: "localhost", + hostname: "localhost", + + frameworks: ["mocha", "karma-typescript"], files: [ - { pattern: "lib/test/src/common/**/*.ts", included: false }, - { pattern: "lib/test/src/worker/**/*.ts", included: false } + { pattern: "lib/src/**/*.ts" }, + { pattern: "common/test/worker-adapter.js" }, + { pattern: "lib/test/src/!(browser|node|esnext)/**/*.ts" }, + { pattern: "common/test/worker-test-runner.js", included: false, served: true, watched: false } ], preprocessors: { - "**/*.ts": [ "rollup" ] + "lib/src/**/*.ts": ["karma-typescript"], + "lib/test/src/**/*.ts": ["karma-typescript"] }, - rollupPreprocessor: { - plugins: [ - typescript({ - tsconfig: "./lib/test/tsconfig.worker.karma.json", - compilerOptions: { - sourceMap: true - }, - }), - plugin.nodeResolve({ - browser: true - }), - commonjs(), - istanbul({ - exclude: [ "**/test/**", "**/node_modules/**" ] - }) - ], - output: { - format: "iife", - dir: "../test-dist", - sourcemap: true - } - }, - client: { - mochaWebWorker: { - pattern: [ - "lib/test/**/*.js" + karmaTypescriptConfig: { + tsconfig: "./lib/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", "karma-typescript"], + + customLaunchers: { + Chromium_without_security: { + base: "ChromeHeadless", + flags: ["--disable-web-security", "--disable-site-isolation-trials", "--no-sandbox"] + } }, - reporters: ["spec", "coverage" ], - logLevel: config.LOG_DEBUG - }) + logLevel: config.LOG_INFO, + captureTimeout: 60000, + browserNoActivityTimeout: 60000 + }); }; \ No newline at end of file diff --git a/karma.worker.esnext.conf.js b/karma.worker.esnext.conf.js index 2cbfb939..f0e699b6 100644 --- a/karma.worker.esnext.conf.js +++ b/karma.worker.esnext.conf.js @@ -1,77 +1,68 @@ -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() +process.env.CHROME_BIN = require("puppeteer").executablePath(); +module.exports = function (config) { config.set({ - browsers: [ "ChromeHeadlessNoSandbox" ], - customLaunchers: { - ChromeHeadlessNoSandbox: { - base: "ChromeHeadless", - flags: [ - "--no-sandbox", - "--disable-gpu", - "--disable-web-security", - "--disable-dev-shm-usage" - ] - } - }, - listenAddress: 'localhost', - hostname: 'localhost', - frameworks: [ "mocha-webworker" ], + browsers: ["Chromium_without_security"], + listenAddress: "localhost", + hostname: "localhost", + + frameworks: ["mocha", "karma-typescript"], files: [ - { pattern: "lib/test/src/common/**/*.ts", included: false }, - { pattern: "lib/test/src/worker/**/*.ts", included: false }, - { pattern: "lib/test/src/esnext/**/*.ts", included: false } + { pattern: "lib/src/**/*.ts" }, + { pattern: "common/test/worker-adapter.js" }, + { pattern: "lib/test/src/!(browser|node)/**/*.ts" }, + { pattern: "common/test/worker-test-runner.js", included: false, served: true, watched: false } ], preprocessors: { - "**/*.ts": [ "rollup" ] + "lib/src/**/*.ts": ["karma-typescript"], + "lib/test/src/**/*.ts": ["karma-typescript"] }, - rollupPreprocessor: { - plugins: [ - typescript({ - tsconfig: "./lib/test/tsconfig.worker.karma.json", - compilerOptions: { - target: "ESNext", - sourceMap: true - }, - }), - plugin.nodeResolve({ - browser: true - }), - commonjs(), - istanbul({ - exclude: [ "**/test/**", "**/node_modules/**" ] - }) - ], - output: { - format: "iife", - dir: "../test-dist", - sourcemap: true - } - }, - client: { - mochaWebWorker: { - pattern: [ - "lib/test/**/*.js" + karmaTypescriptConfig: { + tsconfig: "./lib/test/tsconfig.worker.karma.json", + compilerOptions: { + target: "ESNext", + 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_esnext", + "subdirectory": "./html" + }, + "json": { + "directory": "./coverage/worker_esnext", + "subdirectory": "./", + "filename": "coverage-final.json" + }, + "text": "" } }, - coverageReporter: { - dir: "./coverage/worker_esnext", - includeAllSources: true, - reporters: [ - { type: "text" }, - { type: "html", subdir: "html" }, - { type: "json", subdir: "./", file: "coverage-final.json" } - ], + + reporters: ["spec", "karma-typescript"], + + customLaunchers: { + Chromium_without_security: { + base: "ChromeHeadless", + flags: ["--disable-web-security", "--disable-site-isolation-trials", "--no-sandbox"] + } }, - reporters: ["spec", "coverage" ], - logLevel: config.LOG_DEBUG - }) + logLevel: config.LOG_INFO, + captureTimeout: 60000, + browserNoActivityTimeout: 60000 + }); }; \ No newline at end of file diff --git a/lib/test/src/browser/isBrowser.test.ts b/lib/test/src/browser/isBrowser.test.ts new file mode 100644 index 00000000..13e84d50 --- /dev/null +++ b/lib/test/src/browser/isBrowser.test.ts @@ -0,0 +1,30 @@ +/* + * @nevware21/ts-utils + * https://github.com/nevware21/ts-utils + * + * Copyright (c) 2026 NevWare21 Solutions LLC + * Licensed under the MIT license. + */ + +import { assert } from "@nevware21/tripwire-chai"; +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 00000000..0770db30 --- /dev/null +++ b/lib/test/src/node/isNode.test.ts @@ -0,0 +1,29 @@ +/* + * @nevware21/ts-utils + * https://github.com/nevware21/ts-utils + * + * Copyright (c) 2026 NevWare21 Solutions LLC + * Licensed under the MIT license. + */ + +import { assert } from "@nevware21/tripwire-chai"; +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 00000000..cdba1b89 --- /dev/null +++ b/lib/test/src/worker/isWorker.test.ts @@ -0,0 +1,31 @@ +/* + * @nevware21/ts-utils + * https://github.com/nevware21/ts-utils + * + * Copyright (c) 2026 NevWare21 Solutions LLC + * Licensed under the MIT license. + */ + +import { assert } from "@nevware21/tripwire-chai"; +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 af553fb6..58ccbca5 100644 --- a/package.json +++ b/package.json @@ -167,8 +167,8 @@ "test:node_esnext": "nyc --report-dir=./coverage/nyc_esnext ts-mocha -p lib/test/tsconfig.test.esnext.json lib/test/src/esnext/**/*.test.ts lib/test/src/node/**/*.test.ts lib/test/src/common/**/*.test.ts", "test:browser": "karma start karma.browser.conf.js --single-run", "test:browser_esnext": "karma start karma.browser.esnext.conf.js --single-run", - "test:worker": "cross-env NODE_OPTIONS='--max-old-space-size=16384' karma start karma.worker.conf.js --single-run", - "test:worker_esnext": "cross-env NODE_OPTIONS='--max-old-space-size=16384' karma start karma.worker.esnext.conf.js --single-run", + "test:worker": "karma start karma.worker.conf.js --single-run", + "test:worker_esnext": "karma start karma.worker.esnext.conf.js --single-run", "debug:browser": "karma start karma.debug.browser.conf.js --watch", "debug:worker": "karma start karma.debug.worker.conf.js --watch", "debug:browser_esnext": "karma start karma.debug.browser.esnext.conf.js --watch", @@ -242,11 +242,7 @@ "grunt-cli": "^1.4.3", "karma": "^6.4.3", "karma-chrome-launcher": "^3.2.0", - "karma-coverage": "^2.2.1", - "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.4", "mocha": "^11.2.0",