Compare commits

...

176 Commits

Author SHA1 Message Date
fa9abbc4db 1.3.0 2025-05-15 17:50:26 +00:00
56f0f0be16 feat(logger): Improve logging output and add --logfile support for persistent logs 2025-05-15 17:50:25 +00:00
dc0f859fad 1.2.0 2025-05-15 16:39:46 +00:00
78ffad2f7d feat(logging): Improve logging output, CLI option parsing, and test report formatting. 2025-05-15 16:39:46 +00:00
3fc4cee2b1 1.1.0 2025-05-15 14:37:55 +00:00
a57edeef64 feat(cli): Enhance test discovery with support for single file and glob pattern execution using improved CLI argument detection 2025-05-15 14:37:55 +00:00
1f73751a8c 1.0.96 2025-01-23 20:03:53 +01:00
90741ed917 fix(TsTest): Fixed improper type-check for promise-like testModule defaults 2025-01-23 20:03:52 +01:00
962fa2cd4d 1.0.95 2025-01-23 19:56:56 +01:00
c085a20a4f fix(core): Fix delay handling in Chrome test execution 2025-01-23 19:56:56 +01:00
1f355a10a1 1.0.94 2025-01-23 19:25:14 +01:00
a73ce99564 fix(TsTest): Fix test module execution by ensuring promise resolution delay 2025-01-23 19:25:13 +01:00
64f825091d 1.0.93 2025-01-23 19:20:12 +01:00
5ddc2d2de0 fix(tstest): Handle globalThis.tapPromise in browser runtime evaluation 2025-01-23 19:20:11 +01:00
85fec03878 1.0.92 2025-01-23 19:13:40 +01:00
61c3226156 fix(core): Improve error logging for test modules without default promise 2025-01-23 19:13:40 +01:00
f0bf778810 1.0.91 2025-01-23 19:02:11 +01:00
a8e9f67810 fix(core): Refactored tstest class to enhance promise handling for test modules. 2025-01-23 19:02:11 +01:00
4cce132472 1.0.90 2024-04-18 20:50:46 +02:00
dc250804f5 fix(core): update 2024-04-18 20:50:45 +02:00
9669445646 1.0.89 2024-04-18 20:47:26 +02:00
928d9d0616 fix(core): update 2024-04-18 20:47:25 +02:00
3655b2f734 1.0.88 2024-03-07 13:17:29 +01:00
6712ff6b07 fix(core): update 2024-03-07 13:17:28 +01:00
ef5efc0a93 1.0.87 2024-03-07 13:10:58 +01:00
f305547116 fix(core): update 2024-03-07 13:10:57 +01:00
033a0a806c 1.0.86 2024-01-19 20:59:02 +01:00
7f87c24ad8 fix(core): update 2024-01-19 20:59:01 +01:00
ac08bdffe5 1.0.85 2023-11-10 12:44:08 +01:00
eb64cb4f71 fix(core): update 2023-11-10 12:44:08 +01:00
3b56c6ce9f 1.0.84 2023-11-09 21:06:07 +01:00
722d777f80 fix(core): update 2023-11-09 21:06:06 +01:00
f1a0455662 1.0.83 2023-11-09 19:00:54 +01:00
3c62129e02 fix(core): update 2023-11-09 19:00:53 +01:00
ac5e036967 1.0.82 2023-11-09 17:55:27 +01:00
6ccd0281b9 fix(core): update 2023-11-09 17:55:26 +01:00
d0f85b026f 1.0.81 2023-09-09 23:22:07 +02:00
4376cafabb fix(core): update 2023-09-09 23:22:06 +02:00
1a6e449b8d 1.0.80 2023-08-26 15:42:19 +02:00
6ec99e7276 fix(core): update 2023-08-26 15:42:18 +02:00
e958417d47 1.0.79 2023-08-26 14:54:44 +02:00
24416c1b5c fix(core): update 2023-08-26 14:54:44 +02:00
d6c8fcc1cf 1.0.78 2023-08-26 14:39:48 +02:00
53bb97c6db fix(core): update 2023-08-26 14:39:47 +02:00
4f35b101ec 1.0.77 2023-07-13 09:42:18 +02:00
549ae53a00 fix(core): update 2023-07-13 09:42:18 +02:00
d9aa2984ef 1.0.76 2023-07-13 03:19:12 +02:00
37e6d94c9f fix(core): update 2023-07-13 03:19:11 +02:00
74e1df6824 1.0.75 2022-11-08 08:04:46 +01:00
6eb86c63c3 fix(core): update 2022-11-08 08:04:46 +01:00
e919a4a2e9 1.0.74 2022-11-08 08:03:17 +01:00
85f6703696 fix(core): update 2022-11-08 08:03:17 +01:00
4c2812f671 1.0.73 2022-08-03 19:48:20 +02:00
bab93448e8 fix(core): update 2022-08-03 19:48:19 +02:00
3db913eb59 1.0.72 2022-07-24 14:11:18 +02:00
28e0c32944 fix(core): update 2022-07-24 14:11:17 +02:00
0be6b3400a 1.0.71 2022-05-04 18:58:36 +02:00
eeba113e09 fix(core): update 2022-05-04 18:58:35 +02:00
19e45b305c 1.0.70 2022-03-25 01:30:34 +01:00
f9f4150cff fix(core): update 2022-03-25 01:30:33 +01:00
710548911e 1.0.69 2022-03-17 12:24:40 +01:00
23f9a28fa0 fix(core): update 2022-03-17 12:24:40 +01:00
e1d2f1fd68 1.0.68 2022-03-16 12:28:50 +01:00
3116c5a818 fix(core): update 2022-03-16 12:28:50 +01:00
568772734b 1.0.67 2022-03-14 11:49:39 +01:00
30525e7e55 fix(core): update 2022-03-14 11:49:38 +01:00
f7483ef995 1.0.66 2022-03-13 00:40:22 +01:00
1460f97c52 fix(core): update 2022-03-13 00:40:21 +01:00
dfac554303 1.0.65 2022-03-13 00:30:33 +01:00
1d751bdcdf fix(core): update 2022-03-13 00:30:32 +01:00
bd6713eee8 1.0.64 2022-02-15 11:28:34 +01:00
440b41611b fix(core): update 2022-02-15 11:28:34 +01:00
78a40de700 1.0.63 2022-02-15 00:27:21 +01:00
e0eb00d755 fix(core): update 2022-02-15 00:27:20 +01:00
dbbcbf4ea2 1.0.62 2022-02-14 23:50:07 +01:00
8c13b9db89 fix(core): update 2022-02-14 23:50:07 +01:00
f813a79124 1.0.61 2022-02-14 15:40:12 +01:00
766138aa25 fix(core): update 2022-02-14 15:40:11 +01:00
72880b4a2d 1.0.60 2021-11-07 20:54:40 +01:00
bd5731c439 fix(core): update 2021-11-07 20:54:39 +01:00
0caebb7448 1.0.59 2021-10-06 17:58:39 +02:00
ed896b7f1c fix(core): update 2021-10-06 17:58:38 +02:00
69ec5a98ab 1.0.58 2021-10-06 13:25:59 +02:00
3b93886147 fix(core): update 2021-10-06 13:25:59 +02:00
5949988293 1.0.57 2021-08-20 18:43:11 +02:00
04f7be07a3 fix(core): update 2021-08-20 18:43:11 +02:00
d331f90d24 1.0.56 2021-08-20 18:25:47 +02:00
224400dcb5 fix(core): update 2021-08-20 18:25:47 +02:00
7601ca599a 1.0.55 2021-08-20 18:23:39 +02:00
994a1bc98d fix(core): update 2021-08-20 18:23:39 +02:00
ca51c9e15b 1.0.54 2021-04-29 15:48:45 +00:00
4c4f08152b fix(core): update 2021-04-29 15:48:45 +00:00
39bd80106a 1.0.53 2021-04-29 15:33:54 +00:00
d6b94b534b fix(core): update 2021-04-29 15:33:53 +00:00
d19d3fc51e 1.0.52 2020-10-01 14:29:01 +00:00
f7f1bf25f6 fix(core): update 2020-10-01 14:29:01 +00:00
42fd414609 1.0.51 2020-10-01 14:22:07 +00:00
8f16f46c37 fix(core): update 2020-10-01 14:22:06 +00:00
f8afb2c7f6 1.0.50 2020-10-01 14:12:14 +00:00
a3d1fbb2da fix(core): update 2020-10-01 14:12:13 +00:00
0da1a1bc5b 1.0.49 2020-10-01 13:30:30 +00:00
1ede0b476a fix(core): update 2020-10-01 13:30:29 +00:00
1d251689bb 1.0.48 2020-09-29 16:15:52 +00:00
8f1492dfbd fix(core): update 2020-09-29 16:15:51 +00:00
003dc473ea 1.0.47 2020-09-29 15:58:28 +00:00
e6baed5470 fix(core): update 2020-09-29 15:58:26 +00:00
d9a27adb4a 1.0.46 2020-09-29 15:29:46 +00:00
eabb75a9a8 fix(core): update 2020-09-29 15:29:45 +00:00
deb63c1af5 1.0.45 2020-09-29 15:14:33 +00:00
7ee3969798 fix(core): update 2020-09-29 15:14:32 +00:00
61eea77805 1.0.44 2020-08-13 01:29:19 +00:00
3d9685ac6f fix(core): update 2020-08-13 01:29:19 +00:00
4ec56c3f0b 1.0.43 2020-07-12 00:47:42 +00:00
ab33720aba fix(core): update 2020-07-12 00:47:41 +00:00
5e42565567 1.0.42 2020-07-11 16:14:08 +00:00
88b7581eeb fix(core): update 2020-07-11 16:14:07 +00:00
0ea621cb99 1.0.41 2020-07-11 15:52:32 +00:00
984d551bd6 fix(core): update 2020-07-11 15:52:31 +00:00
4066d9b0e8 1.0.40 2020-07-09 23:20:15 +00:00
f24ff2f79e fix(core): update 2020-07-09 23:20:14 +00:00
9d37fcf734 1.0.39 2020-07-09 22:00:46 +00:00
f7524179d7 fix(core): update 2020-07-09 22:00:45 +00:00
19d6b52ddb 1.0.38 2020-07-08 02:05:51 +00:00
cf69e5436c fix(core): update 2020-07-08 02:05:51 +00:00
6bee853cd2 1.0.37 2020-07-08 00:59:56 +00:00
4aa731b531 fix(core): update 2020-07-08 00:59:55 +00:00
a849f36a1b 1.0.36 2020-07-07 23:09:17 +00:00
30284b770c fix(core): update 2020-07-07 23:09:17 +00:00
023176258a 1.0.35 2020-07-07 21:59:08 +00:00
ad2866ae0b fix(core): update 2020-07-07 21:59:07 +00:00
af030ed013 1.0.34 2020-07-07 20:50:30 +00:00
940133493c fix(core): update 2020-07-07 20:50:29 +00:00
e999abbba6 1.0.33 2020-06-01 20:48:55 +00:00
4ede3090af fix(core): update 2020-06-01 20:48:54 +00:00
c5c295f42d 1.0.32 2020-06-01 19:58:15 +00:00
4602fed130 fix(core): update 2020-06-01 19:58:15 +00:00
a6ecf1d530 1.0.31 2020-06-01 19:52:25 +00:00
22703f261c fix(core): update 2020-06-01 19:52:24 +00:00
289cc6c0df 1.0.30 2020-06-01 19:29:57 +00:00
97d0ebffec fix(core): update 2020-06-01 19:29:56 +00:00
da19d5de39 1.0.29 2020-06-01 18:40:22 +00:00
7380323186 fix(core): update 2020-06-01 18:40:22 +00:00
7a6923051f 1.0.28 2019-10-02 11:51:32 +02:00
0bac34dd37 fix(core): update 2019-10-02 11:51:31 +02:00
e10d9eb2a7 1.0.27 2019-10-02 11:18:45 +02:00
c5596f1a8f fix(core): update 2019-10-02 11:18:45 +02:00
ac0bb6f9b0 1.0.26 2019-10-02 10:59:54 +02:00
32db50ef1f fix(core): update 2019-10-02 10:59:53 +02:00
a35db70155 1.0.25 2019-10-02 10:56:03 +02:00
0286312855 fix(core): update 2019-10-02 10:56:02 +02:00
40cf6f72ce 1.0.24 2019-05-28 11:32:06 +02:00
e6c71a1350 fix(core): update 2019-05-28 11:32:06 +02:00
1c640b8545 1.0.23 2019-05-27 15:49:22 +02:00
8c4b591391 fix(core): update 2019-05-27 15:49:22 +02:00
8eb270ebbc 1.0.22 2019-05-27 13:14:31 +02:00
f6d47a1a67 fix(core): update 2019-05-27 13:14:31 +02:00
2a41acc6e4 1.0.21 2019-05-22 16:43:02 +02:00
fb6bb85441 fix(core): update 2019-05-22 16:43:02 +02:00
02dbe602b2 1.0.20 2019-04-08 17:52:41 +02:00
e17d7009d9 fix(core): update 2019-04-08 17:52:41 +02:00
d22534388d 1.0.19 2019-04-08 17:50:57 +02:00
e258b2d62e fix(core): update 2019-04-08 17:50:57 +02:00
5afe6e6981 1.0.18 2018-12-06 01:03:49 +01:00
5d071d0299 fix(core): update 2018-12-06 01:03:48 +01:00
180bfcb353 1.0.17 2018-12-06 00:56:36 +01:00
3161e6b4eb fix(core): update 2018-12-06 00:56:36 +01:00
6129388a20 1.0.16 2018-12-06 00:38:03 +01:00
8f0cfe1a06 fix(core): update 2018-12-06 00:38:03 +01:00
39926fb08b 1.0.15 2018-08-14 00:04:43 +02:00
36594b64f2 fix(dependencies): update 2018-08-14 00:04:42 +02:00
9f898b6579 1.0.14 2018-08-13 23:58:51 +02:00
b1725b636b fix(improve test handling): now failing correctly and with better log output 2018-08-13 23:58:50 +02:00
df3f1ea9d6 1.0.13 2018-08-08 22:51:21 +02:00
d749476d0c fix(update dependencies): update 2018-08-08 22:51:20 +02:00
4456cd68d0 1.0.12 2018-08-05 23:20:32 +02:00
8f61b5648f fix(log): improve log output 2018-08-05 23:20:32 +02:00
36 changed files with 11351 additions and 1386 deletions

16
.gitignore vendored
View File

@ -1,6 +1,20 @@
.nogit/
node_modules/
# artifacts
coverage/
public/
pages/
# installs
node_modules/
# caches
.yarn/
.cache/
.rpt2_cache
# builds
dist/
dist_*/
# custom

View File

@ -1,142 +0,0 @@
# gitzone standard
image: hosttoday/ht-docker-node:npmci
cache:
paths:
- .npmci_cache/
key: "$CI_BUILD_STAGE"
stages:
- security
- test
- release
- metadata
# ====================
# security stage
# ====================
mirror:
stage: security
script:
- npmci git mirror
tags:
- docker
- notpriv
snyk:
stage: security
script:
- npmci command npm install -g snyk
- npmci command npm install --ignore-scripts
- npmci command snyk test
tags:
- docker
- notpriv
# ====================
# test stage
# ====================
testLEGACY:
stage: test
script:
- npmci node install legacy
- npmci npm install
- npmci npm test
coverage: /\d+.?\d+?\%\s*coverage/
tags:
- docker
- notpriv
allow_failure: true
testLTS:
stage: test
script:
- npmci node install lts
- npmci npm install
- npmci npm test
coverage: /\d+.?\d+?\%\s*coverage/
tags:
- docker
- notpriv
testSTABLE:
stage: test
script:
- npmci node install stable
- npmci npm install
- npmci npm test
coverage: /\d+.?\d+?\%\s*coverage/
tags:
- docker
- notpriv
release:
stage: release
script:
- npmci node install stable
- npmci npm publish
only:
- tags
tags:
- docker
- notpriv
# ====================
# metadata stage
# ====================
codequality:
stage: metadata
image: docker:stable
allow_failure: true
services:
- docker:stable-dind
script:
- export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
- docker run
--env SOURCE_CODE="$PWD"
--volume "$PWD":/code
--volume /var/run/docker.sock:/var/run/docker.sock
"registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code
artifacts:
paths: [codeclimate.json]
tags:
- docker
- priv
trigger:
stage: metadata
script:
- npmci trigger
only:
- tags
tags:
- docker
- notpriv
pages:
image: hosttoday/ht-docker-node:npmci
stage: metadata
script:
- npmci command npm install -g typedoc typescript
- npmci npm install
- npmci command typedoc --module "commonjs" --target "ES2016" --out public/ ts/
tags:
- docker
- notpriv
only:
- tags
artifacts:
expire_in: 1 week
paths:
- public
allow_failure: true
windowsCompatibility:
image: stefanscherer/node-windows:10-build-tools
stage: metadata
script:
- npm install & npm test
coverage: /\d+.?\d+?\%\s*coverage/
tags:
- windows
allow_failure: true

11
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"command": "npm test",
"name": "Run npm test",
"request": "launch",
"type": "node-terminal"
}
]
}

26
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,26 @@
{
"json.schemas": [
{
"fileMatch": ["/npmextra.json"],
"schema": {
"type": "object",
"properties": {
"npmci": {
"type": "object",
"description": "settings for npmci"
},
"gitzone": {
"type": "object",
"description": "settings for gitzone",
"properties": {
"projectType": {
"type": "string",
"enum": ["website", "element", "service", "npm", "wcc"]
}
}
}
}
}
}
]
}

181
changelog.md Normal file
View File

@ -0,0 +1,181 @@
# Changelog
## 2025-05-15 - 1.3.0 - feat(logger)
Improve logging output and add --logfile support for persistent logs
- Add new .claude/settings.local.json with logging permissions configuration
- Remove obsolete readme.plan.md
- Introduce test/test.console.ts to capture and display console outputs during tests
- Update CLI in ts/index.ts to replace '--log-file' with '--logfile' flag
- Enhance TsTestLogger to support file logging, clean ANSI sequences, and improved JSON output
- Forward TAP protocol logs to testConsoleOutput in TapParser for better console distinction
## 2025-05-15 - 1.2.0 - feat(logging)
Improve logging output, CLI option parsing, and test report formatting.
- Added a centralized TsTestLogger with support for multiple verbosity levels, JSON output, and file logging (TODO).
- Integrated new logger into CLI parsing, TapParser, TapCombinator, and TsTest classes to ensure consistent and structured output.
- Introduced new CLI options (--quiet, --verbose, --no-color, --json, --log-file) for enhanced user control.
- Enhanced visual design with progress indicators, detailed error aggregation, and performance summaries.
- Updated documentation and logging code to align with improved CI/CD behavior, including skipping non-CI tests.
## 2025-05-15 - 1.1.0 - feat(cli)
Enhance test discovery with support for single file and glob pattern execution using improved CLI argument detection
- Detect execution mode (file, glob, directory) based on CLI input in ts/index.ts
- Refactor TestDirectory to load test files using SmartFile for single file and glob patterns
- Update TsTest to pass execution mode and adjust test discovery accordingly
- Bump dependency versions for typedserver, tsbundle, tapbundle, and others
- Add .claude/settings.local.json for updated permissions configuration
## 2025-01-23 - 1.0.96 - fix(TsTest)
Fixed improper type-check for promise-like testModule defaults
- Corrected the type-check for promise-like default exports in test modules
- Removed unnecessary setTimeout used for async execution
## 2025-01-23 - 1.0.95 - fix(core)
Fix delay handling in Chrome test execution
- Replaced smartdelay.delayFor with native Promise-based delay mechanism in runInChrome method.
## 2025-01-23 - 1.0.94 - fix(TsTest)
Fix test module execution by ensuring promise resolution delay
- Added a delay to ensure promise resolution when dynamically importing test modules in the runInChrome method.
## 2025-01-23 - 1.0.93 - fix(tstest)
Handle globalThis.tapPromise in browser runtime evaluation
- Added support for using globalThis.tapPromise in the browser evaluation logic.
- Added log messages to indicate the usage of globalThis.tapPromise.
## 2025-01-23 - 1.0.92 - fix(core)
Improve error logging for test modules without default promise
- Added logging to display the exported test module content when it does not export a default promise.
## 2025-01-23 - 1.0.91 - fix(core)
Refactored tstest class to enhance promise handling for test modules.
- Removed .gitlab-ci.yml configuration file.
- Updated package.json dependency versions.
- Added a condition to handle promiselike objects in tests.
## 2024-04-18 - 1.0.89 to 1.0.90 - Enhancements and Bug Fixes
Multiple updates and fixes have been made.
- Updated core components to enhance stability and performance.
## 2024-03-07 - 1.0.86 to 1.0.88 - Core Updates
Continued improvements and updates in the core module.
- Applied critical fixes to enhance core stability.
## 2024-01-19 - 1.0.85 to 1.0.89 - Bug Fixes
Series of core updates have been implemented.
- Addressed known bugs and improved overall system functionality.
## 2023-11-09 - 1.0.81 to 1.0.84 - Maintenance Updates
Maintenance updates focusing on core reliability.
- Improved core module through systematic updates.
- Strengthened system robustness.
## 2023-08-26 - 1.0.77 to 1.0.80 - Critical Fixes
Critical fixes implemented in core functionality.
- Enhanced core processing to fix existing issues.
## 2023-07-13 - 1.0.75 to 1.0.76 - Stability Improvements
Stability enhancements and minor improvements.
- Focused on ensuring a stable operational core.
## 2022-11-08 - 1.0.73 to 1.0.74 - Routine Fixes
Routine core fixes to address reported issues.
- Addressed minor issues in the core module.
## 2022-08-03 - 1.0.71 to 1.0.72 - Core Enhancements
Enhancements applied to core systems.
- Tweaked core components for enhanced reliability.
## 2022-05-04 - 1.0.69 to 1.0.70 - System Reliability Fixes
Fixes targeting the reliability of the core systems.
- Improved system reliability through targeted core updates.
## 2022-03-17 - 1.0.65 to 1.0.68 - Major Core Updates
Major updates and bug fixes delivered for core components.
- Enhanced central operations through key updates.
## 2022-02-15 - 1.0.60 to 1.0.64 - Core Stability Improvements
Focused updates on core stability and performance.
- Reinforced stability through systematic core changes.
## 2021-11-07 - 1.0.54 to 1.0.59 - Core Fixes and Improvements
Multiple core updates aimed at fixing and improving the system.
- Addressed outstanding bugs and improved performance in the core.
## 2021-08-20 - 1.0.50 to 1.0.53 - Core Functionality Updates
Continued updates to improve core functionality and user experience.
- Implemented essential core fixes to enhance user experience.
## 2020-10-01 - 1.0.44 to 1.0.49 - Core System Enhancements
Critical enhancements to core systems.
- Improved core operations and tackled existing issues.
## 2020-09-29 - 1.0.40 to 1.0.43 - Essential Fixes
Series of essential fixes for the core system.
- Rectified known issues and bolstered core functionalities.
## 2020-07-10 - 1.0.35 to 1.0.39 - Core Function Fixes
Focused improvements and fixes for critical components.
- Addressed critical core functions to boost system performance.
## 2020-06-01 - 1.0.31 to 1.0.34 - Core Updates
Updates to maintain core functionality efficacy.
- Fixed inefficiencies and updated essential components.
## 2019-10-02 - 1.0.26 to 1.0.29 - Core Maintenance
Regular maintenance and updates for core reliability.
- Addressed multiple core issues and enhanced system stability.
## 2019-05-28 - 1.0.20 to 1.0.25 - Core Improvements
General improvements targeting core functionalities.
- Made systematic improvements to core processes.
## 2019-04-08 - 1.0.16 to 1.0.19 - Bug Squashing
Resolved numerous issues within core operations.
- Fixed and optimized core functionalities for better performance.
## 2018-12-06 - 1.0.15 - Dependency Updates
Updates aimed at improving dependency management.
- Ensured dependencies are up-to-date for optimal performance.
## 2018-08-14 - 1.0.14 - Test Improvement
Major improvements in testing mechanisms and logging.
- Improved test results handling for accuracy and reliability.
- Enhanced logging features for increased clarity.
## 2018-08-04 - 1.0.1 to 1.0.13 - Initial Implementation and Fixes
Initial release and critical updates focusing on core stability and functionality.
- Implemented core components and established initial system structure.
- Addressed key bugs and enhanced initial functionality.

4
cli.child.ts Normal file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env node
process.env.CLI_CALL = 'true';
import * as cliTool from './ts/index.js';
cliTool.runCli();

3
cli.js
View File

@ -1,3 +1,4 @@
#!/usr/bin/env node
process.env.CLI_CALL = 'true';
require('./dist/index');
const cliTool = await import('./dist_ts/index.js');
cliTool.runCli();

View File

@ -1,4 +1,5 @@
#!/usr/bin/env node
process.env.CLI_CALL = 'true';
require('@gitzone/tsrun');
require('./ts/index');
import * as tsrun from '@git.zone/tsrun';
tsrun.runPath('./cli.child.js', import.meta.url);

View File

@ -2,5 +2,16 @@
"npmci": {
"npmGlobalTools": [],
"npmAccessLevel": "public"
},
"gitzone": {
"projectType": "npm",
"module": {
"githost": "gitlab.com",
"gitscope": "gitzone",
"gitrepo": "tstest",
"description": "a test utility to run tests that match test/**/*.ts",
"npmPackagename": "@gitzone/tstest",
"license": "MIT"
}
}
}
}

917
package-lock.json generated
View File

@ -1,917 +0,0 @@
{
"name": "@gitzone/tstest",
"version": "1.0.11",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@airbnb/node-memwatch": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@airbnb/node-memwatch/-/node-memwatch-1.0.2.tgz",
"integrity": "sha512-2R+MEEMSTUdKwQ6NFWkyA/UNoSjL1tMldZqJbZpgXSwNMBzlNlkUWEXKu9RqTTMkDqJRfGJ2VDs8gPlPK2APDQ==",
"dev": true,
"requires": {
"bindings": "^1.3.0",
"nan": "^2.9.2"
}
},
"@gitzone/tsbuild": {
"version": "2.0.21",
"resolved": "https://registry.npmjs.org/@gitzone/tsbuild/-/tsbuild-2.0.21.tgz",
"integrity": "sha512-MAKfqnhf+42twSzXziRoBCu+sW61+2Rvc5qXxpEb594Fpnsj28cZ1VIEckSmiAkoBSiCnoU+2/qea2ycwWMBTg==",
"dev": true,
"requires": {
"@pushrocks/smartfile": "^6.0.3",
"@pushrocks/smartlog": "^2.0.1",
"@pushrocks/smartpath": "^4.0.1",
"@pushrocks/smartpromise": "^2.0.5",
"typescript": "^2.9.2"
}
},
"@gitzone/tsrun": {
"version": "1.1.9",
"resolved": "https://registry.npmjs.org/@gitzone/tsrun/-/tsrun-1.1.9.tgz",
"integrity": "sha512-MbCLj4hSK5nY6cMqT0OxY0BrXffmiC1Rjbzan8CmEpB8OttaAJT+zsJErJWhI+pk4s75Te73PyhHYaJAXUoJhw==",
"requires": {
"@pushrocks/smartfile": "^6.0.3",
"ts-node": "^7.0.0",
"typescript": "^2.9.1"
}
},
"@pushrocks/consolecolor": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@pushrocks/consolecolor/-/consolecolor-2.0.1.tgz",
"integrity": "sha512-iOFCHVeFZ2OywbdwSxVI4/wokkcLrXVdHLgvMmkNhJ220eeLgjNZWx3EJo3vNW3zq5ybCSCUIq0878djBxrWpw==",
"requires": {
"ansi-256-colors": "^1.1.0"
}
},
"@pushrocks/smartdelay": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@pushrocks/smartdelay/-/smartdelay-2.0.1.tgz",
"integrity": "sha512-olWwh2/JWfhmYdgqrR5RdSsgv1GlXBnbP+XKUrdKVk3dcCzkoqDx9lRE9NfpoCg1cUM2VMxbTVgTW9PWyexEuw==",
"dev": true,
"requires": {
"@pushrocks/smartpromise": "^2.0.5"
}
},
"@pushrocks/smartfile": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/@pushrocks/smartfile/-/smartfile-6.0.3.tgz",
"integrity": "sha512-oYnLQzY/R6kVNerbWY4WwnPvdxXldrzMPWcB9j0aAdSDSqGwBEO1/ZFTQuNzN5MmPopoYmJrc06ZmI6dm4OJmw==",
"requires": {
"@pushrocks/smartpromise": "^2.0.5",
"@pushrocks/smartrequest": "^1.0.15",
"@types/fs-extra": "^5.0.3",
"@types/vinyl": "^2.0.2",
"fs-extra": "^6.0.1",
"glob": "^7.1.2",
"js-yaml": "^3.10.0",
"smartpath": "^3.2.8",
"vinyl-file": "^3.0.0"
}
},
"@pushrocks/smartlog": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@pushrocks/smartlog/-/smartlog-2.0.1.tgz",
"integrity": "sha512-GtsDTGIUF3VuWPyF8FV5dF31ZCEIcaJ56ZlvJsWxjnyJq57X25mk5/K0QAaRE9IIeHg6fORcukFomb5C+AOQrg==",
"requires": {
"@pushrocks/smartlog-interfaces": "^1.0.9"
}
},
"@pushrocks/smartlog-interfaces": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@pushrocks/smartlog-interfaces/-/smartlog-interfaces-1.0.9.tgz",
"integrity": "sha512-0qwpomrRN0kFjmhR9m1iHYXoISoNuXtRP0Wr+JtkYyURLwKHMaW8Xoznf8MzXJptRfqufJi3Fxh5HodpPrIZUA=="
},
"@pushrocks/smartpath": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@pushrocks/smartpath/-/smartpath-4.0.1.tgz",
"integrity": "sha512-MaI0+uLQPCr2V3WGnbdgb0pWa9xkWyrP4qYcbsHIjeismGLbn9s3jmP/HIXU8LkgzRgaVb+BJxmZJHOwl32DyA==",
"dev": true
},
"@pushrocks/smartpromise": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@pushrocks/smartpromise/-/smartpromise-2.0.5.tgz",
"integrity": "sha512-9j/chLtIiNkR0MDw7Mpxg9slxAVvAQwUZuiaPYX5KpHdKxQaHLI1VZ8IN0vPhwlfgNO4i4vGXV0wB8BvSDj03g=="
},
"@pushrocks/smartrequest": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/@pushrocks/smartrequest/-/smartrequest-1.1.12.tgz",
"integrity": "sha512-8vDpYUADkbJFdxDcHQJyJBpc66+cvsRAJdQ6SwMirz5cIeWNlLSR/PVrdGQ94z5tSusf4mwnODk2Ai9smN6XSA==",
"requires": {
"@pushrocks/smartpromise": "^2.0.5",
"@types/form-data": "^2.2.1",
"form-data": "^2.3.2"
}
},
"@pushrocks/smartshell": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@pushrocks/smartshell/-/smartshell-2.0.5.tgz",
"integrity": "sha512-bMmh46jfJxQ7F46bdujmBR8BqPeEFxBqdXab7885v0kaXASIf9+1BMPKfXiPsDrrR8z/2j2cG/Wgh/0+DDD9hQ==",
"requires": {
"@pushrocks/smartpromise": "^2.0.5",
"@types/which": "^1.3.1",
"which": "^1.3.1"
}
},
"@pushrocks/tapbundle": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@pushrocks/tapbundle/-/tapbundle-3.0.1.tgz",
"integrity": "sha512-QWVz5EwB3sjjqHTMa22xuw78TBgVTyqKTF5H6HT9d/rvxL5Ag4ZrTuoadMPcU9hRBx9gtPsKbWq4lEwOHdCmLA==",
"dev": true,
"requires": {
"@pushrocks/smartdelay": "^2.0.1",
"@pushrocks/smartpromise": "^2.0.5",
"early": "^2.1.1",
"leakage": "^0.4.0",
"smartchai": "^2.0.1"
}
},
"@types/chai": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.4.tgz",
"integrity": "sha512-h6+VEw2Vr3ORiFCyyJmcho2zALnUq9cvdB/IO8Xs9itrJVCenC7o26A6+m7D0ihTTr65eS259H5/Ghl/VjYs6g==",
"dev": true
},
"@types/chai-as-promised": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.0.tgz",
"integrity": "sha512-MFiW54UOSt+f2bRw8J7LgQeIvE/9b4oGvwU7XW30S9QGAiHGnU/fmiOprsyMkdmH2rl8xSPc0/yrQw8juXU6bQ==",
"dev": true,
"requires": {
"@types/chai": "*"
}
},
"@types/chai-string": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/@types/chai-string/-/chai-string-1.4.1.tgz",
"integrity": "sha512-aRNMs6TKgjgPlCHwDfq/YNy5VtRR2hJ4AUWByddrT0TRVVD8eX4MiHW6/iHvmQHRlVuuPZcwnTUE7b4yFt7bEA==",
"dev": true,
"requires": {
"@types/chai": "*"
}
},
"@types/figures": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@types/figures/-/figures-2.0.0.tgz",
"integrity": "sha512-mcRgJ+ncKuNI+Dwac7omO18B8C8u+YBS+AU/oyLhEyjAnT3cUUThhHgZpbiIvu5ZqSvdD30BXtrqg9nxc3OKMg=="
},
"@types/form-data": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-2.2.1.tgz",
"integrity": "sha512-JAMFhOaHIciYVh8fb5/83nmuO/AHwmto+Hq7a9y8FzLDcC1KCU344XDOMEmahnrTFlHjgh4L0WJFczNIX2GxnQ==",
"requires": {
"@types/node": "*"
}
},
"@types/fs-extra": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-5.0.4.tgz",
"integrity": "sha512-DsknoBvD8s+RFfSGjmERJ7ZOP1HI0UZRA3FSI+Zakhrc/Gy26YQsLI+m5V5DHxroHRJqCDLKJp7Hixn8zyaF7g==",
"requires": {
"@types/node": "*"
}
},
"@types/node": {
"version": "10.5.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.5.5.tgz",
"integrity": "sha512-6Qnb1gXbp3g1JX9QVJj3A6ORzc9XCyhokxUKaoonHgNXcQhmk8adhotxfkeK8El9TnFeUuH72yI6jQ5nDJKS6w=="
},
"@types/vinyl": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@types/vinyl/-/vinyl-2.0.2.tgz",
"integrity": "sha512-2iYpNuOl98SrLPBZfEN9Mh2JCJ2EI9HU35SfgBEb51DcmaHkhp8cKMblYeBqMQiwXMgAD3W60DbQ4i/UdLiXhw==",
"requires": {
"@types/node": "*"
}
},
"@types/which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@types/which/-/which-1.3.1.tgz",
"integrity": "sha512-ZrJDWpvg75LTGX4XwuneY9s6bF3OeZcGTpoGh3zDV9ytzcHMFsRrMIaLBRJZQMBoGyKs6unBQfVdrLZiYfb1zQ=="
},
"ansi-256-colors": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/ansi-256-colors/-/ansi-256-colors-1.1.0.tgz",
"integrity": "sha1-kQ3lDvzHwJ49gvL4er1rcAwYgYo="
},
"argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"requires": {
"sprintf-js": "~1.0.2"
}
},
"arrify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
"integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0="
},
"assertion-error": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
"dev": true
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"beautycolor": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/beautycolor/-/beautycolor-1.0.11.tgz",
"integrity": "sha512-Uxl/39+2uqixPzsrV+0NOHf0sJlWmsKnRTV0oz8+bfwnHPA/E+SZuh3Upn3OXobv0W7LZg5BVoLj1nkMj7m5jA==",
"dev": true,
"requires": {
"ansi-256-colors": "^1.1.0",
"typings-global": "^1.0.14"
}
},
"bindings": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.0.tgz",
"integrity": "sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw==",
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
},
"chai": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz",
"integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=",
"dev": true,
"requires": {
"assertion-error": "^1.0.1",
"check-error": "^1.0.1",
"deep-eql": "^3.0.0",
"get-func-name": "^2.0.0",
"pathval": "^1.0.0",
"type-detect": "^4.0.0"
}
},
"chai-as-promised": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz",
"integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==",
"dev": true,
"requires": {
"check-error": "^1.0.2"
}
},
"chai-string": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/chai-string/-/chai-string-1.4.0.tgz",
"integrity": "sha1-NZFAwFHTak5LGl/GuRAVL0OKjUk=",
"dev": true
},
"check-error": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
"integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
"dev": true
},
"clone": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
"integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18="
},
"clone-buffer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz",
"integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg="
},
"clone-stats": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz",
"integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA="
},
"cloneable-readable": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.2.tgz",
"integrity": "sha512-Bq6+4t+lbM8vhTs/Bef5c5AdEMtapp/iFb6+s4/Hh9MVTt8OLKH7ZOOZSCT+Ys7hsHvqv0GuMPJ1lnQJVHvxpg==",
"requires": {
"inherits": "^2.0.1",
"process-nextick-args": "^2.0.0",
"readable-stream": "^2.3.5"
}
},
"combined-stream": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
"integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"deep-eql": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
"integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
"dev": true,
"requires": {
"type-detect": "^4.0.0"
}
},
"define-properties": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz",
"integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=",
"dev": true,
"requires": {
"foreach": "^2.0.5",
"object-keys": "^1.0.8"
}
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"diff": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA=="
},
"early": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/early/-/early-2.1.1.tgz",
"integrity": "sha1-hB4jJU6l3FTYr67ugvWrZcAO4jw=",
"dev": true,
"requires": {
"beautycolor": "^1.0.7",
"smartq": "^1.1.1",
"typings-global": "^1.0.16"
}
},
"es-abstract": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz",
"integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==",
"dev": true,
"requires": {
"es-to-primitive": "^1.1.1",
"function-bind": "^1.1.1",
"has": "^1.0.1",
"is-callable": "^1.1.3",
"is-regex": "^1.0.4"
}
},
"es-to-primitive": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz",
"integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=",
"dev": true,
"requires": {
"is-callable": "^1.1.1",
"is-date-object": "^1.0.1",
"is-symbol": "^1.0.1"
}
},
"es6-error": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
"integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
"dev": true
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
},
"figures": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
"integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
"requires": {
"escape-string-regexp": "^1.0.5"
}
},
"first-chunk-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz",
"integrity": "sha1-G97NuOCDwGZLkZRVgVd6Q6nzHXA=",
"requires": {
"readable-stream": "^2.0.2"
}
},
"foreach": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
"integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=",
"dev": true
},
"form-data": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
"integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "1.0.6",
"mime-types": "^2.1.12"
}
},
"fs-extra": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz",
"integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==",
"requires": {
"graceful-fs": "^4.1.2",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
"get-func-name": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
"integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
"dev": true
},
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
},
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dev": true,
"requires": {
"function-bind": "^1.1.1"
}
},
"home": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/home/-/home-1.0.1.tgz",
"integrity": "sha1-lqQjzrSbmDeP9e886uBZpVf53TU=",
"requires": {
"os-homedir": "^1.0.1"
}
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"is-callable": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
"integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==",
"dev": true
},
"is-date-object": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
"integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
"dev": true
},
"is-regex": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
"integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
"dev": true,
"requires": {
"has": "^1.0.1"
}
},
"is-symbol": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz",
"integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=",
"dev": true
},
"is-utf8": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
"integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
},
"js-yaml": {
"version": "3.12.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
"integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==",
"requires": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
}
},
"jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
"requires": {
"graceful-fs": "^4.1.6"
}
},
"leakage": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/leakage/-/leakage-0.4.0.tgz",
"integrity": "sha512-x7gYK5n5dPkHDZWJ2Kh8Ag1hZNzUh+HtXn8Bv1aDdN6o6ONPCJ8sOfFq+kxcULJFp3lXaCjXb3iXOLmQRbBLwA==",
"dev": true,
"requires": {
"@airbnb/node-memwatch": "^1.0.2",
"es6-error": "^4.0.2",
"left-pad": "^1.1.3",
"minimist": "^1.2.0",
"pretty-bytes": "^4.0.2"
}
},
"left-pad": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz",
"integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==",
"dev": true
},
"make-error": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.4.tgz",
"integrity": "sha512-0Dab5btKVPhibSalc9QGXb559ED7G7iLjFXBaj9Wq8O3vorueR5K5jaE3hkG6ZQINyhA/JgG6Qk4qdFQjsYV6g=="
},
"mime-db": {
"version": "1.35.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz",
"integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg=="
},
"mime-types": {
"version": "2.1.19",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz",
"integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==",
"requires": {
"mime-db": "~1.35.0"
}
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"requires": {
"minimist": "0.0.8"
},
"dependencies": {
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
}
}
},
"nan": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz",
"integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==",
"dev": true
},
"object-keys": {
"version": "1.0.12",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz",
"integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==",
"dev": true
},
"object.getownpropertydescriptors": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz",
"integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=",
"dev": true,
"requires": {
"define-properties": "^1.1.2",
"es-abstract": "^1.5.1"
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1"
}
},
"os-homedir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"pathval": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
"integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=",
"dev": true
},
"pify": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
},
"pretty-bytes": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-4.0.2.tgz",
"integrity": "sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=",
"dev": true
},
"process-nextick-args": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"remove-trailing-separator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
"integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8="
},
"replace-ext": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz",
"integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs="
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"smartchai": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/smartchai/-/smartchai-2.0.1.tgz",
"integrity": "sha512-9M+R56OhAHXScxgr2vzQqxGx0XMS0QXriNZuP7hjlbVbo2FUT+l60iEzbwPt9Ga+5u2cEEjSSoZEQVqlROaddA==",
"dev": true,
"requires": {
"@types/chai": "^4.1.2",
"@types/chai-as-promised": "^7.1.0",
"@types/chai-string": "^1.4.0",
"chai": "^4.1.2",
"chai-as-promised": "^7.1.1",
"chai-string": "^1.4.0"
}
},
"smartpath": {
"version": "3.2.8",
"resolved": "https://registry.npmjs.org/smartpath/-/smartpath-3.2.8.tgz",
"integrity": "sha1-SDS9OouuIpW6rK26I8h6UBlS+UA=",
"requires": {
"home": "^1.0.1",
"typings-global": "^1.0.14"
}
},
"smartq": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/smartq/-/smartq-1.1.8.tgz",
"integrity": "sha512-FURlYW/C3bLeZjJcBVyw7bxCyQoCXiXbLCZcDUKznhXHaLu35c8m33/a2H8CA0rtb82lvzN8dRLnBZAcNMzNHQ==",
"dev": true,
"requires": {
"util.promisify": "^1.0.0"
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
},
"source-map-support": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.6.tgz",
"integrity": "sha512-N4KXEz7jcKqPf2b2vZF11lQIz9W5ZMuUcIOGj243lduidkf2fjkVKJS9vNxVWn3u/uxX38AcE8U9nnH9FPcq+g==",
"requires": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
},
"strip-bom": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
"integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
"requires": {
"is-utf8": "^0.2.0"
}
},
"strip-bom-buf": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-bom-buf/-/strip-bom-buf-1.0.0.tgz",
"integrity": "sha1-HLRar1dTD0yvhsf3UXnSyaUd1XI=",
"requires": {
"is-utf8": "^0.2.1"
}
},
"strip-bom-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz",
"integrity": "sha1-+H217yYT9paKpUWr/h7HKLaoKco=",
"requires": {
"first-chunk-stream": "^2.0.0",
"strip-bom": "^2.0.0"
}
},
"ts-node": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.0.tgz",
"integrity": "sha512-klJsfswHP0FuOLsvBZ/zzCfUvakOSSxds78mVeK7I+qP76YWtxf16hEZsp3U+b0kIo82R5UatGFeblYMqabb2Q==",
"requires": {
"arrify": "^1.0.0",
"buffer-from": "^1.1.0",
"diff": "^3.1.0",
"make-error": "^1.1.1",
"minimist": "^1.2.0",
"mkdirp": "^0.5.1",
"source-map-support": "^0.5.6",
"yn": "^2.0.0"
}
},
"type-detect": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
"integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
"dev": true
},
"typescript": {
"version": "2.9.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz",
"integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w=="
},
"typings-global": {
"version": "1.0.28",
"resolved": "https://registry.npmjs.org/typings-global/-/typings-global-1.0.28.tgz",
"integrity": "sha512-6VOwJWEY2971HOMHu/7sURzUXiD4/LiMJPsMAOqkHHAtS3MVpLFE5gzTiHilsH9KY5VE1mBQirWIgWFsDuo90A=="
},
"universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"util.promisify": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz",
"integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==",
"dev": true,
"requires": {
"define-properties": "^1.1.2",
"object.getownpropertydescriptors": "^2.0.3"
}
},
"vinyl": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz",
"integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==",
"requires": {
"clone": "^2.1.1",
"clone-buffer": "^1.0.0",
"clone-stats": "^1.0.0",
"cloneable-readable": "^1.0.0",
"remove-trailing-separator": "^1.0.1",
"replace-ext": "^1.0.0"
}
},
"vinyl-file": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/vinyl-file/-/vinyl-file-3.0.0.tgz",
"integrity": "sha1-sQTZ5ECf+jJfqt1SBkLQo7SIs2U=",
"requires": {
"graceful-fs": "^4.1.2",
"pify": "^2.3.0",
"strip-bom-buf": "^1.0.0",
"strip-bom-stream": "^2.0.0",
"vinyl": "^2.0.1"
}
},
"which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"requires": {
"isexe": "^2.0.0"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"yn": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz",
"integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo="
}
}
}

View File

@ -1,35 +1,58 @@
{
"name": "@gitzone/tstest",
"version": "1.0.11",
"name": "@git.zone/tstest",
"version": "1.3.0",
"private": false,
"description": "a test utility to run tests that match test/**/*.ts",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts",
"type": "module",
"author": "Lossless GmbH",
"license": "MIT",
"bin": {
"tstest": "./cli.js"
},
"scripts": {
"test": "(npm run prepareTest && npm run tstest && npm run cleanUp)",
"test": "(npm run cleanUp && npm run prepareTest && npm run tstest)",
"prepareTest": "git clone https://gitlab.com/sandboxzone/sandbox-npmts.git .nogit/sandbox-npmts && cd .nogit/sandbox-npmts && npm install",
"tstest": "cd .nogit/sandbox-npmts && node ../../cli.ts.js test/",
"tstest": "cd .nogit/sandbox-npmts && node ../../cli.ts.js test/ --web",
"cleanUp": "rm -rf .nogit/sandbox-npmts",
"format": "(gitzone format)",
"build": "(tsbuild)"
"build": "(tsbuild --web --allowimplicitany --skiplibcheck)",
"buildDocs": "tsdoc"
},
"devDependencies": {
"@gitzone/tsbuild": "^2.0.21",
"@pushrocks/tapbundle": "^3.0.1"
"@git.zone/tsbuild": "^2.5.1",
"@types/node": "^22.15.18"
},
"dependencies": {
"@gitzone/tsrun": "^1.1.9",
"@pushrocks/consolecolor": "^2.0.1",
"@pushrocks/smartfile": "^6.0.3",
"@pushrocks/smartlog": "^2.0.1",
"@pushrocks/smartpromise": "^2.0.5",
"@pushrocks/smartshell": "^2.0.5",
"@types/figures": "^2.0.0",
"figures": "^2.0.0"
}
"@api.global/typedserver": "^3.0.74",
"@git.zone/tsbundle": "^2.2.5",
"@git.zone/tsrun": "^1.3.3",
"@push.rocks/consolecolor": "^2.0.2",
"@push.rocks/smartbrowser": "^2.0.8",
"@push.rocks/smartdelay": "^3.0.5",
"@push.rocks/smartfile": "^11.2.0",
"@push.rocks/smartlog": "^3.0.9",
"@push.rocks/smartpromise": "^4.2.3",
"@push.rocks/smartshell": "^3.2.3",
"@push.rocks/tapbundle": "^6.0.3",
"@types/ws": "^8.18.1",
"figures": "^6.1.0",
"ws": "^8.18.2"
},
"files": [
"ts/**/*",
"ts_web/**/*",
"dist/**/*",
"dist_*/**/*",
"dist_ts/**/*",
"dist_ts_web/**/*",
"assets/**/*",
"cli.js",
"npmextra.json",
"readme.md"
],
"browserslist": [
"last 1 chrome versions"
],
"packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39"
}

9901
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

0
readme.hints.md Normal file
View File

61
readme.md Normal file
View File

@ -0,0 +1,61 @@
# @gitzone/tstest
a test utility to run tests that match test/**/*.ts
## Availabililty and Links
* [npmjs.org (npm package)](https://www.npmjs.com/package/@gitzone/tstest)
* [gitlab.com (source)](https://gitlab.com/gitzone/tstest)
* [github.com (source mirror)](https://github.com/gitzone/tstest)
* [docs (typedoc)](https://gitzone.gitlab.io/tstest/)
## Status for master
Status Category | Status Badge
-- | --
GitLab Pipelines | [![pipeline status](https://gitlab.com/gitzone/tstest/badges/master/pipeline.svg)](https://lossless.cloud)
GitLab Pipline Test Coverage | [![coverage report](https://gitlab.com/gitzone/tstest/badges/master/coverage.svg)](https://lossless.cloud)
npm | [![npm downloads per month](https://badgen.net/npm/dy/@gitzone/tstest)](https://lossless.cloud)
Snyk | [![Known Vulnerabilities](https://badgen.net/snyk/gitzone/tstest)](https://lossless.cloud)
TypeScript Support | [![TypeScript](https://badgen.net/badge/TypeScript/>=%203.x/blue?icon=typescript)](https://lossless.cloud)
node Support | [![node](https://img.shields.io/badge/node->=%2010.x.x-blue.svg)](https://nodejs.org/dist/latest-v10.x/docs/api/)
Code Style | [![Code Style](https://badgen.net/badge/style/prettier/purple)](https://lossless.cloud)
PackagePhobia (total standalone install weight) | [![PackagePhobia](https://badgen.net/packagephobia/install/@gitzone/tstest)](https://lossless.cloud)
PackagePhobia (package size on registry) | [![PackagePhobia](https://badgen.net/packagephobia/publish/@gitzone/tstest)](https://lossless.cloud)
BundlePhobia (total size when bundled) | [![BundlePhobia](https://badgen.net/bundlephobia/minzip/@gitzone/tstest)](https://lossless.cloud)
Platform support | [![Supports Windows 10](https://badgen.net/badge/supports%20Windows%2010/yes/green?icon=windows)](https://lossless.cloud) [![Supports Mac OS X](https://badgen.net/badge/supports%20Mac%20OS%20X/yes/green?icon=apple)](https://lossless.cloud)
## Usage
## cli usage
lets assume we have a directory called test/ where all our tests arae defined. Simply type
```
tstest test/
```
to run all tests.
## Syntax
tstest supports tap syntax. In other words your testfiles are run in a subprocess, and the console output contains trigger messages for tstest to determine test status. Inside your testfile you should use `@pushrocks/tapbundle` for the best results.
## Environments
tstest supports different environments:
- a testfile called `test-something.node.ts` will be run in node
- a testfile called `test-something.chrome.ts` will be run in chrome environment (bundled through parcel and run through puppeteer)
- a testfile called `test-something.both.ts` will be run in node an chrome, which is good for isomorphic packages.
> note: there is alpha support for the deno environment by naming a file test-something.deno.ts
## Contribution
We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :)
For further information read the linked docs at the top of this readme.
> MIT licensed | **©** [Lossless GmbH](https://lossless.gmbh)
| By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy)
[![repo-footer](https://lossless.gitlab.io/publicrelations/repofooter.svg)](https://maintainedby.lossless.com)

21
test-output.log Normal file
View File

@ -0,0 +1,21 @@
🔍 Test Discovery
Mode: file
Pattern: test/test.single.ts
Found: 1 test file(s)
▶️ test/test.single.ts (1/1)
Runtime: node.js
✅ single file test execution (1ms)
Summary: 1/1 PASSED
📊 Test Summary
┌────────────────────────────────┐
│ Total Files: 1 │
│ Total Tests: 1 │
│ Passed: 1 │
│ Failed: 0 │
│ Duration: 1230ms │
└────────────────────────────────┘
ALL TESTS PASSED! 🎉

8
test/subdir/test.sub.ts Normal file
View File

@ -0,0 +1,8 @@
import { expect, tap } from '@push.rocks/tapbundle';
tap.test('subdirectory test execution', async () => {
console.log('This test verifies subdirectory test discovery works');
expect(true).toBeTrue();
});
tap.start();

11
test/test.console.ts Normal file
View File

@ -0,0 +1,11 @@
import { expect, tap } from '@push.rocks/tapbundle';
tap.test('Test with console output', async () => {
console.log('Log message 1 from test');
console.log('Log message 2 from test');
console.error('Error message from test');
console.warn('Warning message from test');
expect(true).toBeTrue();
});
tap.start();

13
test/test.fail.ts Normal file
View File

@ -0,0 +1,13 @@
import { expect, tap } from '@push.rocks/tapbundle';
tap.test('This test should fail', async () => {
console.log('This test will fail on purpose');
expect(true).toBeFalse();
});
tap.test('This test should pass', async () => {
console.log('This test will pass');
expect(true).toBeTrue();
});
tap.start();

8
test/test.glob.ts Normal file
View File

@ -0,0 +1,8 @@
import { expect, tap } from '@push.rocks/tapbundle';
tap.test('glob pattern test execution', async () => {
console.log('This test verifies glob pattern execution works');
expect(true).toBeTrue();
});
tap.start();

8
test/test.single.ts Normal file
View File

@ -0,0 +1,8 @@
import { expect, tap } from '@push.rocks/tapbundle';
tap.test('single file test execution', async () => {
console.log('This test verifies single file execution works');
expect(true).toBeTrue();
});
tap.start();

View File

@ -1,5 +1,5 @@
import { expect, tap } from '@pushrocks/tapbundle';
import * as tstest from '../ts/index';
import { expect, tap } from '@push.rocks/tapbundle';
import * as tstest from '../ts/index.js';
tap.test('prepare test', async () => {});

8
ts/00_commitinfo_data.ts Normal file
View File

@ -0,0 +1,8 @@
/**
* autocreated commitinfo by @push.rocks/commitinfo
*/
export const commitinfo = {
name: '@git.zone/tstest',
version: '1.3.0',
description: 'a test utility to run tests that match test/**/*.ts'
}

View File

@ -1,9 +1,71 @@
import { TsTest } from './tstest.classes.tstest';
import { TsTest } from './tstest.classes.tstest.js';
import type { LogOptions } from './tstest.logging.js';
const cliRun = async () => {
if (process.env.CLI_CALL) {
const tsTestInstance = new TsTest(process.cwd(), process.argv[2]);
await tsTestInstance.run();
export enum TestExecutionMode {
DIRECTORY = 'directory',
FILE = 'file',
GLOB = 'glob'
}
export const runCli = async () => {
// Parse command line arguments
const args = process.argv.slice(2);
const logOptions: LogOptions = {};
let testPath: string | null = null;
// Parse options
for (let i = 0; i < args.length; i++) {
const arg = args[i];
switch (arg) {
case '--quiet':
case '-q':
logOptions.quiet = true;
break;
case '--verbose':
case '-v':
logOptions.verbose = true;
break;
case '--no-color':
logOptions.noColor = true;
break;
case '--json':
logOptions.json = true;
break;
case '--log-file':
case '--logfile':
logOptions.logFile = true; // Set this as a flag, not a value
break;
default:
if (!arg.startsWith('-')) {
testPath = arg;
}
}
}
if (!testPath) {
console.error('You must specify a test directory/file/pattern as argument. Please try again.');
console.error('\nUsage: tstest <path> [options]');
console.error('\nOptions:');
console.error(' --quiet, -q Minimal output');
console.error(' --verbose, -v Verbose output');
console.error(' --no-color Disable colored output');
console.error(' --json Output results as JSON');
console.error(' --logfile Write logs to .nogit/testlogs/[testfile].log');
process.exit(1);
}
let executionMode: TestExecutionMode;
// Detect execution mode based on the argument
if (testPath.includes('*') || testPath.includes('?') || testPath.includes('[') || testPath.includes('{')) {
executionMode = TestExecutionMode.GLOB;
} else if (testPath.endsWith('.ts')) {
executionMode = TestExecutionMode.FILE;
} else {
executionMode = TestExecutionMode.DIRECTORY;
}
const tsTestInstance = new TsTest(process.cwd(), testPath, executionMode, logOptions);
await tsTestInstance.run();
};
cliRun();

View File

@ -0,0 +1,43 @@
// ============
// combines different tap test files to an overall result
// ============
import * as plugins from './tstest.plugins.js';
import { coloredString as cs } from '@push.rocks/consolecolor';
import { TapParser } from './tstest.classes.tap.parser.js';
import * as logPrefixes from './tstest.logprefixes.js';
import { TsTestLogger } from './tstest.logging.js';
export class TapCombinator {
tapParserStore: TapParser[] = [];
private logger: TsTestLogger;
constructor(logger: TsTestLogger) {
this.logger = logger;
}
addTapParser(tapParserArg: TapParser) {
this.tapParserStore.push(tapParserArg);
}
evaluate() {
// Call the logger's summary method
this.logger.summary();
// Check for failures
let failGlobal = false;
for (const tapParser of this.tapParserStore) {
if (!tapParser.expectedTests ||
tapParser.expectedTests !== tapParser.receivedTests ||
tapParser.getErrorTests().length > 0) {
failGlobal = true;
break;
}
}
// Exit with error code if tests failed
if (failGlobal) {
process.exit(1);
}
}
}

View File

@ -0,0 +1,207 @@
import { ChildProcess } from 'child_process';
import { coloredString as cs } from '@push.rocks/consolecolor';
// ============
// combines different tap test files to an overall result
// ============
import * as plugins from './tstest.plugins.js';
import { TapTestResult } from './tstest.classes.tap.testresult.js';
import * as logPrefixes from './tstest.logprefixes.js';
import { TsTestLogger } from './tstest.logging.js';
export class TapParser {
testStore: TapTestResult[] = [];
expectedTestsRegex = /([0-9]*)\.\.([0-9]*)$/;
expectedTests: number;
receivedTests: number;
testStatusRegex = /(ok|not\sok)\s([0-9]+)\s-\s(.*)\s#\stime=(.*)ms$/;
activeTapTestResult: TapTestResult;
pretaskRegex = /^::__PRETASK:(.*)$/;
private logger: TsTestLogger;
/**
* the constructor for TapParser
*/
constructor(public fileName: string, logger?: TsTestLogger) {
this.logger = logger;
}
private _getNewTapTestResult() {
this.activeTapTestResult = new TapTestResult(this.testStore.length + 1);
}
private _processLog(logChunk: Buffer | string) {
if (Buffer.isBuffer(logChunk)) {
logChunk = logChunk.toString();
}
const logLineArray = logChunk.split('\n');
if (logLineArray[logLineArray.length - 1] === '') {
logLineArray.pop();
}
// lets parse the log information
for (const logLine of logLineArray) {
let logLineIsTapProtocol = false;
if (!this.expectedTests && this.expectedTestsRegex.test(logLine)) {
logLineIsTapProtocol = true;
const regexResult = this.expectedTestsRegex.exec(logLine);
this.expectedTests = parseInt(regexResult[2]);
if (this.logger) {
this.logger.tapOutput(`Expecting ${this.expectedTests} tests!`);
}
// initiating first TapResult
this._getNewTapTestResult();
} else if (this.pretaskRegex.test(logLine)) {
logLineIsTapProtocol = true;
const pretaskContentMatch = this.pretaskRegex.exec(logLine);
if (pretaskContentMatch && pretaskContentMatch[1]) {
if (this.logger) {
this.logger.tapOutput(`Pretask -> ${pretaskContentMatch[1]}: Success.`);
}
}
} else if (this.testStatusRegex.test(logLine)) {
logLineIsTapProtocol = true;
const regexResult = this.testStatusRegex.exec(logLine);
const testId = parseInt(regexResult[2]);
const testOk = (() => {
if (regexResult[1] === 'ok') {
return true;
}
return false;
})();
const testSubject = regexResult[3];
const testDuration = parseInt(regexResult[4]);
// test for protocol error
if (testId !== this.activeTapTestResult.id) {
if (this.logger) {
this.logger.error('Something is strange! Test Ids are not equal!');
}
}
this.activeTapTestResult.setTestResult(testOk);
if (testOk) {
if (this.logger) {
this.logger.testResult(testSubject, true, testDuration);
}
} else {
if (this.logger) {
this.logger.testResult(testSubject, false, testDuration);
}
}
}
if (!logLineIsTapProtocol) {
if (this.activeTapTestResult) {
this.activeTapTestResult.addLogLine(logLine);
}
if (this.logger) {
// This is console output from the test file, not TAP protocol
this.logger.testConsoleOutput(logLine);
}
}
if (this.activeTapTestResult && this.activeTapTestResult.testSettled) {
this.testStore.push(this.activeTapTestResult);
this._getNewTapTestResult();
}
}
}
/**
* returns all tests that are not completed
*/
public getUncompletedTests() {
// TODO:
}
/**
* returns all tests that threw an error
*/
public getErrorTests() {
return this.testStore.filter((tapTestArg) => {
return !tapTestArg.testOk;
});
}
/**
* returns a test overview as string
*/
getTestOverviewAsString() {
let overviewString = '';
for (const test of this.testStore) {
if (overviewString !== '') {
overviewString += ' | ';
}
if (test.testOk) {
overviewString += cs(`T${test.id} ${plugins.figures.tick}`, 'green');
} else {
overviewString += cs(`T${test.id} ${plugins.figures.cross}`, 'red');
}
}
return overviewString;
}
/**
* handles a tap process
* @param childProcessArg
*/
public async handleTapProcess(childProcessArg: ChildProcess) {
const done = plugins.smartpromise.defer();
childProcessArg.stdout.on('data', (data) => {
this._processLog(data);
});
childProcessArg.stderr.on('data', (data) => {
this._processLog(data);
});
childProcessArg.on('exit', async () => {
await this.evaluateFinalResult();
done.resolve();
});
await done.promise;
}
public async handleTapLog(tapLog: string) {
this._processLog(tapLog);
}
public async evaluateFinalResult() {
this.receivedTests = this.testStore.length;
// check wether all tests ran
if (this.expectedTests === this.receivedTests) {
if (this.logger) {
this.logger.tapOutput(`${this.receivedTests} out of ${this.expectedTests} Tests completed!`);
}
} else {
if (this.logger) {
this.logger.error(`Only ${this.receivedTests} out of ${this.expectedTests} completed!`);
}
}
if (!this.expectedTests) {
if (this.logger) {
this.logger.error('No tests were defined. Therefore the testfile failed!');
}
} else if (this.expectedTests !== this.receivedTests) {
if (this.logger) {
this.logger.error('The amount of received tests and expectedTests is unequal! Therefore the testfile failed');
}
} else if (this.getErrorTests().length === 0) {
if (this.logger) {
this.logger.tapOutput('All tests are successfull!!!');
this.logger.testFileEnd(this.receivedTests, 0, 0);
}
} else {
if (this.logger) {
this.logger.tapOutput(`${this.getErrorTests().length} tests threw an error!!!`, true);
this.logger.testFileEnd(this.receivedTests - this.getErrorTests().length, this.getErrorTests().length, 0);
}
}
}
}

View File

@ -1,7 +1,7 @@
// ============
// combines different tap test files to an overall result
// ============
import * as plugins from './tstest.plugins';
import * as plugins from './tstest.plugins.js';
export class TapTestResult {
testLogBuffer = Buffer.from('');

View File

@ -1,11 +1,12 @@
import * as plugins from './tstest.plugins';
import * as paths from './tstest.paths';
import { Smartfile } from '@pushrocks/smartfile';
import * as plugins from './tstest.plugins.js';
import * as paths from './tstest.paths.js';
import { SmartFile } from '@push.rocks/smartfile';
import { TestExecutionMode } from './index.js';
// tap related stuff
import { TapCombinator } from './tstest.tap.combinator';
import { TapParser } from './tstest.tap.parser';
import { TapTestResult } from './tstest.tap.testresult';
import { TapCombinator } from './tstest.classes.tap.combinator.js';
import { TapParser } from './tstest.classes.tap.parser.js';
import { TapTestResult } from './tstest.classes.tap.testresult.js';
export class TestDirectory {
/**
@ -14,43 +15,87 @@ export class TestDirectory {
cwd: string;
/**
* the relative location of the test dir
* the test path or pattern
*/
relativePath: string;
testPath: string;
/**
* the absolute path of the test dir
* the execution mode
*/
absolutePath: string;
executionMode: TestExecutionMode;
/**
* an array of Smartfiles
*/
testfileArray: Smartfile[] = [];
testfileArray: SmartFile[] = [];
/**
* the constructor for TestDirectory
* tell it the path
* @param pathToTestDirectory
* @param cwdArg - the current working directory
* @param testPathArg - the test path/pattern
* @param executionModeArg - the execution mode
*/
constructor(cwdArg: string, relativePathToTestDirectory: string) {
constructor(cwdArg: string, testPathArg: string, executionModeArg: TestExecutionMode) {
this.cwd = cwdArg;
this.relativePath = relativePathToTestDirectory;
this.testPath = testPathArg;
this.executionMode = executionModeArg;
}
private async _init() {
this.testfileArray = await plugins.smartfile.fs.fileTreeToObject(
plugins.path.join(this.cwd, this.relativePath),
'**/*.ts'
);
switch (this.executionMode) {
case TestExecutionMode.FILE:
// Single file mode
const filePath = plugins.path.isAbsolute(this.testPath)
? this.testPath
: plugins.path.join(this.cwd, this.testPath);
if (await plugins.smartfile.fs.fileExists(filePath)) {
this.testfileArray = [await plugins.smartfile.SmartFile.fromFilePath(filePath)];
} else {
throw new Error(`Test file not found: ${filePath}`);
}
break;
case TestExecutionMode.GLOB:
// Glob pattern mode - use listFileTree which supports glob patterns
const globPattern = this.testPath;
const matchedFiles = await plugins.smartfile.fs.listFileTree(this.cwd, globPattern);
this.testfileArray = await Promise.all(
matchedFiles.map(async (filePath) => {
const absolutePath = plugins.path.isAbsolute(filePath)
? filePath
: plugins.path.join(this.cwd, filePath);
return await plugins.smartfile.SmartFile.fromFilePath(absolutePath);
})
);
break;
case TestExecutionMode.DIRECTORY:
// Directory mode - now recursive with ** pattern
const dirPath = plugins.path.join(this.cwd, this.testPath);
const testPattern = '**/test*.ts';
const testFiles = await plugins.smartfile.fs.listFileTree(dirPath, testPattern);
this.testfileArray = await Promise.all(
testFiles.map(async (filePath) => {
const absolutePath = plugins.path.isAbsolute(filePath)
? filePath
: plugins.path.join(dirPath, filePath);
return await plugins.smartfile.SmartFile.fromFilePath(absolutePath);
})
);
break;
}
}
async getTestFilePathArray() {
await this._init();
const testFilePaths: string[] = [];
for (const testFile of this.testfileArray) {
const filePath = plugins.path.join(this.relativePath, testFile.path);
testFilePaths.push(filePath);
// Use the path directly from the SmartFile
testFilePaths.push(testFile.path);
}
return testFilePaths;
}

View File

@ -1,42 +1,218 @@
import * as plugins from './tstest.plugins';
import * as paths from './tstest.paths';
import { coloredString as cs } from '@pushrocks/consolecolor';
import * as plugins from './tstest.plugins.js';
import * as paths from './tstest.paths.js';
import * as logPrefixes from './tstest.logprefixes.js';
import { TestDirectory } from './tstest.classes.testdirectory';
import { TapCombinator } from './tstest.tap.combinator';
import { TapParser } from './tstest.tap.parser';
import { coloredString as cs } from '@push.rocks/consolecolor';
import { TestDirectory } from './tstest.classes.testdirectory.js';
import { TapCombinator } from './tstest.classes.tap.combinator.js';
import { TapParser } from './tstest.classes.tap.parser.js';
import { TestExecutionMode } from './index.js';
import { TsTestLogger } from './tstest.logging.js';
import type { LogOptions } from './tstest.logging.js';
export class TsTest {
testDir: TestDirectory;
public testDir: TestDirectory;
public executionMode: TestExecutionMode;
public logger: TsTestLogger;
constructor(cwdArg: string, relativePathToTestDirectory: string) {
this.testDir = new TestDirectory(cwdArg, relativePathToTestDirectory);
public smartshellInstance = new plugins.smartshell.Smartshell({
executor: 'bash',
pathDirectories: [paths.binDirectory],
sourceFilePaths: [],
});
public smartbrowserInstance = new plugins.smartbrowser.SmartBrowser();
public tsbundleInstance = new plugins.tsbundle.TsBundle();
constructor(cwdArg: string, testPathArg: string, executionModeArg: TestExecutionMode, logOptions: LogOptions = {}) {
this.executionMode = executionModeArg;
this.testDir = new TestDirectory(cwdArg, testPathArg, executionModeArg);
this.logger = new TsTestLogger(logOptions);
}
async run() {
const fileNamesToRun: string[] = await this.testDir.getTestFilePathArray();
console.log(`Found ${fileNamesToRun.length} Testfile(s):`);
for (const fileName of fileNamesToRun) {
console.log(cs(fileName, 'orange'));
}
console.log('-'.repeat(16));
console.log(''); // force new line
const smartshellInstance = new plugins.smartshell.Smartshell({
executor: 'bash',
pathDirectories: [paths.binDirectory],
sourceFilePaths: []
});
const tapCombinator = new TapCombinator(); // lets create the TapCombinator
for (const fileName of fileNamesToRun) {
console.log(`${cs('=> ', 'blue')} Running ${cs(fileName, 'orange')}`);
console.log(cs(`=`.repeat(16), 'cyan'));
const tapParser = new TapParser(fileName);
const execResultStreaming = await smartshellInstance.execStreamingSilent(`tsrun ${fileName}`);
await tapParser.handleTapProcess(execResultStreaming.childProcess);
console.log(cs(`^`.repeat(16), 'cyan'));
console.log(''); // force new line
tapCombinator.addTapParser(tapParser);
// Log test discovery
this.logger.testDiscovery(
fileNamesToRun.length,
this.testDir.testPath,
this.executionMode
);
const tapCombinator = new TapCombinator(this.logger); // lets create the TapCombinator
let fileIndex = 0;
for (const fileNameArg of fileNamesToRun) {
fileIndex++;
switch (true) {
case process.env.CI && fileNameArg.includes('.nonci.'):
this.logger.tapOutput(`Skipping ${fileNameArg} - marked as non-CI`);
break;
case fileNameArg.endsWith('.browser.ts') || fileNameArg.endsWith('.browser.nonci.ts'):
const tapParserBrowser = await this.runInChrome(fileNameArg, fileIndex, fileNamesToRun.length);
tapCombinator.addTapParser(tapParserBrowser);
break;
case fileNameArg.endsWith('.both.ts') || fileNameArg.endsWith('.both.nonci.ts'):
this.logger.sectionStart('Part 1: Chrome');
const tapParserBothBrowser = await this.runInChrome(fileNameArg, fileIndex, fileNamesToRun.length);
tapCombinator.addTapParser(tapParserBothBrowser);
this.logger.sectionEnd();
this.logger.sectionStart('Part 2: Node');
const tapParserBothNode = await this.runInNode(fileNameArg, fileIndex, fileNamesToRun.length);
tapCombinator.addTapParser(tapParserBothNode);
this.logger.sectionEnd();
break;
default:
const tapParserNode = await this.runInNode(fileNameArg, fileIndex, fileNamesToRun.length);
tapCombinator.addTapParser(tapParserNode);
break;
}
}
tapCombinator.evaluate();
}
public async runInNode(fileNameArg: string, index: number, total: number): Promise<TapParser> {
this.logger.testFileStart(fileNameArg, 'node.js', index, total);
const tapParser = new TapParser(fileNameArg + ':node', this.logger);
// tsrun options
let tsrunOptions = '';
if (process.argv.includes('--web')) {
tsrunOptions += ' --web';
}
const execResultStreaming = await this.smartshellInstance.execStreamingSilent(
`tsrun ${fileNameArg}${tsrunOptions}`
);
await tapParser.handleTapProcess(execResultStreaming.childProcess);
return tapParser;
}
public async runInChrome(fileNameArg: string, index: number, total: number): Promise<TapParser> {
this.logger.testFileStart(fileNameArg, 'chromium', index, total);
// lets get all our paths sorted
const tsbundleCacheDirPath = plugins.path.join(paths.cwd, './.nogit/tstest_cache');
const bundleFileName = fileNameArg.replace('/', '__') + '.js';
const bundleFilePath = plugins.path.join(tsbundleCacheDirPath, bundleFileName);
// lets bundle the test
await plugins.smartfile.fs.ensureEmptyDir(tsbundleCacheDirPath);
await this.tsbundleInstance.build(process.cwd(), fileNameArg, bundleFilePath, {
bundler: 'esbuild',
});
// lets create a server
const server = new plugins.typedserver.servertools.Server({
cors: true,
port: 3007,
});
server.addRoute(
'/test',
new plugins.typedserver.servertools.Handler('GET', async (req, res) => {
res.type('.html');
res.write(`
<html>
<head>
<script>
globalThis.testdom = true;
</script>
</head>
<body></body>
</html>
`);
res.end();
})
);
server.addRoute('*', new plugins.typedserver.servertools.HandlerStatic(tsbundleCacheDirPath));
await server.start();
// lets handle realtime comms
const tapParser = new TapParser(fileNameArg + ':chrome', this.logger);
const wss = new plugins.ws.WebSocketServer({ port: 8080 });
wss.on('connection', (ws) => {
ws.on('message', (message) => {
const messageStr = message.toString();
if (messageStr.startsWith('console:')) {
const [, level, ...messageParts] = messageStr.split(':');
this.logger.browserConsole(messageParts.join(':'), level);
} else {
tapParser.handleTapLog(messageStr);
}
});
});
// lets do the browser bit
await this.smartbrowserInstance.start();
const evaluation = await this.smartbrowserInstance.evaluateOnPage(
`http://localhost:3007/test?bundleName=${bundleFileName}`,
async () => {
// lets enable real time comms
const ws = new WebSocket('ws://localhost:8080');
await new Promise((resolve) => (ws.onopen = resolve));
// Ensure this function is declared with 'async'
const logStore = [];
const originalLog = console.log;
const originalError = console.error;
// Override console methods to capture the logs
console.log = (...args) => {
logStore.push(args.join(' '));
ws.send(args.join(' '));
originalLog(...args);
};
console.error = (...args) => {
logStore.push(args.join(' '));
ws.send(args.join(' '));
originalError(...args);
};
const bundleName = new URLSearchParams(window.location.search).get('bundleName');
originalLog(`::TSTEST IN CHROMIUM:: Relevant Script name is: ${bundleName}`);
try {
// Dynamically import the test module
const testModule = await import(`/${bundleName}`);
if (testModule && testModule.default && testModule.default instanceof Promise) {
// Execute the exported test function
await testModule.default;
} else if (testModule && testModule.default && typeof testModule.default.then === 'function') {
console.log('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
console.log('Test module default export is just promiselike: Something might be messing with your Promise implementation.');
console.log('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
await testModule.default;
} else if (globalThis.tapPromise && typeof globalThis.tapPromise.then === 'function') {
console.log('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
console.log('Using globalThis.tapPromise');
console.log('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
await testModule.default;
} else {
console.error('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
console.error('Test module does not export a default promise.');
console.error('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
console.log(`We got: ${JSON.stringify(testModule)}`);
}
} catch (err) {
console.error(err);
}
return logStore.join('\n');
}
);
await this.smartbrowserInstance.stop();
await server.stop();
wss.close();
console.log(
`${cs('=> ', 'blue')} Stopped ${cs(fileNameArg, 'orange')} chromium instance and server.`
);
// lets create the tap parser
await tapParser.evaluateFinalResult();
return tapParser;
}
public async runInDeno() {}
}

358
ts/tstest.logging.ts Normal file
View File

@ -0,0 +1,358 @@
import { coloredString as cs } from '@push.rocks/consolecolor';
import * as plugins from './tstest.plugins.js';
import * as fs from 'fs';
import * as path from 'path';
export interface LogOptions {
quiet?: boolean;
verbose?: boolean;
noColor?: boolean;
json?: boolean;
logFile?: boolean;
}
export interface TestFileResult {
file: string;
passed: number;
failed: number;
total: number;
duration: number;
tests: Array<{
name: string;
passed: boolean;
duration: number;
error?: string;
}>;
}
export interface TestSummary {
totalFiles: number;
totalTests: number;
totalPassed: number;
totalFailed: number;
totalDuration: number;
fileResults: TestFileResult[];
}
export class TsTestLogger {
private options: LogOptions;
private startTime: number;
private fileResults: TestFileResult[] = [];
private currentFileResult: TestFileResult | null = null;
private currentTestLogFile: string | null = null;
constructor(options: LogOptions = {}) {
this.options = options;
this.startTime = Date.now();
}
private format(text: string, color?: string): string {
if (this.options.noColor || !color) {
return text;
}
return cs(text, color as any);
}
private log(message: string) {
if (this.options.json) {
// For JSON mode, skip console output
// JSON output is handled by logJson method
return;
}
console.log(message);
// Log to the current test file log if we're in a test and --logfile is specified
if (this.currentTestLogFile) {
this.logToTestFile(message);
}
}
private logToFile(message: string) {
// This method is no longer used since we use logToTestFile for individual test logs
// Keeping it for potential future use with a global log file
}
private logToTestFile(message: string) {
try {
// Remove ANSI color codes for file logging
const cleanMessage = message.replace(/\u001b\[[0-9;]*m/g, '');
// Append to test log file
fs.appendFileSync(this.currentTestLogFile, cleanMessage + '\n');
} catch (error) {
// Silently fail to avoid disrupting the test run
}
}
private logJson(data: any) {
const jsonString = JSON.stringify(data);
console.log(jsonString);
// Also log to test file if --logfile is specified
if (this.currentTestLogFile) {
this.logToTestFile(jsonString);
}
}
// Section separators
sectionStart(title: string) {
if (this.options.quiet || this.options.json) return;
this.log(this.format(`\n━━━ ${title} ━━━`, 'cyan'));
}
sectionEnd() {
if (this.options.quiet || this.options.json) return;
this.log(this.format('─'.repeat(50), 'dim'));
}
// Progress indication
progress(current: number, total: number, message: string) {
if (this.options.quiet || this.options.json) return;
const percentage = Math.round((current / total) * 100);
const filled = Math.round((current / total) * 20);
const empty = 20 - filled;
this.log(this.format(`\n📊 Progress: ${current}/${total} (${percentage}%)`, 'cyan'));
this.log(this.format(`[${'█'.repeat(filled)}${'░'.repeat(empty)}] ${message}`, 'dim'));
}
// Test discovery
testDiscovery(count: number, pattern: string, executionMode: string) {
if (this.options.json) {
this.logJson({ event: 'discovery', count, pattern, executionMode });
return;
}
if (this.options.quiet) {
this.log(`Found ${count} tests`);
} else {
this.log(this.format(`\n🔍 Test Discovery`, 'bold'));
this.log(this.format(` Mode: ${executionMode}`, 'dim'));
this.log(this.format(` Pattern: ${pattern}`, 'dim'));
this.log(this.format(` Found: ${count} test file(s)`, 'green'));
}
}
// Test execution
testFileStart(filename: string, runtime: string, index: number, total: number) {
this.currentFileResult = {
file: filename,
passed: 0,
failed: 0,
total: 0,
duration: 0,
tests: []
};
// Only set up test log file if --logfile option is specified
if (this.options.logFile) {
const baseFilename = path.basename(filename, '.ts');
this.currentTestLogFile = path.join('.nogit', 'testlogs', `${baseFilename}.log`);
// Ensure the directory exists
const logDir = path.dirname(this.currentTestLogFile);
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir, { recursive: true });
}
// Clear the log file for this test
fs.writeFileSync(this.currentTestLogFile, '');
}
if (this.options.json) {
this.logJson({ event: 'fileStart', filename, runtime, index, total });
return;
}
if (this.options.quiet) return;
this.log(this.format(`\n▶ ${filename} (${index}/${total})`, 'blue'));
this.log(this.format(` Runtime: ${runtime}`, 'dim'));
}
testResult(testName: string, passed: boolean, duration: number, error?: string) {
if (this.currentFileResult) {
this.currentFileResult.tests.push({ name: testName, passed, duration, error });
this.currentFileResult.total++;
if (passed) {
this.currentFileResult.passed++;
} else {
this.currentFileResult.failed++;
}
this.currentFileResult.duration += duration;
}
if (this.options.json) {
this.logJson({ event: 'testResult', testName, passed, duration, error });
return;
}
const icon = passed ? '✅' : '❌';
const color = passed ? 'green' : 'red';
if (this.options.quiet) {
this.log(`${icon} ${testName}`);
} else {
this.log(this.format(` ${icon} ${testName} (${duration}ms)`, color));
if (error && !passed) {
this.log(this.format(` ${error}`, 'red'));
}
}
}
testFileEnd(passed: number, failed: number, duration: number) {
if (this.currentFileResult) {
this.fileResults.push(this.currentFileResult);
this.currentFileResult = null;
}
if (this.options.json) {
this.logJson({ event: 'fileEnd', passed, failed, duration });
return;
}
if (!this.options.quiet) {
const total = passed + failed;
const status = failed === 0 ? 'PASSED' : 'FAILED';
const color = failed === 0 ? 'green' : 'red';
this.log(this.format(` Summary: ${passed}/${total} ${status}`, color));
}
// Clear the current test log file reference only if using --logfile
if (this.options.logFile) {
this.currentTestLogFile = null;
}
}
// TAP output forwarding (for TAP protocol messages)
tapOutput(message: string, isError: boolean = false) {
if (this.options.json) return;
// Never show raw TAP protocol messages in console
// They are already processed by TapParser and shown in our format
// Always log to test file if --logfile is specified
if (this.currentTestLogFile) {
this.logToTestFile(` ${message}`);
}
}
// Console output from test files (non-TAP output)
testConsoleOutput(message: string) {
if (this.options.json) return;
// Show console output from test files only in verbose mode
if (this.options.verbose) {
this.log(this.format(` ${message}`, 'dim'));
}
// Always log to test file if --logfile is specified
if (this.currentTestLogFile) {
this.logToTestFile(` ${message}`);
}
}
// Browser console
browserConsole(message: string, level: string = 'log') {
if (this.options.json) {
this.logJson({ event: 'browserConsole', message, level });
return;
}
if (!this.options.quiet) {
const prefix = level === 'error' ? '🌐❌' : '🌐';
const color = level === 'error' ? 'red' : 'magenta';
this.log(this.format(` ${prefix} ${message}`, color));
}
}
// Final summary
summary() {
const totalDuration = Date.now() - this.startTime;
const summary: TestSummary = {
totalFiles: this.fileResults.length,
totalTests: this.fileResults.reduce((sum, r) => sum + r.total, 0),
totalPassed: this.fileResults.reduce((sum, r) => sum + r.passed, 0),
totalFailed: this.fileResults.reduce((sum, r) => sum + r.failed, 0),
totalDuration,
fileResults: this.fileResults
};
if (this.options.json) {
this.logJson({ event: 'summary', summary });
return;
}
if (this.options.quiet) {
const status = summary.totalFailed === 0 ? 'PASSED' : 'FAILED';
this.log(`\nSummary: ${summary.totalPassed}/${summary.totalTests} | ${totalDuration}ms | ${status}`);
return;
}
// Detailed summary
this.log(this.format('\n📊 Test Summary', 'bold'));
this.log(this.format('┌────────────────────────────────┐', 'dim'));
this.log(this.format(`│ Total Files: ${summary.totalFiles.toString().padStart(14)}`, 'white'));
this.log(this.format(`│ Total Tests: ${summary.totalTests.toString().padStart(14)}`, 'white'));
this.log(this.format(`│ Passed: ${summary.totalPassed.toString().padStart(14)}`, 'green'));
this.log(this.format(`│ Failed: ${summary.totalFailed.toString().padStart(14)}`, summary.totalFailed > 0 ? 'red' : 'green'));
this.log(this.format(`│ Duration: ${totalDuration.toString().padStart(14)}ms │`, 'white'));
this.log(this.format('└────────────────────────────────┘', 'dim'));
// File results
if (summary.totalFailed > 0) {
this.log(this.format('\n❌ Failed Tests:', 'red'));
this.fileResults.forEach(fileResult => {
if (fileResult.failed > 0) {
this.log(this.format(`\n ${fileResult.file}`, 'yellow'));
fileResult.tests.filter(t => !t.passed).forEach(test => {
this.log(this.format(`${test.name}`, 'red'));
if (test.error) {
this.log(this.format(` ${test.error}`, 'dim'));
}
});
}
});
}
// Performance metrics
if (this.options.verbose) {
const avgDuration = Math.round(totalDuration / summary.totalTests);
const slowestTest = this.fileResults
.flatMap(r => r.tests)
.sort((a, b) => b.duration - a.duration)[0];
this.log(this.format('\n⏱ Performance Metrics:', 'cyan'));
this.log(this.format(` Average per test: ${avgDuration}ms`, 'white'));
if (slowestTest) {
this.log(this.format(` Slowest test: ${slowestTest.name} (${slowestTest.duration}ms)`, 'yellow'));
}
}
// Final status
const status = summary.totalFailed === 0 ? 'ALL TESTS PASSED! 🎉' : 'SOME TESTS FAILED! ❌';
const statusColor = summary.totalFailed === 0 ? 'green' : 'red';
this.log(this.format(`\n${status}`, statusColor));
}
// Error display
error(message: string, file?: string, stack?: string) {
if (this.options.json) {
this.logJson({ event: 'error', message, file, stack });
return;
}
if (this.options.quiet) {
console.error(`ERROR: ${message}`);
} else {
this.log(this.format('\n⚠ Error', 'red'));
if (file) this.log(this.format(` File: ${file}`, 'yellow'));
this.log(this.format(` ${message}`, 'red'));
if (stack && this.options.verbose) {
this.log(this.format(` Stack:`, 'dim'));
this.log(this.format(stack.split('\n').map(line => ` ${line}`).join('\n'), 'dim'));
}
}
}
}

View File

@ -1,7 +1,8 @@
import * as plugins from './tstest.plugins';
import { coloredString as cs } from '@pushrocks/consolecolor';
import * as plugins from './tstest.plugins.js';
import { coloredString as cs } from '@push.rocks/consolecolor';
export const TapPrefix = cs(`:::TAP:::`, 'pink', 'black');
export const TapErrorPrefix = cs(`!!!TAP PROTOCOL ERROR!!!`, 'red', 'black');
export const TapPrefix = cs(`::TAP::`, 'pink', 'black');
export const TapPretaskPrefix = cs(`::PRETASK::`, 'cyan', 'black');
export const TapErrorPrefix = cs(` !!!TAP PROTOCOL ERROR!!! `, 'red', 'black');
export const TsTestPrefix = cs(`>>>TSTEST<<<`, 'pink', 'black');
export const TsTestPrefix = cs(`**TSTEST**`, 'pink', 'black');

View File

@ -1,5 +1,5 @@
import * as plugins from './tstest.plugins';
import * as plugins from './tstest.plugins.js';
export const cwd = process.cwd();
export const testDir = plugins.path.join(cwd, './test/');
export const binDirectory = plugins.path.join(cwd, 'node_modules/.bin');
export const binDirectory = plugins.path.join(cwd, './node_modules/.bin');

View File

@ -1,14 +1,49 @@
// node native
import * as path from 'path';
// @pushrocks scope
import * as consolecolor from '@pushrocks/consolecolor';
import * as smartfile from '@pushrocks/smartfile';
import * as smartlog from '@pushrocks/smartlog';
import * as smartpromise from '@pushrocks/smartpromise';
import * as smartshell from '@pushrocks/smartshell';
export { path };
// @apiglobal scope
import * as typedserver from '@api.global/typedserver';
export {
typedserver
}
// @push.rocks scope
import * as consolecolor from '@push.rocks/consolecolor';
import * as smartbrowser from '@push.rocks/smartbrowser';
import * as smartdelay from '@push.rocks/smartdelay';
import * as smartfile from '@push.rocks/smartfile';
import * as smartlog from '@push.rocks/smartlog';
import * as smartpromise from '@push.rocks/smartpromise';
import * as smartshell from '@push.rocks/smartshell';
import * as tapbundle from '@push.rocks/tapbundle';
export {
consolecolor,
smartbrowser,
smartdelay,
smartfile,
smartlog,
smartpromise,
smartshell,
tapbundle,
};
// @gitzone scope
import * as tsbundle from '@git.zone/tsbundle';
export { tsbundle };
// sindresorhus
import * as figures from 'figures';
import figures from 'figures';
export { consolecolor, figures, path, smartfile, smartlog, smartpromise, smartshell };
export { figures };
// third party
import * as ws from 'ws';
export {
ws
}

View File

@ -1,48 +0,0 @@
// ============
// combines different tap test files to an overall result
// ============
import * as plugins from './tstest.plugins';
import { coloredString as cs } from '@pushrocks/consolecolor';
import { TapParser } from './tstest.tap.parser';
import * as logPrefixes from './tstest.logprefixes';
export class TapCombinator {
tapParserStore: TapParser[] = [];
addTapParser(tapParserArg: TapParser) {
this.tapParserStore.push(tapParserArg);
}
evaluate() {
console.log(`${logPrefixes.TsTestPrefix} Ran ${this.tapParserStore.length} Testfiles!`);
console.log(`${logPrefixes.TsTestPrefix} Here are the overall results:`);
let failGlobal = false; // determine wether tstest should fail
for (const tapParser of this.tapParserStore) {
if(tapParser.getErrorTests().length === 0) {
console.log(
logPrefixes.TsTestPrefix +
cs(` ${tapParser.fileName} ${plugins.figures.tick}`, 'green') +
' | ' +
cs(` all tests completed successfully!`, 'blue')
)
} else {
console.log(
logPrefixes.TsTestPrefix +
cs(` ${tapParser.fileName} ${plugins.figures.cross}`, 'red') +
' | ' +
cs(` Errors ocurred, please check for the logs!`, 'blue')
);
failGlobal = true;
}
}
console.log(cs('-'.repeat(16), 'cyan'));
console.log(cs('*'.repeat(16), 'cyan'));
console.log(cs('-'.repeat(16), 'cyan'));
if(!failGlobal) {
console.log(cs('Ending with code 0: TESTS ARE PASSING!', 'green'));
} else {
console.log(cs('Ending with code 1: TESTS ARE FAILING!', 'red'));
}
}
}

View File

@ -1,177 +0,0 @@
import { ChildProcess } from 'child_process';
import { coloredString as cs } from '@pushrocks/consolecolor';
// ============
// combines different tap test files to an overall result
// ============
import * as plugins from './tstest.plugins';
import { TapTestResult } from './tstest.tap.testresult';
import * as logPrefixes from './tstest.logprefixes';
export class TapParser {
testStore: TapTestResult[] = [];
expectedTestsRegex = /([0-9]*)\.\.([0-9]*)/;
expectedTests: number;
receivedTests: number;
testStatusRegex = /(ok|not\sok)\s([0-9]+)\s-\s(.*)\s#\stime=(.*)ms$/;
activeTapTestResult: TapTestResult;
/**
* the constructor for TapParser
*/
constructor(public fileName: string) {}
private _getNewTapTestResult() {
this.activeTapTestResult = new TapTestResult(this.testStore.length + 1);
}
private _processLog(logChunk: Buffer | string) {
if (Buffer.isBuffer(logChunk)) {
logChunk = logChunk.toString();
}
const logLineArray = logChunk.split('\n');
if (logLineArray[logLineArray.length - 1] === '') {
logLineArray.pop();
}
// lets parse the log information
for (const logLine of logLineArray) {
let logLineIsTapProtocol = false;
if (!this.expectedTests && this.expectedTestsRegex.test(logLine)) {
logLineIsTapProtocol = true;
const regexResult = this.expectedTestsRegex.exec(logLine);
this.expectedTests = parseInt(regexResult[2]);
console.log(
`${logPrefixes.TapPrefix} ${cs(
`Expecting ${this.expectedTests} tests!`,
'blue'
)}`
);
// initiating first TapResult
this._getNewTapTestResult();
} else if (this.testStatusRegex.test(logLine)) {
logLineIsTapProtocol = true;
const regexResult = this.testStatusRegex.exec(logLine);
const testId = parseInt(regexResult[2]);
const testOk = (() => {
if (regexResult[1] === 'ok') {
return true;
}
return false;
})();
const testSubject = regexResult[3];
const testDuration = parseInt(regexResult[4]);
// test for protocol error
if (testId !== this.activeTapTestResult.id) {
console.log(
`${
logPrefixes.TapErrorPrefix
} Something is strange! Test Ids are not equal!`
);
}
this.activeTapTestResult.setTestResult(testOk);
if (testOk) {
console.log(
logPrefixes.TapPrefix,
`${cs(`T${testId} ${plugins.figures.tick}`, 'green')} | ` +
cs(testSubject, 'blue') +
` | ${cs(`${testDuration} ms`, 'orange')}`
);
} else {
console.log(
logPrefixes.TapPrefix,
`${cs(`T${testId} ${plugins.figures.cross}`, 'red')} | ` +
cs(testSubject, 'blue') +
` | ${cs(`${testDuration} ms`, 'orange')}`
);
}
}
if (!logLineIsTapProtocol) {
if (this.activeTapTestResult) {
this.activeTapTestResult.addLogLine(logLine);
}
console.log(logLine);
}
if (this.activeTapTestResult && this.activeTapTestResult.testSettled) {
this.testStore.push(this.activeTapTestResult);
this._getNewTapTestResult();
}
}
}
/**
* returns all tests that are not completed
*/
getUncompletedTests() {
// TODO:
}
/**
* returns all tests that threw an error
*/
getErrorTests() {
return this.testStore.filter(tapTestArg => {
return !tapTestArg.testOk;
});
}
async handleTapProcess(childProcessArg: ChildProcess) {
const done = plugins.smartpromise.defer();
childProcessArg.stdout.on('data', data => {
this._processLog(data);
});
childProcessArg.stderr.on('data', data => {
this._processLog(data);
});
childProcessArg.on('exit', () => {
this.receivedTests = this.testStore.length;
// check wether all tests ran
if (this.expectedTests === this.receivedTests) {
console.log(
`${logPrefixes.TapPrefix} ${cs(
`${this.receivedTests} out of ${
this.expectedTests
} Tests completed!`,
'green'
)}`
);
} else {
console.log(
`${logPrefixes.TapErrorPrefix} ${cs(
`Only ${this.receivedTests} out of ${
this.expectedTests
} completed!`,
'red'
)}`
);
}
if (this.getErrorTests().length === 0) {
console.log(
`${logPrefixes.TapPrefix} ${cs(
`All tests are successfull!!!`,
'green'
)}`
);
} else {
console.log(
`${logPrefixes.TapPrefix} ${cs(
`${this.getErrorTests().length} tests threw an error!!!`,
'red'
)}`
);
}
done.resolve();
});
await done.promise;
}
}

14
tsconfig.json Normal file
View File

@ -0,0 +1,14 @@
{
"compilerOptions": {
"experimentalDecorators": true,
"useDefineForClassFields": false,
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"verbatimModuleSyntax": true
},
"exclude": [
"dist_*/**/*.d.ts"
]
}

View File

@ -1,3 +0,0 @@
{
"extends": "tslint-config-standard"
}